← RPG results

RPG

GLM 4.6V GGUF · full

Initial view of RPG

Browser check: Artifact runtime error. This is a technical check, not a quality review.

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 42,140 bytes · SHA-256 c2fcf3a80fc4
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Adventure Quest - Action RPG</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: #1a1a2e;
            color: #fff;
            overflow: hidden;
            cursor: crosshair;
        }
        
        #gameCanvas {
            display: block;
            background: linear-gradient(180deg, #0f0f1e 0%, #1a1a2e 100%);
        }
        
        #ui {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            padding: 20px;
            pointer-events: none;
            z-index: 10;
        }
        
        #healthContainer {
            display: flex;
            gap: 10px;
            margin-bottom: 10px;
        }
        
        .heart {
            width: 30px;
            height: 30px;
            background: #ff4757;
            clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
            transition: all 0.3s ease;
            box-shadow: 0 0 10px rgba(255, 71, 87, 0.5);
        }
        
        .heart.empty {
            background: #2f3640;
            opacity: 0.3;
            box-shadow: none;
        }
        
        #inventory {
            position: absolute;
            bottom: 20px;
            left: 20px;
            background: rgba(0, 0, 0, 0.8);
            padding: 15px;
            border-radius: 10px;
            display: flex;
            gap: 10px;
            border: 2px solid #7f8c8d;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
        }
        
        .inventory-slot {
            width: 50px;
            height: 50px;
            background: rgba(255, 255, 255, 0.1);
            border: 2px solid #7f8c8d;
            border-radius: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
            transition: all 0.2s ease;
        }
        
        .inventory-slot:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: scale(1.05);
        }
        
        #money {
            position: absolute;
            top: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.8);
            padding: 10px 20px;
            border-radius: 10px;
            font-size: 18px;
            border: 2px solid #f1c40f;
            box-shadow: 0 0 20px rgba(241, 196, 15, 0.3);
        }
        
        #shop {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.95);
            padding: 30px;
            border-radius: 15px;
            display: none;
            z-index: 100;
            border: 3px solid #3498db;
            box-shadow: 0 0 30px rgba(52, 152, 219, 0.5);
        }
        
        #shop h2 {
            margin-bottom: 20px;
            text-align: center;
            color: #3498db;
            text-shadow: 0 0 10px rgba(52, 152, 219, 0.5);
        }
        
        .shop-item {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin: 10px 0;
            padding: 10px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 8px;
            transition: all 0.2s ease;
        }
        
        .shop-item:hover {
            background: rgba(255, 255, 255, 0.2);
            transform: translateX(5px);
        }
        
        .shop-item button {
            padding: 5px 15px;
            background: #3498db;
            border: none;
            border-radius: 5px;
            color: white;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        
        .shop-item button:hover {
            background: #2980b9;
            transform: scale(1.05);
        }
        
        #savePoint {
            position: absolute;
            bottom: 20px;
            right: 20px;
            background: rgba(0, 0, 0, 0.8);
            padding: 10px 20px;
            border-radius: 10px;
            cursor: pointer;
            transition: all 0.3s ease;
            border: 2px solid #2ecc71;
            box-shadow: 0 0 20px rgba(46, 204, 113, 0.3);
        }
        
        #savePoint:hover {
            background: rgba(46, 204, 113, 0.3);
            transform: scale(1.05);
            box-shadow: 0 0 30px rgba(46, 204, 113, 0.5);
        }
        
        #gameOver {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: rgba(0, 0, 0, 0.95);
            padding: 30px;
            border-radius: 15px;
            text-align: center;
            display: none;
            z-index: 200;
            border: 3px solid #e74c3c;
            box-shadow: 0 0 30px rgba(231, 76, 60, 0.5);
        }
        
        #gameOver button {
            margin-top: 20px;
            padding: 10px 20px;
            background: #3498db;
            border: none;
            border-radius: 5px;
            color: white;
            cursor: pointer;
            font-size: 16px;
            transition: all 0.2s ease;
        }
        
        #gameOver button:hover {
            background: #2980b9;
            transform: scale(1.05);
        }
        
        .damage-text {
            position: absolute;
            color: #ff4757;
            font-weight: bold;
            font-size: 24px;
            pointer-events: none;
            animation: damageFloat 1s ease-out forwards;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
        }
        
        @keyframes damageFloat {
            0% {
                opacity: 1;
                transform: translateY(0);
            }
            100% {
                opacity: 0;
                transform: translateY(-50px);
            }
        }
        
        /* Add visual feedback for stamina */
        .stamina-bar {
            position: absolute;
            bottom: 20px;
            right: 20px;
            width: 150px;
            height: 20px;
            background: rgba(0, 0, 0, 0.7);
            border-radius: 10px;
            overflow: hidden;
            border: 2px solid #7f8c8d;
        }
        
        .stamina-fill {
            height: 100%;
            background: linear-gradient(90deg, #2ecc71, #27ae60);
            transition: width 0.3s ease;
        }
        
        .stamina-empty {
            background: #e74c3c;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    
    <div id="ui">
        <div id="healthContainer"></div>
        <div id="money">Gold: 0</div>
    </div>
    
    <div id="inventory">
        <div class="inventory-slot" data-slot="0"></div>
        <div class="inventory-slot" data-slot="1"></div>
        <div class="inventory-slot" data-slot="2"></div>
        <div class="inventory-slot" data-slot="3"></div>
        <div class="inventory-slot" data-slot="4"></div>
    </div>
    
    <div class="stamina-bar">
        <div class="stamina-fill" id="staminaFill"></div>
    </div>
    
    <div id="savePoint">Save Point</div>
    
    <div id="shop">
        <h2>Item Shop</h2>
        <div id="shopItems"></div>
    </div>
    
    <div id="gameOver">
        <h2>Game Over</h2>
        <p>You have been defeated!</p>
        <button onclick="restartGame()">Restart</button>
    </div>
    
    <script>
        // Game Configuration
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        
        // Player State & Visuals
        const gameState = {
            player: {
                x: canvas.width / 2,
                y: canvas.height / 2,
                width: 40,
                height: 40,
                health: 6,
                maxHealth: 6,
                healthContainers: 3,
                maxHealthContainers: 5,
                speed: 3,
                stamina: 100,
                maxStamina: 100,
                weapon: 'sword',
                weaponLevel: 0,
                hasRanged: false,
                money: 0,
                inventory: [],
                facing: 'right',
                isWalking: false,
                walkFrame: 0,
                lastWalkTime: 0
            },
            keys: {},
            enemies: [],
            items: [],
            particles: [],
            shops: [],
            savePoints: [],
            currentArea: 0,
            gameProgress: 0,
            isShopOpen: false,
            isGameOver: false,
            lastAttackTime: 0
        };
        
        // Sound Effects
        const sounds = {
            walk: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w=='),
            attack: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w=='),
            damage: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w=='),
            pickup: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w=='),
            shop: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w=='),
            save: new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQoAAAD//w==')
        };

        // Initialize sound effects (using base64 encoded empty sounds as placeholders)
        Object.values(sounds).forEach(sound => {
            sound.volume = 0.3;
        });
        
        // Item Definitions
        const itemDefinitions = {
            potion: { name: 'Health Potion', icon: '❤️', effect: 'heal', value: 20 },
            key: { name: 'Dungeon Key', icon: '🔑', effect: 'key', value: 0 },
            coin: { name: 'Gold Coin', icon: '💰', effect: 'money', value: 10 },
            shield: { name: 'Iron Shield', icon: '🛡️', effect: 'defense', value: 0 },
            bomb: { name: 'Bomb', icon: '💣', effect: 'bomb', value: 0 }
        };
        
        // Weapon Definitions
        const weapons = {
            sword: {
                name: 'Iron Sword',
                damage: 2,
                attackSpeed: 1000,
                range: 50,
                color: '#8e44ad',
                level: 0,
                description: 'A basic iron sword'
            },
            sword2: {
                name: 'Steel Sword',
                damage: 4,
                attackSpeed: 800,
                range: 60,
                color: '#3498db',
                level: 1,
                description: 'A stronger steel sword'
            },
            sword3: {
                name: 'Diamond Sword',
                damage: 7,
                attackSpeed: 600,
                range: 70,
                color: '#f1c40f',
                level: 2,
                description: 'A powerful diamond sword'
            },
            bow: {
                name: 'Wooden Bow',
                damage: 3,
                attackSpeed: 1500,
                range: 150,
                color: '#27ae60',
                level: 0,
                description: 'A ranged wooden bow'
            }
        };
        
        // Shop Items
        const shopItems = [
            { name: 'Health Potion', price: 20, icon: '❤️', effect: 'heal' },
            { name: 'Health Container', price: 100, icon: '💚', effect: 'healthContainer' },
            { name: 'Steel Sword', price: 150, icon: '⚔️', effect: 'weaponUpgrade' },
            { name: 'Diamond Sword', price: 300, icon: '⚔️', effect: 'weaponUpgrade' },
            { name: 'Wooden Bow', price: 200, icon: '🏹', effect: 'rangedWeapon' }
        ];
        
        // Initialize Game
        function init() {
            setupEventListeners();
            createInitialWorld();
            updateUI();
            gameLoop();
        }
        
        // Event Listeners
        function setupEventListeners() {
            window.addEventListener('keydown', (e) => {
                gameState.keys[e.key.toLowerCase()] = true;
                
                // Visual feedback for key presses
                if (e.key === ' ') {
                    e.preventDefault();
                    attack();
                }
                if (e.key === 'i') {
                    openShop();
                }
                if (e.key === 's') {
                    saveGame();
                }
            });
            
            window.addEventListener('keyup', (e) => {
                gameState.keys[e.key.toLowerCase()] = false;
            });
            
            window.addEventListener('resize', () => {
                canvas.width = window.innerWidth;
                canvas.height = window.innerHeight;
                gameState.player.x = Math.min(gameState.player.x, canvas.width - gameState.player.width);
                gameState.player.y = Math.min(gameState.player.y, canvas.height - gameState.player.height);
            });
            
            document.getElementById('savePoint').addEventListener('click', saveGame);
        }
        
        // Create Initial World
        function createInitialWorld() {
            // Create enemies with varying types and difficulties
            for (let i = 0; i < 5; i++) {
                const enemyTypes = ['goblin', 'orc', 'skeleton'];
                const enemyType = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
                
                let health, damage, speed;
                switch(enemyType) {
                    case 'goblin':
                        health = 3;
                        damage = 1;
                        speed = 1;
                        break;
                    case 'orc':
                        health = 5;
                        damage = 2;
                        speed = 0.8;
                        break;
                    case 'skeleton':
                        health = 4;
                        damage = 1.5;
                        speed = 1.2;
                        break;
                }
                
                gameState.enemies.push({
                    x: Math.random() * canvas.width,
                    y: Math.random() * canvas.height,
                    width: 30,
                    height: 30,
                    health: health,
                    maxHealth: health,
                    speed: speed,
                    damage: damage,
                    type: enemyType
                });
            }
            
            // Create items with better distribution
            gameState.items.push({
                x: 200,
                y: 200,
                type: 'potion',
                collected: false
            });
            
            gameState.items.push({
                x: 400,
                y: 300,
                type: 'coin',
                collected: false
            });
            
            gameState.items.push({
                x: 600,
                y: 150,
                type: 'shield',
                collected: false
            });
            
            gameState.items.push({
                x: 300,
                y: 450,
                type: 'bomb',
                collected: false
            });
            
            gameState.items.push({
                x: 700,
                y: 400,
                type: 'key',
                collected: false
            });
            
            // Create save point
            gameState.savePoints.push({
                x: canvas.width / 2,
                y: canvas.height / 2,
                radius: 50
            });
            
            // Create shop
            gameState.shops.push({
                x: canvas.width - 200,
                y: canvas.height - 200,
                radius: 60
            });
            
            // Create additional save points for progression
            gameState.savePoints.push({
                x: canvas.width / 4,
                y: canvas.height / 4,
                radius: 50
            });
            
            gameState.savePoints.push({
                x: (canvas.width * 3) / 4,
                y: (canvas.height * 3) / 4,
                radius: 50
            });
        }
        
        // Game Loop
        function gameLoop() {
            if (gameState.isGameOver) return;
            
            update();
            render();
            
            // Limit frame rate for better performance
            setTimeout(() => {
                requestAnimationFrame(gameLoop);
            }, 16); // ~60 FPS
        }
        
        // Update Game State
        function update() {
            updatePlayer();
            updateEnemies();
            updateItems();
            updateParticles();
            checkCollisions();
            updateProgression();
        }
        
        // Update Player
        function updatePlayer() {
            let dx = 0;
            let dy = 0;
            let isMoving = false;
            
            if (gameState.keys['a'] || gameState.keys['arrowleft']) {
                dx = -gameState.player.speed;
                gameState.player.facing = 'left';
                isMoving = true;
            }
            if (gameState.keys['d'] || gameState.keys['arrowright']) {
                dx = gameState.player.speed;
                gameState.player.facing = 'right';
                isMoving = true;
            }
            if (gameState.keys['w'] || gameState.keys['arrowup']) {
                dy = -gameState.player.speed;
                isMoving = true;
            }
            if (gameState.keys['s'] || gameState.keys['arrowdown']) {
                dy = gameState.player.speed;
                isMoving = true;
            }
            
            // Update walking animation
            if (isMoving) {
                gameState.player.isWalking = true;
                const now = Date.now();
                if (now - gameState.player.lastWalkTime > 150) {
                    gameState.player.walkFrame = (gameState.player.walkFrame + 1) % 4;
                    gameState.player.lastWalkTime = now;
                }
            } else {
                gameState.player.isWalking = false;
                gameState.player.walkFrame = 0;
            }
            
            // Update position
            gameState.player.x += dx;
            gameState.player.y += dy;
            
            // Keep player in bounds
            gameState.player.x = Math.max(0, Math.min(canvas.width - gameState.player.width, gameState.player.x));
            gameState.player.y = Math.max(0, Math.min(canvas.height - gameState.player.height, gameState.player.y));
            
            // Update stamina
            if (isMoving) {
                gameState.player.stamina = Math.max(0, gameState.player.stamina - 0.5);
            } else {
                gameState.player.stamina = Math.min(gameState.player.maxStamina, gameState.player.stamina + 0.2);
            }
        }
        
        // Update Enemies
        function updateEnemies() {
            gameState.enemies.forEach(enemy => {
                // Simple AI: move towards player
                const dx = gameState.player.x - enemy.x;
                const dy = gameState.player.y - enemy.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance > 0) {
                    enemy.x += (dx / distance) * enemy.speed;
                    enemy.y += (dy / distance) * enemy.speed;
                }
            });
        }
        
        // Update Items
        function updateItems() {
            gameState.items.forEach(item => {
                if (!item.collected) {
                    // Check if player is near item
                    const dx = gameState.player.x - item.x;
                    const dy = gameState.player.y - item.y;
                    const distance = Math.sqrt(dx * dx + dy * dy);
                    
                    if (distance < 30) {
                        collectItem(item);
                    }
                }
            });
        }
        
        // Update Particles
        function updateParticles() {
            gameState.particles = gameState.particles.filter(particle => {
                particle.x += particle.vx;
                particle.y += particle.vy;
                particle.life -= 0.02;
                return particle.life > 0;
            });
        }
        
        // Check Collisions
        function checkCollisions() {
            // Enemy collisions
            gameState.enemies.forEach(enemy => {
                const dx = gameState.player.x - enemy.x;
                const dy = gameState.player.y - enemy.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < 30) {
                    takeDamage(enemy.damage);
                }
            });
            
            // Shop interaction
            gameState.shops.forEach(shop => {
                const dx = gameState.player.x - shop.x;
                const dy = gameState.player.y - shop.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < shop.radius) {
                    if (!gameState.isShopOpen) {
                        openShop();
                    }
                }
            });
            
            // Save point interaction
            gameState.savePoints.forEach(savePoint => {
                const dx = gameState.player.x - savePoint.x;
                const dy = gameState.player.y - savePoint.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < savePoint.radius) {
                    saveGame();
                    createNotification('Progress saved at this location!');
                }
            });
            
            // Update game progress based on actions
            gameState.gameProgress += 0.1;
        }
        
        // Update Progression
        function updateProgression() {
            // Check for mid-game progression (ranged weapon discovery)
            if (gameState.gameProgress >= 50 && !gameState.hasRanged) {
                gameState.hasRanged = true;
                gameState.player.weapon = 'bow';
                createNotification('You discovered a Wooden Bow! Press Space to shoot arrows.');
                createParticles(gameState.player.x, gameState.player.y, '#27ae60');
            }
            
            // Check for late-game progression
            if (gameState.gameProgress >= 100 && gameState.player.healthContainers < gameState.player.maxHealthContainers) {
                createNotification('You feel stronger! Maximum health increased!');
                gameState.player.healthContainers++;
                gameState.player.maxHealth = gameState.player.healthContainers * 2;
                gameState.player.health = gameState.player.maxHealth;
                updateUI();
            }
        }
        
        // Attack
        function attack() {
            const now = Date.now();
            if (now - gameState.lastAttackTime < weapons[gameState.player.weapon].attackSpeed) return;
            gameState.lastAttackTime = now;
            
            const weapon = weapons[gameState.player.weapon];
            const attackRange = weapon.range;
            
            // Play attack sound
            sounds.attack.play().catch(() => {});
            
            // Create attack effect
            createAttackEffect();
            
            // Check for enemy hits
            gameState.enemies.forEach(enemy => {
                const dx = enemy.x - gameState.player.x;
                const dy = enemy.y - gameState.player.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                if (distance < attackRange) {
                    enemy.health -= weapon.damage;
                    createDamageText(enemy.x, enemy.y, weapon.damage);
                    
                    if (enemy.health <= 0) {
                        // Enemy defeated
                        createParticles(enemy.x, enemy.y, '#ff4757');
                        gameState.enemies.splice(gameState.enemies.indexOf(enemy), 1);
                        gameState.player.money += 10;
                        updateUI();
                    }
                }
            });
        }
        
        // Take Damage
        function takeDamage(amount) {
            gameState.player.health -= amount;
            createDamageText(gameState.player.x, gameState.player.y, amount);
            createParticles(gameState.player.x, gameState.player.y, '#ff4757');
            
            // Play damage sound
            sounds.damage.play().catch(() => {});
            
            if (gameState.player.health <= 0) {
                gameOver();
            }
            
            updateUI();
        }
        
        // Collect Item
        function collectItem(item) {
            item.collected = true;
            createParticles(item.x, item.y, '#2ecc71');
            createNotification(`Collected ${itemDefinitions[item.type].name}`);
            
            // Play pickup sound
            sounds.pickup.play().catch(() => {});
            
            switch (item.type) {
                case 'potion':
                    gameState.player.health = Math.min(gameState.player.maxHealth, gameState.player.health + itemDefinitions[item.type].value);
                    break;
                case 'coin':
                    gameState.player.money += itemDefinitions[item.type].value;
                    break;
                case 'key':
                    gameState.player.inventory.push(item.type);
                    break;
                case 'shield':
                    gameState.player.inventory.push(item.type);
                    break;
                case 'bomb':
                    gameState.player.inventory.push(item.type);
                    break;
            }
            
            updateUI();
        }
        
        // Create Attack Effect
        function createAttackEffect() {
            const weapon = weapons[gameState.player.weapon];
            const direction = gameState.player.facing === 'right' ? 1 : -1;
            
            // Create more dramatic attack particles
            for (let i = 0; i < 10; i++) {
                const angle = (Math.PI * 2 * i) / 10;
                const speed = 3 + Math.random() * 2;
                gameState.particles.push({
                    x: gameState.player.x + (direction * 20),
                    y: gameState.player.y,
                    vx: Math.cos(angle) * speed,
                    vy: Math.sin(angle) * speed,
                    life: 1,
                    color: weapon.color
                });
            }
            
            // Add attack flash effect
            const flash = document.createElement('div');
            flash.style.position = 'absolute';
            flash.style.left = '0';
            flash.style.top = '0';
            flash.style.width = '100%';
            flash.style.height = '100%';
            flash.style.background = `rgba(255, 255, 255, 0.1)`;
            flash.style.pointerEvents = 'none';
            flash.style.zIndex = '100';
            document.body.appendChild(flash);
            
            setTimeout(() => flash.remove(), 100);
        }
        
        // Create Damage Text
        function createDamageText(x, y, damage) {
            const damageText = document.createElement('div');
            damageText.className = 'damage-text';
            damageText.textContent = `-${damage}`;
            damageText.style.left = `${x}px`;
            damageText.style.top = `${y}px`;
            damageText.style.fontSize = '24px';
            damageText.style.fontWeight = 'bold';
            damageText.style.textShadow = '2px 2px 4px rgba(0, 0, 0, 0.5)';
            document.body.appendChild(damageText);
            
            setTimeout(() => damageText.remove(), 1000);
        }
        
        // Create Particles
        function createParticles(x, y, color) {
            // Create burst of particles with varying sizes and velocities
            for (let i = 0; i < 15; i++) {
                const angle = (Math.PI * 2 * i) / 15;
                const speed = 2 + Math.random() * 4;
                const size = 3 + Math.random() * 4;
                
                gameState.particles.push({
                    x: x,
                    y: y,
                    vx: Math.cos(angle) * speed,
                    vy: Math.sin(angle) * speed,
                    life: 1,
                    color: color,
                    size: size
                });
            }
        }
        
        // Create Notification
        function createNotification(message) {
            const notification = document.createElement('div');
            notification.style.position = 'absolute';
            notification.style.top = '50%';
            notification.style.left = '50%';
            notification.style.transform = 'translate(-50%, -50%)';
            notification.style.background = 'rgba(0, 0, 0, 0.9)';
            notification.style.padding = '20px 30px';
            notification.style.borderRadius = '10px';
            notification.style.fontSize = '20px';
            notification.style.zIndex = '1000';
            notification.style.border = '2px solid #3498db';
            notification.style.boxShadow = '0 0 20px rgba(52, 152, 219, 0.5)';
            notification.textContent = message;
            document.body.appendChild(notification);
            
            setTimeout(() => notification.remove(), 2000);
        }
        
        // Open Shop
        function openShop() {
            if (gameState.isShopOpen) return;
            
            gameState.isShopOpen = true;
            document.getElementById('shop').style.display = 'block';
            
            // Play shop sound
            sounds.shop.play().catch(() => {});
            
            const shopItemsContainer = document.getElementById('shopItems');
            shopItemsContainer.innerHTML = '';
            
            shopItems.forEach(item => {
                const itemElement = document.createElement('div');
                itemElement.className = 'shop-item';
                itemElement.innerHTML = `
                    <span>${item.icon} ${item.name}</span>
                    <button onclick="buyItem('${item.effect}', ${item.price})">Buy (${item.price}g)</button>
                `;
                shopItemsContainer.appendChild(itemElement);
            });
        }
        
        // Buy Item
        function buyItem(effect, price) {
            if (gameState.player.money >= price) {
                gameState.player.money -= price;
                
                switch (effect) {
                    case 'heal':
                        gameState.player.health = Math.min(gameState.player.maxHealth, gameState.player.health + 20);
                        createNotification('Health restored!');
                        break;
                    case 'healthContainer':
                        if (gameState.player.healthContainers < gameState.player.maxHealthContainers) {
                            gameState.player.healthContainers++;
                            gameState.player.maxHealth = gameState.player.healthContainers * 2;
                            gameState.player.health = gameState.player.maxHealth;
                            createNotification('Maximum health increased!');
                        }
                        break;
                    case 'weaponUpgrade':
                        if (gameState.player.weaponLevel < 2) {
                            gameState.player.weaponLevel++;
                            gameState.player.weapon = `sword${gameState.player.weaponLevel + 1}`;
                            createNotification(`${weapons[gameState.player.weapon].name} acquired!`);
                        }
                        break;
                    case 'rangedWeapon':
                        if (!gameState.hasRanged) {
                            gameState.hasRanged = true;
                            gameState.player.weapon = 'bow';
                            createNotification('Wooden Bow acquired! Press Space to shoot arrows.');
                        }
                        break;
                }
                
                updateUI();
                createNotification('Purchase successful!');
            } else {
                createNotification('Not enough gold!');
            }
        }
        
        // Save Game
        function saveGame() {
            const saveData = {
                player: gameState.player,
                enemies: gameState.enemies,
                items: gameState.items,
                money: gameState.player.money,
                gameProgress: gameState.gameProgress
            };
            
            localStorage.setItem('adventureQuestSave', JSON.stringify(saveData));
            
            // Play save sound
            sounds.save.play().catch(() => {});
            
            createNotification('Game saved!');
        }
        
        // Game Over
        function gameOver() {
            gameState.isGameOver = true;
            document.getElementById('gameOver').style.display = 'block';
        }
        
        // Restart Game
        function restartGame() {
            gameState.isGameOver = false;
            document.getElementById('gameOver').style.display = 'none';
            
            // Reset game state with proper initialization
            gameState.player = {
                x: canvas.width / 2,
                y: canvas.height / 2,
                width: 40,
                height: 40,
                health: 6,
                maxHealth: 6,
                healthContainers: 3,
                maxHealthContainers: 5,
                speed: 3,
                stamina: 100,
                maxStamina: 100,
                weapon: 'sword',
                weaponLevel: 0,
                hasRanged: false,
                money: 0,
                inventory: [],
                facing: 'right',
                isWalking: false,
                walkFrame: 0,
                lastWalkTime: 0
            };
            
            gameState.enemies = [];
            gameState.items = [];
            gameState.particles = [];
            gameState.gameProgress = 0;
            gameState.lastAttackTime = 0;
            
            createInitialWorld();
            updateUI();
            gameLoop();
            
            createNotification('Game restarted! Good luck on your adventure!');
        }
        
        // Update UI
        function updateUI() {
            // Update health display
            const healthContainer = document.getElementById('healthContainer');
            healthContainer.innerHTML = '';
            
            for (let i = 0; i < gameState.player.healthContainers; i++) {
                const heart = document.createElement('div');
                heart.className = 'heart';
                if (i >= Math.ceil(gameState.player.health / 2)) {
                    heart.classList.add('empty');
                }
                healthContainer.appendChild(heart);
            }
            
            // Update money
            document.getElementById('money').textContent = `Gold: ${gameState.player.money}`;
            
            // Update stamina bar
            const staminaFill = document.getElementById('staminaFill');
            staminaFill.style.width = `${(gameState.player.stamina / gameState.player.maxStamina) * 100}%`;
            staminaFill.className = gameState.player.stamina > 30 ? 'stamina-fill' : 'stamina-fill stamina-empty';
            
            // Update inventory
            const inventorySlots = document.querySelectorAll('.inventory-slot');
            inventorySlots.forEach((slot, index) => {
                slot.innerHTML = '';
                if (gameState.player.inventory[index]) {
                    slot.textContent = itemDefinitions[gameState.player.inventory[index]].icon;
                    slot.style.borderColor = '#f1c40f';
                    slot.style.boxShadow = '0 0 10px rgba(241, 196, 15, 0.5)';
                } else {
                    slot.style.borderColor = '#7f8c8d';
                    slot.style.boxShadow = 'none';
                }
            });
        }
        
        // Render Game
        function render() {
            // Clear canvas
            ctx.fillStyle = '#0f0f1e';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            
            // Draw grid pattern
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.05)';
            ctx.lineWidth = 1;
            for (let x = 0; x < canvas.width; x += 50) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, canvas.height);
                ctx.stroke();
            }
            for (let y = 0; y < canvas.height; y += 50) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(canvas.width, y);
                ctx.stroke();
            }
            
            // Draw save points
            gameState.savePoints.forEach(savePoint => {
                ctx.fillStyle = 'rgba(46, 204, 113, 0.3)';
                ctx.beginPath();
                ctx.arc(savePoint.x, savePoint.y, savePoint.radius, 0, Math.PI * 2);
                ctx.fill();
                
                ctx.strokeStyle = '#2ecc71';
                ctx.lineWidth = 2;
                ctx.stroke();
            });
            
            // Draw shops
            gameState.shops.forEach(shop => {
                ctx.fillStyle = 'rgba(52, 152, 219, 0.3)';
                ctx.beginPath();
                ctx.arc(shop.x, shop.y, shop.radius, 0, Math.PI * 2);
                ctx.fill();
                
                ctx.strokeStyle = '#3498db';
                ctx.lineWidth = 2;
                ctx.stroke();
            });
            
            // Draw items
            gameState.items.forEach(item => {
                if (!item.collected) {
                    ctx.fillStyle = '#f1c40f';
                    ctx.font = '20px Arial';
                    ctx.fillText(itemDefinitions[item.type].icon, item.x - 10, item.y + 5);
                }
            });
            
            // Draw enemies
            gameState.enemies.forEach(enemy => {
                ctx.fillStyle = '#e74c3c';
                ctx.fillRect(enemy.x - enemy.width/2, enemy.y - enemy.height/2, enemy.width, enemy.height);
                
                // Draw health bar
                ctx.fillStyle = '#c0392b';
                ctx.fillRect(enemy.x - 15, enemy.y - 25, 30, 4);
                ctx.fillStyle = '#2ecc71';
                ctx.fillRect(enemy.x - 15, enemy.y - 25, (enemy.health / enemy.maxHealth) * 30, 4);
            });
            
            // Draw player with walking animation
            ctx.fillStyle = '#3498db';
            ctx.fillRect(gameState.player.x - gameState.player.width/2, gameState.player.y - gameState.player.height/2, gameState.player.width, gameState.player.height);
            
            // Draw walking animation effect
            if (gameState.player.isWalking) {
                ctx.fillStyle = 'rgba(52, 152, 219, 0.3)';
                const offset = Math.sin(gameState.player.walkFrame * Math.PI / 2) * 5;
                ctx.fillRect(
                    gameState.player.x - gameState.player.width/2 + offset,
                    gameState.player.y - gameState.player.height/2,
                    gameState.player.width,
                    gameState.player.height
                );
            }
            
            // Draw stamina bar
            ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
            ctx.fillRect(gameState.player.x - 25, gameState.player.y - 40, 50, 6);
            ctx.fillStyle = gameState.player.stamina > 30 ? '#2ecc71' : '#e74c3c';
            ctx.fillRect(gameState.player.x - 25, gameState.player.y - 40, (gameState.player.stamina / gameState.player.maxStamina) * 50, 6);
            
            // Draw weapon
            const weapon = weapons[gameState.player.weapon];
            ctx.fillStyle = weapon.color;
            const direction = gameState.player.facing === 'right' ? 1 : -1;
            ctx.fillRect(
                gameState.player.x + (direction * 20),
                gameState.player.y - 5,
                20,
                10
            );
            
            // Draw particles
            gameState.particles.forEach(particle => {
                ctx.fillStyle = particle.color;
                ctx.globalAlpha = particle.life;
                ctx.fillRect(particle.x - particle.size/2, particle.y - particle.size/2, particle.size, particle.size);
                ctx.globalAlpha = 1;
            });
        }
        
        // Initialize game
        init();
    </script>
</body>
</html>
<!-- agent-meta {"model":"unsloth/GLM-4.6V-GGUF","provider":"brigid","persona":"full","sessionId":"11e1fead-3d4a-4221-b03d-f7f196759d0e","tokensIn":1421928,"tokensOut":17999,"tokensTotal":1439927,"cost":0,"turns":47,"toolCalls":46,"failedToolCalls":1,"timestamp":"2026-08-06T00:22:31.149Z"} -->