<!-- GAME CREATOR - S GIBBS -->
<!-- MCARS -  MAPPING CONTROL & AWARENESS RESPONSE-->
<!-- DELTA ATTACK GAME -->
<!-- 11/04/2026, STABLE VERSION V2 -->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Voyager Assault</title>

<style>
body {
    margin:0;
    background:black;
    font-family:Impact;
    overflow:hidden;
}

/* BACKGROUND */
#uiBG {
    position:absolute;
    width:100%;
    height:100%;
    z-index:1;
    background:url("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Voy Game Background.gif") no-repeat center/cover;
}

/* GAME AREA */
#gameArea {
    position:absolute;
    top:40px;
    left:5px;
    width:1035px;
    height:600px;
    z-index:2;
    overflow:hidden;
    background:url("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Stars Background.gif");
}

#player {
    position:absolute;
    width:90px;
    left:30px;
    top:300px;
}

.projectile {
    position:absolute;
    width:20px;
    height:20px;
    pointer-events:none;
}

.enemy {
    position:absolute;
    width:80px;
}

.ui {
    position:absolute;
    z-index:3;
    color:white;
    font-size:22px;
}

.button {
    padding:12px 40px;
    border-radius:40px;
    background:#9ea4ba;
    color:black;
    cursor:pointer;
}

.screen {
    position:absolute;
    width:100%;
    height:100%;
    display:flex;
    justify-content:center;
    align-items:center;
    z-index:10;
    background:black;
}

#titleScreen { display:none; }

#gameOver {
    display:none;
    color:red;
    font-size:80px;
    background:rgba(0,0,0,0.8);
}

/* LEVEL OVERLAY */
#levelScreen {
    display:none;
    color:white;
    font-size:60px;
    background:rgba(0,0,0,0.9);
}

#titleScreen img { width:1470px; }

.pulse {
    animation: pulseAnim 1s infinite;
}

@keyframes pulseAnim {
    0%   { background:#333; transform:scale(1); }
    50%  { background:#888; transform:scale(1.1); }
    100% { background:#333; transform:scale(1); }
}

#touchUI{
    position:absolute;
    width:100%;
    height:100%;
    z-index:50;
    pointer-events:none;
    display:none;
}

/* D-PAD container (bottom left) */
#dpad{
    position:absolute;
    bottom:10px;
    left:68px;
    display:flex;
    flex-direction:column;
    align-items:center;
    pointer-events:auto;
}

/* horizontal row for left/right */
.padRow{
    display:flex;
    gap:15px;
}

/* D-pad buttons */
.padBtn{
    width:100px;
    height:40px;
    background:#ffca18;
    color:black;
    display:flex;
    align-items:center;
    justify-content:center;
    font-family:Impact;
    border-radius:15px;
    user-select:none;
    touch-action:none;
}

/* FIRE button bottom right */
#fireBtn{
    position:absolute;
    bottom:30px;
    right:47px;
    width:120px;
    height:80px;
    background:#550000;
    color:white;
    display:flex;
    align-items:center;
    justify-content:center;
    font-family:Impact;
    border-radius:12px;
    pointer-events:auto;
    user-select:none;
    touch-action:none;
}
</style>
</head>

<body>

<div id="uiBG"></div>

<div id="gameArea">
    <img id="player" src="C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Voyager.png">
</div>

<!-- UI -->
<div class="ui" style="top:100px; left:1375px;">Score: <span id="score">0</span></div>
<div class="ui" style="top:140px; left:1375px;">Shields: <span id="shields">5</span></div>
<div class="ui" style="top:180px; left:1375px;">Time: <span id="time">60</span></div>
<div class="ui" style="top:220px; left:1375px;">Level: <span id="level">1</span></div>

<div class="ui button" style="top:300px; left:1372px;" onclick="pause()">Pause</div>
<div class="ui button" style="top:380px; left:1383px;" onclick="exitGame()">Exit</div>

<!-- START -->
<div id="startScreen" class="screen">
    <div class="button" onclick="startGame()">Click to Start</div>
</div>

<!-- TITLE -->
<div id="titleScreen" class="screen">
    <img src="C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Voyager Game Title.gif">
</div>

<!-- LEVEL -->
<div id="levelScreen" class="screen">
    <div id="levelText">LEVEL 1</div>
</div>

<!-- GAME OVER -->
<div id="gameOver" class="screen">
    <div style="text-align:center;">
        <div style="margin-bottom:30px;">GAME OVER</div>
        <div class="button pulse" onclick="newGame()">New Game</div>
    </div>
</div>

<!-- TOUCH CONTROLS -->
<div id="touchUI">
    <div id="dpad">
        <div class="padBtn" id="up">▲</div>
        <div class="padRow">
            <div class="padBtn" id="left">◀</div>
            <div class="padBtn" id="right">▶</div>
        </div>
        <div class="padBtn" id="down">▼</div>
    </div>

    <div id="fireBtn">FIRE</div>
</div>

<script>

/* STATE */
let timerStarted = false;
let playing = false;
let player = document.getElementById("player");
let gameArea = document.getElementById("gameArea");
let keys = {};

let boss = null;
let bossHP = 0;
let bossActive = false;
let bossMoveDir = 1;

let shields = 5;
let score = 0;
let time = 60;
let level = 1;
let canFire = true;

function getBounds(){
    return {
        w: gameArea.clientWidth,
        h: gameArea.clientHeight
    };
}

/* AUDIO */
let intro = new Audio("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Delta Intro.wav");
let fireSound = new Audio("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Voy Torpedo SFX.wav");
let explosionSound = new Audio("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Explosion.wav");
let gameOverSound = new Audio("C:/Users/steve/Pictures/LCARS Wall Display/My Maps Rescaled/K Game over tone.wav");
let enemyFireSound = new Audio("C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Enemy Fire.wav");

/* INPUT */
document.addEventListener("keydown", e=>keys[e.key]=true);
document.addEventListener("keyup", e=>keys[e.key]=false);

function bindHold(el, key){

    const down = (e)=>{
        e.preventDefault();
        keys[key] = true;
    };

    const up = (e)=>{
        e.preventDefault();
        keys[key] = false;
    };

    el.addEventListener("touchstart", down);
    el.addEventListener("touchend", up);
    el.addEventListener("touchcancel", up);

    el.addEventListener("mousedown", down);
    el.addEventListener("mouseup", up);
    el.addEventListener("mouseleave", up);
}

// D-PAD
bindHold(document.getElementById("up"), "ArrowUp");
bindHold(document.getElementById("down"), "ArrowDown");
bindHold(document.getElementById("left"), "ArrowLeft");
bindHold(document.getElementById("right"), "ArrowRight");

// FIRE BUTTON
bindHold(document.getElementById("fireBtn"), " ");

/* START GAME */
function startGame() {

    document.getElementById("startScreen").style.display="none";
    document.getElementById("titleScreen").style.display="flex";

    intro.play().catch(()=>{});

    setTimeout(()=>{
        document.getElementById("titleScreen").style.display="none";
        startLevel();
    },6000);
}

/* START LEVEL */
function startLevel(){

    playing = false;

    shields = 5;
    time = 60;

    document.getElementById("shields").innerText = shields;
    document.getElementById("time").innerText = time;
    document.getElementById("level").innerText = level;

    document.getElementById("levelText").innerText = "LEVEL " + level;
    document.getElementById("levelScreen").style.display = "flex";

   setTimeout(()=>{

    document.getElementById("levelScreen").style.display = "none";

    document.getElementById("touchUI").style.display = "block";

    playing = true;
    gameLoop();
    spawnEnemies();
    timerLoop();

},3000);
}

/* GAME LOOP */
function gameLoop(){
    if(!playing) return;

    movePlayer();
    requestAnimationFrame(gameLoop);
}

/* PLAYER MOVE */
function movePlayer(){

    let x = player.offsetLeft;
    let y = player.offsetTop;

    if(keys["ArrowUp"]) y-=2;
    if(keys["ArrowDown"]) y+=2;
    if(keys["ArrowLeft"]) x-=2;
    if(keys["ArrowRight"]) x+=2;

    let bounds = getBounds();

y = Math.max(0, Math.min(bounds.h - player.offsetHeight, y));
x = Math.max(0, Math.min(bounds.w - player.offsetWidth, x));

    player.style.top = y+"px";
    player.style.left = x+"px";

    if(keys[" "]) shoot();
}

/* SHOOT */
function shoot(){

    if(!playing || !canFire) return;
    canFire = false;

    fireSound.currentTime = 0;
    fireSound.play().catch(()=>{});

    let p = document.createElement("img");
    p.className = "projectile";
    p.src = "C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Voy Torpedo.png";

    p.style.left = (player.offsetLeft + 60) + "px";
    p.style.top  = (player.offsetTop + 10) + "px";

    gameArea.appendChild(p);

    let move = setInterval(()=>{

        if(!playing){
            clearInterval(move);
            p.remove();
            return;
        }

        p.style.left = (p.offsetLeft + (25 + level)) + "px";

        // collisions
        document.querySelectorAll(".enemy").forEach(e=>{

            if(!e || !e.isConnected) return;

            if(collide(p, e)){

                explode(e.offsetLeft, e.offsetTop);

                // BOSS HIT
                if(e === boss){
                    bossHP--;

                    if(bossHP <= 0){
                        boss.remove();
                        boss = null;
                        bossActive = false;

                        level++;
                        startLevel();
                    }

                } else {
                    e.remove();
                    score += 10;
                    document.getElementById("score").innerText = score;
                }

                p.remove();
                clearInterval(move);
            }
        });

        if(p.offsetLeft > gameArea.clientWidth){
            p.remove();
            clearInterval(move);
        }

    },30);

    setTimeout(()=>canFire = true, 450);
}

/* ENEMIES */
function spawnEnemies(){

    setInterval(()=>{

        if(!playing) return;

        let enemy = document.createElement("img");
        enemy.className="enemy";

        let ships=["8472 Ship.png","BOP.png","Kayzon Ship.png","War Bird.png"];
        enemy.src="C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/"+ships[Math.floor(Math.random()*ships.length)];

        let bounds = getBounds();

enemy.style.left = bounds.w + "px";
enemy.style.top = Math.random() * (bounds.h - 80) + "px";

        gameArea.appendChild(enemy);

        let speed = 3 + (level * 0.5);

        let move=setInterval(()=>{

            if(!playing){
                clearInterval(move);
                enemy.remove();
                return;
            }

            enemy.style.left=(enemy.offsetLeft - speed) + "px";

            if(Math.random() < Math.min(0.015, 0.004 + level*0.001)) enemyFire(enemy);

            if(collide(enemy,player)){
                explode(player.offsetLeft,player.offsetTop);
                enemy.remove();
                takeDamage();
                clearInterval(move);
            }

            if(enemy.offsetLeft < -enemy.offsetWidth){
                enemy.remove();
                clearInterval(move);
            }

        },30);

    }, Math.max(400, 1500 - (level * 100)));
}

/* ENEMY FIRE */
function enemyFire(enemy){

    if(!playing || !enemy || !enemy.isConnected) return;

    enemyFireSound.currentTime = 0;
    enemyFireSound.play().catch(()=>{});

    let s = document.createElement("img");
    s.className = "projectile";

    // FORCE DIMENSIONS VIA PROPERTIES (more reliable than CSS for collision)
    if(enemy === boss){
        s.src = "C:/Users/steve/Pictures/LCARS Wall Display/My Maps Rescaled/Borg Torpedo.png";
        s.width = 28;
        s.height = 28;
    } else {
        s.src = "C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Enemy Torpedo.png";
        s.width = 20;
        s.height = 20;
    }

    s.style.left = enemy.offsetLeft + "px";
    s.style.top  = enemy.offsetTop + "px";

    gameArea.appendChild(s);

    let move = setInterval(()=>{

        if(!playing){
            clearInterval(move);
            s.remove();
            return;
        }

        s.style.left = (s.offsetLeft - (12 + level)) + "px";

        // collision
        if(collide(s, player)){
            explode(player.offsetLeft, player.offsetTop);
            s.remove();
            takeDamage();
            clearInterval(move);
            return;
        }

        if(s.offsetLeft < -50){
            s.remove();
            clearInterval(move);
        }

    },30);
}
function explode(x,y){

    explosionSound.currentTime = 0;
    explosionSound.play().catch(()=>{});

    let boom = document.createElement("img");
    boom.src = "C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/K Explosion.gif";
    boom.className = "explosion";

boom.style.position = "absolute";
boom.style.width = "80px";

let size = 80;

boom.style.left = (x - size / 2) + "px";
boom.style.top  = (y - size / 2) + "px";

    gameArea.appendChild(boom);

    setTimeout(()=>boom.remove(),500);
}

function collide(a,b){
    return !(
        a.offsetLeft > b.offsetLeft + b.offsetWidth ||
        a.offsetLeft + a.offsetWidth < b.offsetLeft ||
        a.offsetTop > b.offsetTop + b.offsetHeight ||
        a.offsetTop + a.offsetHeight < b.offsetTop
    );
}

/* DAMAGE */
function takeDamage(){

    shields--;
    document.getElementById("shields").innerText = shields;

    if(shields <= 0){
    playing = false;
    document.getElementById("touchUI").style.display = "none";
    document.getElementById("gameOver").style.display="flex";
    gameOverSound.play();
}
}

/* TIMER */
function timerLoop(){

    if(timerStarted) return;
    timerStarted = true;

    setInterval(()=>{

        if(!playing) return;

        time--;
        document.getElementById("time").innerText = time;

if(time <= 0){

    if(!bossActive){
        spawnBoss();
    }

    return; // pause normal progression until boss is dead
}

    },1000);
}

function pause(){
    playing = !playing;
    if(playing) gameLoop();
}

/* EXIT */
function exitGame(){
    document.querySelectorAll(".enemy, .projectile, .explosion").forEach(e => e.remove());
    try { window.open('about:blank', '_self'); window.close(); } catch(e){}
    setTimeout(()=>{ window.location.replace("about:blank"); },200);
}

/* NEW GAME */
function newGame(){

    document.querySelectorAll(".enemy, .projectile, .explosion").forEach(e => e.remove());

    shields = 5;
    score = 0;
    time = 60;
    level = 1;

    document.getElementById("score").innerText = score;

    document.getElementById("gameOver").style.display = "none";

    document.getElementById("touchUI").style.display = "none";

    setTimeout(() => startGame(), 200);
}

function spawnBoss(){

    bossActive = true;
    bossHP = 10;

    boss = document.createElement("img");
    boss.className = "enemy";
    boss.src = "C:/Users/steve/Pictures/LCARS Wall Display/Voyager Game/Borg cube.png";

    let bounds = getBounds();

boss.style.left = (bounds.w - 150) + "px"; // stays inside view
boss.style.top = (bounds.h / 2) + "px";
    boss.style.width = "140px";

    gameArea.appendChild(boss);

    // movement + firing loop
    let move = setInterval(()=>{

        if(!playing || !boss || !boss.isConnected){
            clearInterval(move);
            return;
        }

        // vertical movement only
        let y = boss.offsetTop + (bossMoveDir * 2);

        let bounds = getBounds();

if(y < 0 || y > (bounds.h - boss.offsetHeight)){
    bossMoveDir *= -1;
}

        boss.style.top = y + "px";

        // random firing
        if(Math.random() < 0.08){
            enemyFire(boss);
        }

    },30);
}

function clearAllEnemies(){
    document.querySelectorAll(".enemy").forEach(e=>{
        if(e !== player) e.remove();
    });
}
</script>

</body>
</html>