← DOOM results

DOOM

ProCreations grug 27b GGUF IQ4 · typescript

Initial view of DOOM

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 30,354 bytes · SHA-256 b441e2754389
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Doom</title>
<style>
/* ── css: layout ── */
html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
}

#app {
  width: 100%;
  height: 100%;
}

#game-layout {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #000;
}

#game-canvas {
  width: 100%;
  height: 100%;
  display: block;
}

#hud {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  padding: 20px;
  font-family: monospace;
  font-size: 14px;
  color: #fff;
  text-shadow: 1px 1px 2px #000;
  pointer-events: none;
}

#overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  color: #fff;
  font-family: monospace;
  font-size: 48px;
  text-align: center;
  pointer-events: none;
}
</style>
</head>
<body>
<div id="app"><div id="game-layout" style="position:relative;width:100vw;height:100vh;overflow:hidden;background:#000">
  <canvas id="game-canvas"></canvas>
  <div id="hud"></div>
  <div id="overlay"></div>
</div></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./player":"src/player.ts","./world":"src/world.ts","./renderer":"src/renderer.ts"},"src/world.ts":{"./state":"src/state.ts"},"src/player.ts":{"./state":"src/state.ts"},"src/renderer.ts":{"./state":"src/state.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const player_1 = require("./player");
const world_1 = require("./world");
const renderer_1 = require("./renderer");
const canvas = document.getElementById('game-canvas');
const game = (0, player_1.createGame)();
game.world = (0, world_1.createWorld)();
game.totalEnemies = game.world.enemies.length;
function resizeCanvas() {
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
function requestPointerLock() {
    canvas.requestPointerLock();
}
function handleMouseMove(event) {
    if (document.pointerLockElement === canvas) {
        game.mouseDX += event.movementX;
        game.mouseDY += event.movementY;
    }
}
function handleClick(event) {
    if (!document.pointerLockElement) {
        requestPointerLock();
    }
    else {
        game.mouseDown = true;
    }
}
function handleMouseUp() {
    game.mouseDown = false;
}
function handleKeyDown(event) {
    if (event.key === 'ArrowLeft')
        game.keys.add('ArrowLeft');
    if (event.key === 'ArrowRight')
        game.keys.add('ArrowRight');
    if (event.key === 'ArrowUp')
        game.keys.add('ArrowUp');
    if (event.key === 'ArrowDown')
        game.keys.add('ArrowDown');
    if (event.key === '1')
        (0, player_1.switchWeapon)(game, 'pistol');
    if (event.key === '2')
        (0, player_1.switchWeapon)(game, 'shotgun');
    if (event.key === '3')
        (0, player_1.switchWeapon)(game, 'rifle');
    if (event.key === 'r')
        (0, player_1.reloadWeapon)(game);
    if (event.key === 'r' && game.gameOver) {
        game.gameOver = false;
        game.gameWin = false;
        game.player.health = game.player.maxHealth;
        game.player.x = 5;
        game.player.z = 5;
        game.player.angle = 0;
        game.world.enemies = game.world.enemies.concat((0, world_1.createWorld)().enemies);
        game.world.pickups = game.world.pickups.concat((0, world_1.createWorld)().pickups);
        game.enemiesKilled = 0;
        game.totalEnemies = game.world.enemies.length;
    }
}
function handleKeyUp(event) {
    if (event.key === 'ArrowLeft')
        game.keys.delete('ArrowLeft');
    if (event.key === 'ArrowRight')
        game.keys.delete('ArrowRight');
    if (event.key === 'ArrowUp')
        game.keys.delete('ArrowUp');
    if (event.key === 'ArrowDown')
        game.keys.delete('ArrowDown');
}
canvas.addEventListener('mousemove', handleMouseMove);
canvas.addEventListener('click', handleClick);
window.addEventListener('mouseup', handleMouseUp);
window.addEventListener('keydown', handleKeyDown);
window.addEventListener('keyup', handleKeyUp);
let lastTime = performance.now();
function gameLoop(currentTime) {
    const deltaTime = Math.min((currentTime - lastTime) / 1000, 1 / 30);
    lastTime = currentTime;
    game.time += deltaTime;
    game.damageFlash *= 0.9;
    game.shotFlash *= 0.8;
    (0, player_1.updatePlayer)(game, deltaTime);
    (0, player_1.updateEnemies)(game, deltaTime);
    (0, player_1.updatePickups)(game);
    (0, player_1.updateWeapons)(game);
    if (game.mouseDown) {
        (0, player_1.fireWeapon)(game);
    }
    game.mouseDX = 0;
    game.mouseDY = 0;
    game.mouseDown = false;
    (0, renderer_1.render)(game, canvas);
    if (game.gameOver) {
        setTimeout(() => {
            game.gameOver = false;
            game.player.health = game.player.maxHealth;
            game.player.x = 5;
            game.player.z = 5;
            game.player.angle = 0;
        }, 3000);
    }
    requestAnimationFrame(gameLoop);
}
requestAnimationFrame(gameLoop);
};

// ── module: src/state.ts ──
__mods["src/state.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WEAPONS = void 0;
exports.WEAPONS = {
    pistol: { name: 'Pistol', damage: 25, rate: 0.4, ammoCost: 1, magSize: 12, maxAmmo: 60, reloadTime: 1.5, spread: 0.02, pellets: 1, range: 2000 },
    shotgun: { name: 'Shotgun', damage: 15, rate: 0.8, ammoCost: 1, magSize: 6, maxAmmo: 30, reloadTime: 2.5, spread: 0.15, pellets: 5, range: 1200 },
    rifle: { name: 'Assault Rifle', damage: 18, rate: 0.12, ammoCost: 1, magSize: 30, maxAmmo: 120, reloadTime: 2.0, spread: 0.05, pellets: 1, range: 2500 }
};
};

// ── module: src/world.ts ──
__mods["src/world.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createWorld = createWorld;
function createMap() {
    const map = [];
    for (let y = 0; y < 40; y++) {
        let row = '';
        for (let x = 0; x < 40; x++) {
            if (x === 0 || y === 0 || x === 39 || y === 39) {
                row += '#';
            }
            else if (x === 20 && y >= 10 && y <= 30) {
                row += '#';
            }
            else if ((x === 10 || x === 30) && (y >= 5 || y <= 15)) {
                row += '#';
            }
            else if (x === 5 && y === 20) {
                row += '#';
            }
            else if (x === 35 && y === 20) {
                row += '#';
            }
            else {
                row += ' ';
            }
        }
        map.push(row);
    }
    return map;
}
function createEnemies() {
    const enemies = [];
    const positions = [
        { x: 15, z: 10 },
        { x: 25, z: 15 },
        { x: 35, z: 10 },
        { x: 5, z: 30 },
        { x: 15, z: 35 },
        { x: 25, z: 30 },
        { x: 35, z: 35 },
        { x: 10, z: 5 },
        { x: 30, z: 5 },
        { x: 20, z: 5 },
        { x: 8, z: 25 },
        { x: 32, z: 25 },
        { x: 12, z: 18 },
        { x: 28, z: 22 },
        { x: 22, z: 35 },
        { x: 18, z: 38 },
        { x: 12, z: 32 },
        { x: 28, z: 8 },
        { x: 36, z: 36 },
        { x: 4, z: 36 },
        { x: 20, z: 15 },
        { x: 30, z: 30 },
        { x: 15, z: 8 },
        { x: 25, z: 38 },
        { x: 18, z: 25 },
        { x: 22, z: 20 },
        { x: 8, z: 15 },
        { x: 32, z: 18 },
        { x: 35, z: 30 },
        { x: 5, z: 10 },
        { x: 10, z: 35 },
        { x: 30, z: 35 },
        { x: 15, z: 20 },
        { x: 25, z: 10 },
        { x: 35, z: 15 },
        { x: 5, z: 25 },
        { x: 10, z: 30 },
        { x: 30, z: 10 },
        { x: 20, z: 8 },
        { x: 25, z: 25 },
        { x: 35, z: 25 },
        { x: 10, z: 15 },
        { x: 20, z: 30 },
        { x: 30, z: 20 },
        { x: 8, z: 30 },
        { x: 32, z: 30 },
        { x: 12, z: 25 },
        { x: 28, z: 15 },
        { x: 18, z: 10 },
        { x: 22, z: 35 }
    ];
    for (const pos of positions) {
        const enemy = {
            x: pos.x,
            z: pos.z,
            health: 100,
            maxHealth: 100,
            speed: 0.02,
            state: 'walking',
            walkTimer: Math.random() * 100,
            attackTimer: 0
        };
        enemies.push(enemy);
    }
    return enemies;
}
function createPickups() {
    const pickups = [];
    const positions = [
        { x: 20, z: 5, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 15, z: 10, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 25, z: 15, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 35, z: 10, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 5, z: 30, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 15, z: 35, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 25, z: 30, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 35, z: 35, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 10, z: 5, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 30, z: 5, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 15, z: 20, type: 'ammo', ammoAmount: 25, healthAmount: 0 },
        { x: 25, z: 25, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 5, z: 15, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 35, z: 20, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 20, z: 15, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 20, z: 35, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 8, z: 25, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 32, z: 25, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 12, z: 18, type: 'ammo', ammoAmount: 25, healthAmount: 0 },
        { x: 28, z: 22, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 18, z: 25, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 22, z: 20, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 8, z: 15, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 32, z: 18, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 35, z: 30, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 5, z: 10, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 10, z: 35, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 30, z: 35, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 15, z: 20, type: 'ammo', ammoAmount: 25, healthAmount: 0 },
        { x: 25, z: 10, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 35, z: 15, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 5, z: 25, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 10, z: 30, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 30, z: 10, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 20, z: 8, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 25, z: 25, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 35, z: 25, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 10, z: 15, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 20, z: 30, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 30, z: 20, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 8, z: 30, type: 'ammo', ammoAmount: 15, healthAmount: 0 },
        { x: 32, z: 30, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 12, z: 25, type: 'ammo', ammoAmount: 25, healthAmount: 0 },
        { x: 28, z: 15, type: 'health', ammoAmount: 0, healthAmount: 25 },
        { x: 18, z: 10, type: 'ammo', ammoAmount: 20, healthAmount: 0 },
        { x: 22, z: 35, type: 'health', ammoAmount: 0, healthAmount: 25 }
    ];
    for (const pos of positions) {
        const pickup = {
            x: pos.x,
            z: pos.z,
            type: pos.type,
            ammoAmount: pos.ammoAmount,
            healthAmount: pos.healthAmount
        };
        pickups.push(pickup);
    }
    return pickups;
}
function createWorld() {
    return {
        width: 40,
        height: 40,
        map: createMap(),
        enemies: createEnemies(),
        pickups: createPickups()
    };
}
};

// ── module: src/player.ts ──
__mods["src/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlayer = createPlayer;
exports.createWeapons = createWeapons;
exports.createGame = createGame;
exports.updatePlayer = updatePlayer;
exports.switchWeapon = switchWeapon;
exports.reloadWeapon = reloadWeapon;
exports.fireWeapon = fireWeapon;
exports.updateWeapons = updateWeapons;
exports.updatePickups = updatePickups;
exports.updateEnemies = updateEnemies;
const state_1 = require("./state");
function createPlayer() {
    return {
        x: 5,
        z: 5,
        angle: 0,
        pitch: 0,
        health: 100,
        maxHealth: 100
    };
}
function createWeapons() {
    const weapons = {};
    for (const [type, weapon] of Object.entries(state_1.WEAPONS)) {
        weapons[type] = {
            type,
            ammo: weapon.maxAmmo,
            maxAmmo: weapon.maxAmmo,
            mag: weapon.magSize,
            maxMag: weapon.magSize,
            reloading: false,
            reloadStart: 0,
            lastShot: 0
        };
    }
    return weapons;
}
function createGame() {
    return {
        player: createPlayer(),
        weapons: createWeapons(),
        currentWeapon: 'pistol',
        world: null,
        cameraHeight: 0.5,
        moveSpeed: 0.05,
        rotSpeed: 0.005,
        keys: new Set(),
        mouseDown: false,
        mouseDX: 0,
        mouseDY: 0,
        time: 0,
        deltaTime: 0,
        enemiesKilled: 0,
        totalEnemies: 0,
        gameOver: false,
        gameWin: false,
        gameStarted: false,
        damageFlash: 0,
        shotFlash: 0
    };
}
function updatePlayer(game, deltaTime) {
    if (game.gameOver || game.gameWin)
        return;
    const moveX = Math.cos(game.player.angle);
    const moveZ = Math.sin(game.player.angle);
    const strafeX = Math.cos(game.player.angle + Math.PI / 2);
    const strafeZ = Math.sin(game.player.angle + Math.PI / 2);
    if (game.keys.has('ArrowLeft')) {
        game.player.angle -= game.rotSpeed * 360 * deltaTime;
    }
    if (game.keys.has('ArrowRight')) {
        game.player.angle += game.rotSpeed * 360 * deltaTime;
    }
    if (game.keys.has('ArrowUp')) {
        const newX = game.player.x + moveX * game.moveSpeed * deltaTime;
        const newZ = game.player.z + moveZ * game.moveSpeed * deltaTime;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    if (game.keys.has('ArrowDown')) {
        const newX = game.player.x - moveX * game.moveSpeed * deltaTime;
        const newZ = game.player.z - moveZ * game.moveSpeed * deltaTime;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    if (game.keys.has('ArrowLeft') && game.keys.has('ArrowUp')) {
        const newX = game.player.x + (moveX + strafeX) * game.moveSpeed * deltaTime * 0.7;
        const newZ = game.player.z + (moveZ + strafeZ) * game.moveSpeed * deltaTime * 0.7;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    if (game.keys.has('ArrowLeft') && game.keys.has('ArrowDown')) {
        const newX = game.player.x + (moveX - strafeX) * game.moveSpeed * deltaTime * 0.7;
        const newZ = game.player.z + (moveZ - strafeZ) * game.moveSpeed * deltaTime * 0.7;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    if (game.keys.has('ArrowRight') && game.keys.has('ArrowUp')) {
        const newX = game.player.x + (moveX - strafeX) * game.moveSpeed * deltaTime * 0.7;
        const newZ = game.player.z + (moveZ - strafeZ) * game.moveSpeed * deltaTime * 0.7;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    if (game.keys.has('ArrowRight') && game.keys.has('ArrowDown')) {
        const newX = game.player.x + (moveX + strafeX) * game.moveSpeed * deltaTime * 0.7;
        const newZ = game.player.z + (moveZ + strafeZ) * game.moveSpeed * deltaTime * 0.7;
        if (!isWall(game, newX, newZ)) {
            game.player.x = newX;
            game.player.z = newZ;
        }
    }
    game.player.pitch -= game.mouseDY * 0.01;
    game.player.pitch = Math.max(-1, Math.min(1, game.player.pitch));
}
function isWall(game, x, z) {
    const mapX = Math.floor(x);
    const mapZ = Math.floor(z);
    if (mapX < 0 || mapX >= game.world.width || mapZ < 0 || mapZ >= game.world.height) {
        return true;
    }
    return game.world.map[mapZ][mapX] === '#';
}
function switchWeapon(game, weaponType) {
    if (game.weapons[weaponType] && !game.gameOver && !game.gameWin) {
        game.currentWeapon = weaponType;
    }
}
function reloadWeapon(game) {
    const weapon = game.weapons[game.currentWeapon];
    if (!weapon || weapon.reloading || weapon.mag === weapon.maxMag || weapon.ammo === 0)
        return;
    weapon.reloading = true;
    weapon.reloadStart = game.time;
}
function fireWeapon(game) {
    const weapon = game.weapons[game.currentWeapon];
    const weaponDef = state_1.WEAPONS[game.currentWeapon];
    if (!weapon || weapon.reloading || weapon.mag === 0 || weapon.lastShot + weaponDef.rate > game.time)
        return;
    weapon.mag--;
    weapon.lastShot = game.time;
    game.shotFlash = 0.1;
    const pellets = weaponDef.pellets;
    for (let i = 0; i < pellets; i++) {
        const spread = (Math.random() - 0.5) * weaponDef.spread;
        const angle = game.player.angle + spread;
        const damage = weaponDef.damage * (0.8 + Math.random() * 0.4);
        const range = weaponDef.range;
        for (const enemy of game.world.enemies) {
            const dx = enemy.x - game.player.x;
            const dz = enemy.z - game.player.z;
            const distance = Math.sqrt(dx * dx + dz * dz);
            if (distance > range)
                continue;
            const enemyAngle = Math.atan2(dz, dx);
            const angleDiff = Math.abs(normalizeAngle(angle - enemyAngle));
            if (angleDiff < 0.15 / distance) {
                enemy.health -= damage;
                enemy.state = 'attacking';
                enemy.attackTimer = 0.5;
                break;
            }
        }
    }
}
function normalizeAngle(angle) {
    while (angle > Math.PI)
        angle -= 2 * Math.PI;
    while (angle < -Math.PI)
        angle += 2 * Math.PI;
    return angle;
}
function updateWeapons(game) {
    for (const [type, weapon] of Object.entries(game.weapons)) {
        if (weapon.reloading) {
            const weaponDef = state_1.WEAPONS[type];
            const reloadTime = weaponDef.reloadTime;
            const reloadProgress = (game.time - weapon.reloadStart) / reloadTime;
            if (reloadProgress >= 1) {
                const ammoNeeded = weapon.maxMag - weapon.mag;
                const ammoGiven = Math.min(ammoNeeded, weapon.ammo);
                weapon.mag += ammoGiven;
                weapon.ammo -= ammoGiven;
                weapon.reloading = false;
            }
        }
    }
}
function updatePickups(game) {
    for (let i = game.world.pickups.length - 1; i >= 0; i--) {
        const pickup = game.world.pickups[i];
        const dx = pickup.x - game.player.x;
        const dz = pickup.z - game.player.z;
        const distance = Math.sqrt(dx * dx + dz * dz);
        if (distance < 0.5) {
            if (pickup.type === 'health') {
                game.player.health = Math.min(game.player.maxHealth, game.player.health + pickup.healthAmount);
            }
            else if (pickup.type === 'ammo') {
                const weapon = game.weapons[game.currentWeapon];
                if (weapon) {
                    weapon.ammo = Math.min(weapon.maxAmmo, weapon.ammo + pickup.ammoAmount);
                }
            }
            game.world.pickups.splice(i, 1);
        }
    }
}
function updateEnemies(game, deltaTime) {
    for (const enemy of game.world.enemies) {
        if (enemy.health <= 0)
            continue;
        const dx = game.player.x - enemy.x;
        const dz = game.player.z - enemy.z;
        const distance = Math.sqrt(dx * dx + dz * dz);
        if (distance < 15) {
            enemy.state = 'attacking';
            enemy.attackTimer += deltaTime;
            if (enemy.attackTimer > 2) {
                game.player.health -= 5;
                enemy.attackTimer = 0;
            }
        }
        else if (distance < 30) {
            enemy.state = 'walking';
            const moveX = dx / distance;
            const moveZ = dz / distance;
            const newX = enemy.x + moveX * enemy.speed * deltaTime;
            const newZ = enemy.z + moveZ * enemy.speed * deltaTime;
            if (!isWall(game, newX, newZ)) {
                enemy.x = newX;
                enemy.z = newZ;
            }
        }
        else {
            enemy.state = 'idle';
        }
    }
    for (let i = game.world.enemies.length - 1; i >= 0; i--) {
        if (game.world.enemies[i].health <= 0) {
            game.world.enemies.splice(i, 1);
            game.enemiesKilled++;
        }
    }
    if (game.player.health <= 0) {
        game.gameOver = true;
        respawnPlayer(game);
    }
    if (game.world.enemies.length === 0 && game.enemiesKilled > 0) {
        game.gameWin = true;
    }
}
function respawnPlayer(game) {
    game.player.health = game.player.maxHealth;
    game.player.x = 5;
    game.player.z = 5;
    game.player.angle = 0;
    game.gameOver = false;
}
};

// ── module: src/renderer.ts ──
__mods["src/renderer.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.render = render;
const state_1 = require("./state");
function render(game, canvas) {
    const ctx = canvas.getContext('2d');
    const width = canvas.width;
    const height = canvas.height;
    // Clear screen
    ctx.fillStyle = '#000';
    ctx.fillRect(0, 0, width, height);
    // Render walls
    renderWalls(game, ctx, width, height);
    // Render enemies
    renderEnemies(game, ctx, width, height);
    // Render pickups
    renderPickups(game, ctx, width, height);
    // Render HUD
    renderHUD(game, ctx, width, height);
    // Render shot flash
    if (game.shotFlash > 0) {
        ctx.fillStyle = `rgba(255, 255, 0, ${game.shotFlash})`;
        ctx.fillRect(0, 0, width, height);
    }
    // Render damage flash
    if (game.damageFlash > 0) {
        ctx.fillStyle = `rgba(255, 0, 0, ${game.damageFlash})`;
        ctx.fillRect(0, 0, width, height);
    }
    // Render game over screen
    if (game.gameOver) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
        ctx.fillRect(0, 0, width, height);
        ctx.fillStyle = '#fff';
        ctx.font = '48px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('GAME OVER', width / 2, height / 2);
        ctx.font = '24px sans-serif';
        ctx.fillText('Respawning...', width / 2, height / 2 + 50);
    }
    // Render win screen
    if (game.gameWin) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
        ctx.fillRect(0, 0, width, height);
        ctx.fillStyle = '#0f0';
        ctx.font = '48px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('VICTORY!', width / 2, height / 2);
        ctx.font = '24px sans-serif';
        ctx.fillText(`Enemies killed: ${game.enemiesKilled}`, width / 2, height / 2 + 50);
        ctx.fillText('Press R to restart', width / 2, height / 2 + 80);
    }
}
function renderWalls(game, ctx, width, height) {
    const numRays = width / 4;
    const FOV = Math.PI / 3;
    const halfFOV = FOV / 2;
    const pitchOffset = game.player.pitch * height / 2;
    for (let i = 0; i < numRays; i++) {
        const rayAngle = game.player.angle - halfFOV + (FOV / numRays) * i;
        const rayX = Math.cos(rayAngle);
        const rayZ = Math.sin(rayAngle);
        let distance = 0;
        let hitWall = false;
        let wallX = 0;
        let wallZ = 0;
        while (!hitWall && distance < 50) {
            const testX = game.player.x + rayX * distance;
            const testZ = game.player.z + rayZ * distance;
            const mapX = Math.floor(testX);
            const mapZ = Math.floor(testZ);
            if (mapX < 0 || mapX >= game.world.width || mapZ < 0 || mapZ >= game.world.height) {
                hitWall = true;
                distance = 50;
            }
            else if (game.world.map[mapZ][mapX] === '#') {
                hitWall = true;
                wallX = mapX;
                wallZ = mapZ;
            }
            distance += 0.01;
        }
        if (hitWall) {
            const perpDistance = distance * Math.cos(rayAngle - game.player.angle);
            const lineHeight = height / perpDistance;
            const drawStart = (height - lineHeight) / 2 + pitchOffset;
            const shade = Math.max(0, 1 - perpDistance / 20);
            ctx.fillStyle = `rgb(${Math.floor(128 * shade)}, ${Math.floor(64 * shade)}, ${Math.floor(32 * shade)})`;
            ctx.fillRect(i * 4, drawStart, 4, lineHeight);
        }
    }
}
function renderEnemies(game, ctx, width, height) {
    const pitchOffset = game.player.pitch * height / 2;
    for (const enemy of game.world.enemies) {
        const dx = enemy.x - game.player.x;
        const dz = enemy.z - game.player.z;
        const distance = Math.sqrt(dx * dx + dz * dz);
        const enemyAngle = Math.atan2(dz, dx);
        const screenX = width / 2 + (enemyAngle - game.player.angle) * width / Math.PI;
        if (Math.abs(screenX - width / 2) < width / 2 && distance < 50) {
            const perpDistance = distance * Math.cos(enemyAngle - game.player.angle);
            const lineHeight = height / perpDistance;
            const spriteHeight = lineHeight * 0.8;
            const drawStart = (height - spriteHeight) / 2 + pitchOffset;
            const shade = Math.max(0, 1 - perpDistance / 20);
            const color = enemy.health > 0 ? `rgb(${Math.floor(255 * shade)}, ${Math.floor(64 * shade)}, ${Math.floor(32 * shade)})` : '#000';
            ctx.fillStyle = color;
            ctx.fillRect(screenX - spriteHeight / 4, drawStart, spriteHeight / 2, spriteHeight);
            // Draw health bar
            if (enemy.health > 0 && enemy.health < enemy.maxHealth) {
                const healthBarWidth = spriteHeight / 2;
                const healthPercent = enemy.health / enemy.maxHealth;
                ctx.fillStyle = '#f00';
                ctx.fillRect(screenX - healthBarWidth / 2, drawStart - 10, healthBarWidth, 5);
                ctx.fillStyle = '#0f0';
                ctx.fillRect(screenX - healthBarWidth / 2, drawStart - 10, healthBarWidth * healthPercent, 5);
            }
        }
    }
}
function renderPickups(game, ctx, width, height) {
    const pitchOffset = game.player.pitch * height / 2;
    for (const pickup of game.world.pickups) {
        const dx = pickup.x - game.player.x;
        const dz = pickup.z - game.player.z;
        const distance = Math.sqrt(dx * dx + dz * dz);
        const pickupAngle = Math.atan2(dz, dx);
        const screenX = width / 2 + (pickupAngle - game.player.angle) * width / Math.PI;
        if (Math.abs(screenX - width / 2) < width / 2 && distance < 50) {
            const perpDistance = distance * Math.cos(pickupAngle - game.player.angle);
            const lineHeight = height / perpDistance;
            const spriteHeight = lineHeight * 0.4;
            const drawStart = (height - spriteHeight) / 2 + pitchOffset;
            const shade = Math.max(0, 1 - perpDistance / 20);
            ctx.fillStyle = pickup.type === 'health' ? `rgb(${Math.floor(0 * shade)}, ${Math.floor(255 * shade)}, ${Math.floor(0 * shade)})` : `rgb(${Math.floor(255 * shade)}, ${Math.floor(255 * shade)}, ${Math.floor(0 * shade)})`;
            ctx.fillRect(screenX - spriteHeight / 4, drawStart, spriteHeight / 2, spriteHeight);
        }
    }
}
function renderHUD(game, ctx, width, height) {
    const weapon = game.weapons[game.currentWeapon];
    const weaponDef = state_1.WEAPONS[game.currentWeapon];
    ctx.fillStyle = '#fff';
    ctx.font = '24px sans-serif';
    ctx.textAlign = 'left';
    ctx.fillText(`Health: ${Math.ceil(game.player.health)}`, 20, 40);
    ctx.fillText(`Weapon: ${weaponDef.name}`, 20, 70);
    ctx.fillText(`Ammo: ${weapon.mag}/${weapon.ammo}`, 20, 100);
    ctx.fillText(`Enemies: ${game.world.enemies.length}`, 20, 130);
    if (weapon.reloading) {
        const reloadTime = weaponDef.reloadTime;
        const reloadProgress = (game.time - weapon.reloadStart) / reloadTime;
        ctx.fillText('Reloading...', 20, 160);
        ctx.fillStyle = '#f00';
        ctx.fillRect(20, 170, 200 * reloadProgress, 10);
    }
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"bartowski/ProCreations_grug-27b-GGUF-IQ4","provider":"brigid","persona":"typescript","sessionId":"a1e3e37b-e9d3-41ad-9f39-88333948da81","tokensIn":259662,"tokensOut":13078,"tokensTotal":272740,"cost":0,"turns":17,"toolCalls":16,"failedToolCalls":3,"timestamp":"2026-08-05T17:23:35.281Z"} -->