403Webshell
Server IP : 167.235.67.158  /  Your IP : 216.73.216.95
Web Server : Apache
System : Linux ubuntu-8gb-nbg1-1 6.8.0-111-generic #111-Ubuntu SMP PREEMPT_DYNAMIC Sat Apr 11 23:16:02 UTC 2026 x86_64
User : upstairsbar.co.uk ( 982)
PHP Version : 8.3.6
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/bc.the-word.com/bowling/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/bc.the-word.com/bowling/index.html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bowling Game</title>

    <link href="https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600&display=swap" rel="stylesheet" />

    <style>
        html,
        body {
            height: 100%;
            overflow: hidden;
            position: fixed;
            width: 100%;
            color: #fff;
            margin: 0;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            background: #000;
            font-family: "Fredoka", sans-serif;
            font-weight: 400;
            touch-action: none;
        }

        canvas {
            position: relative;
            width: 100%;
            height: 100%;
            max-width: 100vw;
            max-height: 100vh;
            background: #000;
            overflow: hidden;
            aspect-ratio: 5 / 8;
            width: min(100vw, calc(100vh * 5 / 8));
            height: min(100vh, calc(100vw * 8 / 5));
        }

        #preloader {
            position: absolute;
            top: 0;
            left: 50%;
            width: min(100vw, calc(100vh * 5 / 8));
            height: min(100vh, calc(100vw * 8 / 5));
            z-index: 10;
            transform: translateX(-50%);
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            transition: opacity 0.5s ease-out;
        }

        #preloader.fade-out {
            opacity: 0;
            pointer-events: none;
        }

        .logo {
            font-size: 48px;
            font-weight: 600;
            color: white;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            margin-bottom: 40px;
            animation: logoGlow 2s ease-in-out infinite alternate;
        }

        @keyframes logoGlow {
            from {
                text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            }

            to {
                text-shadow: 2px 2px 20px rgba(255, 255, 255, 0.5), 2px 2px 4px rgba(0, 0, 0, 0.5);
            }
        }

        .loading-bar {
            width: 200px;
            height: 4px;
            background: rgba(255, 255, 255, 0.3);
            border-radius: 2px;
            overflow: hidden;
            margin-bottom: 20px;
        }

        .loading-progress {
            width: 0%;
            height: 100%;
            background: linear-gradient(90deg, #4CAF50, #8BC34A);
            border-radius: 2px;
            transition: width 0.3s ease;
        }

        .loading-text {
            color: rgba(255, 255, 255, 0.8);
            font-size: 16px;
            font-weight: 400;
        }

        #homeScreen {
            position: absolute;
            top: 0;
            left: 50%;
            width: min(100vw, calc(100vh * 5 / 8));
            height: min(100vh, calc(100vw * 8 / 5));
            z-index: 10;
            transform: translateX(-50%);
            background: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%);
            transition: opacity 0.5s ease-out;
        }

        #homeScreen.fade-out {
            opacity: 0;
            pointer-events: none;
        }

        .screen-content {
            position: relative;
            height: 100%;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .game-title {
            font-size: 42px;
            font-weight: 600;
            color: white;
            text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
            margin-bottom: 20px;
            animation: titleBounce 1.5s ease-in-out infinite alternate;
        }

        .game-description {
            font-size: 18px;
            color: rgba(255, 255, 255, 0.9);
            text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
            cursor: pointer;
            padding: 10px 20px;
            border: 2px solid rgba(255, 255, 255, 0.5);
            border-radius: 25px;
            transition: all 0.3s ease;
        }

        .game-description:hover {
            background: rgba(255, 255, 255, 0.1);
            border-color: rgba(255, 255, 255, 0.8);
        }

        @keyframes titleBounce {
            from {
                transform: translateY(0px);
            }

            to {
                transform: translateY(-5px);
            }
        }
    </style>
</head>

<body>
    <div id="preloader">
        <div class="logo">A New Game</div>
        <div class="loading-bar">
            <div class="loading-progress" id="loadingProgress"></div>
        </div>
        <div class="loading-text" id="loadingText">Loading...</div>
    </div>

    <div id="homeScreen" style="display: none;">
        <div class="screen-content">
            <div class="game-title">🌿 Wall-nut Bowling</div>
            <div class="game-description">Click to Start</div>
        </div>
    </div>

    <script type="module">
        import * as Phaser from "https://cdn.jsdelivr.net/npm/phaser@3.90.0/dist/phaser.esm.min.js";


        class Preloader extends Phaser.Scene {
            constructor() {
                super({ key: "Preloader" });
            }

            preload() {
                const progressBar = document.getElementById('loadingProgress');
                const progressText = document.getElementById('loadingText');

                this.load.on('progress', (value) => {
                    const percentage = Math.floor(value * 100);
                    progressBar.style.width = percentage + '%';
                    progressText.textContent = `Loading... ${percentage}%`;
                });

                this.load.on('complete', () => {
                    progressText.textContent = 'Ready!';

                    setTimeout(() => {
                        const preloader = document.getElementById('preloader');
                        preloader.classList.add('fade-out');

                        setTimeout(() => {
                            preloader.style.display = 'none';
                            const homeScreen = document.getElementById('homeScreen');
                            homeScreen.style.display = 'block';
                            console.log('[HOME SCREEN] Home screen now visible - click to start game');
                        }, 500);
                    }, 500);
                });

                // Example asset loading - you can add your bowling assets here
                // this.load.image('ball', 'assets/bowling-ball.png');
                // this.load.image('pin', 'assets/bowling-pin.png');
                // this.load.image('lane', 'assets/bowling-lane.png');

                // Load background image
                this.load.image('background', 'background.jpg');
                // Load scroll image for falling cards
                this.load.image('scroll', 'scroll.png');
                // Load shield image for armored enemies
                this.load.image('shield', 'shield.png');

                // Load character sprite sheets with atlas
                this.load.atlas('summoner', 'wizards-15.png', 'frames.json');
                this.load.atlas('armored', 'wizards-283.png', 'frames.json');
                this.load.atlas('basic', 'wizards-989.png', 'frames.json');
                this.load.atlas('summoned', 'wizards-965.png', 'frames.json');
                this.load.atlas('defender', 'wizards-242.png', 'frames.json');
                this.load.atlas('jeff', 'wizards-366.png', 'frames.json');

                // For now, create placeholder graphics
                this.load.on('complete', () => {
                    // Complete callback already handled above
                });

                // Simulate loading time
                this.load.image('placeholder', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==');
            }
        }

        // Layer Depth Constants
        const LAYERS = {
            BACKGROUND: 0,
            TILES: 10,
            GRAPHICS: 20,
            ENEMIES: 30,
            PROJECTILES: 40,
            CARDS: 45,
            GUI: 50
        };

        // Base Enemy Class - Holds core mechanics
        class Enemy extends Phaser.GameObjects.Container {
            constructor(scene, x, y) {
                super(scene, x, y);
                this.scene = scene;
                this.maxHealth = this.getMaxHealth();
                this.health = this.maxHealth;
                this.hitRadius = this.getHitRadius();
                this.movementSpeed = this.getMovementSpeed();
                this.isPaused = false;
                this.pauseTimer = 0;
                this.createVisuals();
                this.setDepth(LAYERS.ENEMIES);
                scene.add.existing(this);
            }

            // Abstract methods - to be overridden by subclasses
            getMaxHealth() { return 1; }
            getHitRadius() { return 20; }
            getMovementSpeed() { return 1; }
            createVisuals() { }
            onMove(deltaTime) { }
            onSummon() { }

            // Core mechanics - shared by all enemies
            takeDamage(damage = 1) {
                this.health -= damage;
                this.onDamageTaken(damage);

                // Pause movement for 1 second when taking damage
                this.isPaused = true;
                this.pauseTimer = 1000; // 1000ms = 1 second

                if (this.health <= 0) {
                    this.onDestroy();
                    return true;
                }
                return false;
            }

            onDamageTaken(damage) {
                // Flash red when taking damage
                this.flashRed();
                // Override in subclasses for specific damage reactions
            }

            onDestroy() {
                console.log(`[ENEMY] ${this.constructor.name} destroyed at position (${Math.round(this.x)}, ${Math.round(this.y)})`);
                // Flash red and fade out on death
                this.flashRed(() => {
                    this.fadeOut(() => {
                        console.log(`[ENEMY] ${this.constructor.name} fade complete, returning to pool`);
                        this.scene.returnEnemyToPool(this);
                    });
                });
                // Override in subclasses for specific death effects
            }

            flashRed(callback) {
                // Flash red effect for damage
                // Apply tint to all contained objects
                this.each((child) => {
                    if (child.setTint) {
                        child.setTint(0xff0000);
                    }
                });

                this.scene.tweens.add({
                    targets: this,
                    duration: 200,
                    onComplete: () => {
                        // Clear tint from all contained objects
                        this.each((child) => {
                            if (child.clearTint) {
                                child.clearTint();
                            }
                        });
                        if (callback) callback();
                    }
                });
            }

            fadeOut(callback) {
                // Fade out effect for death
                this.scene.tweens.add({
                    targets: this,
                    alpha: 0,
                    duration: 500,
                    ease: 'Power2.easeOut',
                    onComplete: () => {
                        this.setAlpha(1); // Reset for reuse
                        if (callback) callback();
                    }
                });
            }

            update(deltaTime) {
                // Handle pause timer
                if (this.isPaused) {
                    this.pauseTimer -= deltaTime;
                    if (this.pauseTimer <= 0) {
                        this.isPaused = false;
                        this.pauseTimer = 0;
                    }
                    return; // Don't move while paused
                }

                this.onMove(deltaTime);
            }

            reset() {
                this.health = this.maxHealth;
                this.setAlpha(1);
                this.setVisible(true);
                this.setActive(true);
                this.isPaused = false;
                this.pauseTimer = 0;
                this.createVisuals();
            }
        }

        // Basic Enemy - Red triangle with 1 health
        class BasicEnemy extends Enemy {
            constructor(scene, x, y) {
                super(scene, x, y);
                this.isPaused = false;
                this.pauseTimer = 0;
            }

            getMaxHealth() { return 1; }
            getHitRadius() { return 15; }
            getMovementSpeed() { return 1; }

            createVisuals() {
                this.removeAll(true);

                // Create sprite for basic enemy
                this.sprite = this.scene.add.sprite(0, 0, 'basic', '0');
                this.sprite.setScale(1.75); // Double the enemy size
                this.add(this.sprite);

                // Play idle animation initially
                this.sprite.play('basic-idle');
            }

            onMove(deltaTime) {
                // Basic movement - move down slowly
                const movement = this.movementSpeed * deltaTime * 0.02;
                this.y += movement;

                // Play walking animation if moving
                if (this.sprite && !this.sprite.anims.isPlaying || this.sprite.anims.currentAnim.key !== 'basic-walk-down') {
                    this.sprite.play('basic-walk-down');
                }

                // Check if enemy has reached the bottom boundary
                const bottomBoundary = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                if (this.y > bottomBoundary) {
                    // Stop at boundary for now
                    this.y = bottomBoundary;
                }
            }
        }

        // SummonedEnemy - Created by summoners, similar to basic but with different appearance
        class SummonedEnemy extends BasicEnemy {
            constructor(scene, x, y) {
                super(scene, x, y);
            }

            createVisuals() {
                this.removeAll(true);

                // Create sprite for summoned enemy
                this.sprite = this.scene.add.sprite(0, 0, 'summoned', '0');
                this.sprite.setScale(1.75); // Double the enemy size
                this.add(this.sprite);

                // Play idle animation initially
                this.sprite.play('summoned-idle');

                // Add small glow to indicate it was summoned
                const summonGlow = this.scene.add.circle(0, 0, 20, 0xffff44, 0.2);
                this.add(summonGlow);
                this.sendToBack(summonGlow);

                // Fade out the glow over time
                this.scene.tweens.add({
                    targets: summonGlow,
                    alpha: 0,
                    duration: 1000,
                    onComplete: () => {
                        summonGlow.destroy();
                    }
                });
            }

            onMove(deltaTime) {
                // Same movement as basic enemy
                const movement = this.movementSpeed * deltaTime * 0.02;
                this.y += movement;

                // Play walking animation if moving
                if (this.sprite && (!this.sprite.anims.isPlaying || this.sprite.anims.currentAnim.key !== 'summoned-walk-down')) {
                    this.sprite.play('summoned-walk-down');
                }

                // Check if enemy has reached the bottom boundary
                const bottomBoundary = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                if (this.y > bottomBoundary) {
                    // Stop at boundary for now
                    this.y = bottomBoundary;
                }
            }
        }

        // Armored Enemy - Gray triangle with red triangle on top (2 health)
        class ArmoredEnemy extends Enemy {
            constructor(scene, x, y) {
                super(scene, x, y);
            }

            getMaxHealth() { return 2; }
            getHitRadius() { return 18; }
            getMovementSpeed() { return 0.8; }

            createVisuals() {
                this.removeAll(true);

                // Create sprite for armored enemy
                this.sprite = this.scene.add.sprite(0, 0, 'armored', '0');
                this.sprite.setScale(1.75); // Double the enemy size
                this.add(this.sprite);

                // Play idle animation initially
                this.sprite.play('armored-idle');

                // Add visual indicator for armor health
                if (this.health === 2) {
                    // Full armor - add shield image on right side, 30px below character bottom
                    const shield = this.scene.add.image(8, 15, 'shield');
                    shield.setScale(0.75); // Adjust size as needed
                    this.add(shield);
                }
            }

            onDamageTaken(damage) {
                // Recreate visuals when armor is lost
                this.createVisuals();
            }

            onMove(deltaTime) {
                // Slower movement due to armor
                const movement = this.movementSpeed * deltaTime * 0.02;
                this.y += movement;

                // Play walking animation if moving
                if (this.sprite && !this.sprite.anims.isPlaying || this.sprite.anims.currentAnim.key !== 'armored-walk-down') {
                    this.sprite.play('armored-walk-down');
                }

                // Check if enemy has reached the bottom boundary
                const bottomBoundary = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                if (this.y > bottomBoundary) {
                    // Stop at boundary for now
                    this.y = bottomBoundary;
                }
            }
        }

        // Summoner Enemy - Purple circle that spawns other enemies
        class SummonerEnemy extends Enemy {
            constructor(scene, x, y) {
                super(scene, x, y);
                this.summonCooldown = 0;
                this.maxSummonCooldown = 5000; // Will be randomized on reset
                this.summoning = false;
                this.summonPauseTimer = 0;
                this.summonPhase = 'none'; // 'pre', 'summoning', 'post', 'none'
                this.glowEffect = null;
                this.currentGridRow = 0;
                this.currentGridCol = 0;
                this.summonsUsed = 0;
                this.maxSummons = 1;
            }

            getMaxHealth() { return 1; }
            getHitRadius() { return 20; }
            getMovementSpeed() { return 0.5; }

            createVisuals() {
                this.removeAll(true);

                // Create sprite for summoner enemy
                this.sprite = this.scene.add.sprite(0, 0, 'summoner', '0');
                this.sprite.setScale(1.75); // Double the enemy size
                this.add(this.sprite);

                // Play idle animation initially
                this.sprite.play('summoner-idle');

                // Central glowing orb that gently pulses
                this.centralOrb = this.scene.add.circle(-12, 15, 7, 0xffff44, 0.7);
                this.centralOrb.setStrokeStyle(2, 0xffff00, 0.9);
                this.add(this.centralOrb);

                // Gentle pulsing animation for the central orb
                this.scene.tweens.add({
                    targets: this.centralOrb,
                    scaleX: 1.2,
                    scaleY: 1.2,
                    alpha: 0.9,
                    duration: 1000,
                    yoyo: true,
                    repeat: -1,
                    ease: 'Sine.easeInOut'
                });

                // Add summoning sphere effect if summoning
                if (this.summonPhase === 'summoning') {
                    this.summoningSphere = this.scene.add.circle(0, 0, 5, 0xffffff, 0.8);
                    this.summoningSphere.setStrokeStyle(3, 0xffff00, 1.0);
                    this.add(this.summoningSphere);

                    // Expanding sphere of light animation
                    this.scene.tweens.add({
                        targets: this.summoningSphere,
                        scaleX: 10,
                        scaleY: 10,
                        alpha: 0,
                        duration: 800,
                        ease: 'Power2.easeOut',
                        onComplete: () => {
                            if (this.summoningSphere) {
                                this.summoningSphere.destroy();
                                this.centralOrb.destroy();
                                this.summoningSphere = null;
                                this.centralOrb = null;
                            }
                        }
                    });
                }
            }

            onMove(deltaTime) {
                // Handle summoning phases
                if (this.summonPhase !== 'none') {
                    this.summonPauseTimer -= deltaTime;

                    // Play idle animation when paused for summoning
                    if (this.sprite && (!this.sprite.anims.isPlaying || this.sprite.anims.currentAnim.key !== 'summoner-idle')) {
                        this.sprite.play('summoner-idle');
                    }

                    if (this.summonPhase === 'pre' && this.summonPauseTimer <= 0) {
                        // Start summoning phase
                        this.summonPhase = 'summoning';
                        this.createVisuals(); // Add glow effect
                        this.performSummon();
                        this.summonPauseTimer = 500; // 0.5 second post-summon pause
                    } else if (this.summonPhase === 'summoning' && this.summonPauseTimer <= 0) {
                        // End summoning phase
                        this.summonPhase = 'none';
                        this.createVisuals(); // Remove glow effect
                        this.summonCooldown = this.maxSummonCooldown;
                    }

                    // Don't move while summoning
                    return;
                }

                // Normal movement + summoning logic
                const movement = this.movementSpeed * deltaTime * 0.02;
                this.y += movement;

                // Play walking animation when moving
                if (this.sprite && (!this.sprite.anims.isPlaying || this.sprite.anims.currentAnim.key !== 'summoner-walk-down')) {
                    this.sprite.play('summoner-walk-down');
                }

                // Check if enemy has reached the bottom boundary
                const bottomBoundary = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                if (this.y > bottomBoundary) {
                    // Stop at boundary for now
                    this.y = bottomBoundary;
                }

                // Update current grid position for summoning
                this.updateGridPosition();

                this.summonCooldown -= deltaTime;
                if (this.summonCooldown <= 0) {
                    this.startSummon();
                }
            }

            updateGridPosition() {
                // Use the scene's getTile helper function for consistency
                const tileInfo = this.scene.getTile(this.x, this.y);
                this.currentGridCol = tileInfo.col;
                this.currentGridRow = tileInfo.row;
            }

            isOnTileCenter() {
                // Check if the summoner is close enough to the center of a tile
                const gridPos = this.scene.grid[this.currentGridRow][this.currentGridCol];
                const distanceToCenter = Phaser.Math.Distance.Between(
                    this.x, this.y,
                    gridPos.centerX, gridPos.centerY
                );

                // Allow a tolerance of 5 pixels from perfect center
                return distanceToCenter <= 5;
            }

            startSummon() {
                // Check summon limit
                if (this.summonsUsed >= this.maxSummons) {
                    console.log(`Summoner has used all ${this.maxSummons} summons - no more summoning`);
                    this.summonCooldown = Number.MAX_SAFE_INTEGER; // No more summoning
                    return;
                }

                // Only summon in first 4 rows
                if (this.currentGridRow >= 4) {
                    this.summonCooldown = this.maxSummonCooldown;
                    return;
                }

                // Only summon when centered on a tile
                if (!this.isOnTileCenter()) {
                    console.log(`Summoner not centered on tile - delaying summon`);
                    this.summonCooldown = 500; // Check again in 0.5 seconds
                    return;
                }

                const summonChance = Math.random();
                console.log(`Summon chance: ${summonChance}`);
                console.log(`Current grid row: ${this.currentGridRow}`);
                if (this.currentGridRow < 3 && summonChance > 0.25) {
                    console.log(`dont summon`);
                    this.summonCooldown = this.maxSummonCooldown;
                    return;
                }

                console.log(`Summoner at (${this.currentGridCol}, ${this.currentGridRow}) starting summon sequence! (${this.summonsUsed + 1}/${this.maxSummons})`);
                this.summonPhase = 'pre';
                this.summonPauseTimer = 500; // 0.5 second pre-summon pause
            }

            performSummon() {
                // Increment summons used counter
                this.summonsUsed++;

                // Spawn BasicEnemies in adjacent tiles (up, down, left, right)
                const spawnOffsets = [
                    { col: 0, row: -1 }, // up
                    { col: 0, row: 1 },  // down
                    { col: -1, row: 0 }, // left
                    { col: 1, row: 0 }   // right
                ];

                let spawnedCount = 0;
                spawnOffsets.forEach((offset, index) => {
                    const targetCol = this.currentGridCol + offset.col;
                    const targetRow = this.currentGridRow + offset.row;
                    const direction = ['up', 'down', 'left', 'right'][index];

                    console.log(`Attempting to spawn ${direction} at (${targetCol}, ${targetRow}) from summoner at (${this.currentGridCol}, ${this.currentGridRow})`);

                    // Check bounds
                    if (targetCol >= 0 && targetCol < this.scene.GRID_COLS &&
                        targetRow >= 0 && targetRow < this.scene.GRID_ROWS) {

                        const gridPos = this.scene.grid[targetRow][targetCol];
                        //if (!gridPos.occupied) {
                        // Spawn a summoned enemy with fade-in and pause
                        const newEnemy = this.scene.getEnemyFromPool('summoned');
                        if (newEnemy) {
                            newEnemy.setPosition(gridPos.centerX, gridPos.centerY);
                            newEnemy.setAlpha(0); // Start invisible
                            newEnemy.isPaused = true;
                            newEnemy.pauseTimer = 500; // 0.5 second pause
                            gridPos.occupied = true;
                            spawnedCount++;

                            // Fade in animation
                            this.scene.tweens.add({
                                targets: newEnemy,
                                alpha: 1,
                                duration: 300,
                                ease: 'Power2.easeOut'
                            });

                            console.log(`✅ Spawned SummonedEnemy ${direction} at (${targetCol}, ${targetRow})`);
                        } else {
                            console.log(`❌ Failed to get enemy from pool for spawn at (${targetCol}, ${targetRow})`);
                        }
                        /*} else {
                            console.log(`❌ Cannot spawn ${direction} at (${targetCol}, ${targetRow}) - tile occupied`);
                        }*/
                    } else {
                        console.log(`❌ Cannot spawn ${direction} at (${targetCol}, ${targetRow}) - out of bounds`);
                    }
                });

                console.log(`Summoner completed summon ${this.summonsUsed}/${this.maxSummons} - spawned ${spawnedCount} enemies`);
            }

            reset() {
                super.reset();

                // Reset summon counter
                this.summonsUsed = 0;

                // Randomize summon cooldown based on current row (first 4 tiles)
                this.updateGridPosition();
                const baseTime = 3000; // 3 seconds base
                const rowMultiplier = Math.max(1, this.currentGridRow + 1); // Row 0 = 1x, Row 1 = 2x, etc.
                const randomFactor = 0.5 + Math.random(); // 0.5x to 1.5x
                this.maxSummonCooldown = baseTime * rowMultiplier * randomFactor;
                this.summonCooldown = this.maxSummonCooldown;

                this.summonPhase = 'none';
                this.summonPauseTimer = 0;

                console.log(`Summoner cooldown set to ${Math.round(this.maxSummonCooldown)}ms for row ${this.currentGridRow} (0/${this.maxSummons} summons used)`);
            }
        }

        // Base Attack Class - Handles drag and drop behavior
        class Attack extends Phaser.GameObjects.Container {
            constructor(scene, x, y, attackType) {
                super(scene, x, y);
                this.scene = scene;
                this.attackType = attackType;
                this.isDragging = false;
                this.originalX = x;
                this.originalY = y;
                this.targetColumn = -1;
                this.hitPositions = []; // Track positions where this attack has already caused damage

                this.createVisuals();
                this.setupInteractivity();
                this.setDepth(LAYERS.GUI);
                scene.add.existing(this);
            }

            // Abstract methods - to be overridden by subclasses
            createVisuals() { }
            getAttackName() { return 'Unknown'; }
            executeAttack(column) { }

            setupInteractivity() {
                this.setSize(60, 60);
                this.setInteractive({ draggable: true });

                this.on('dragstart', (pointer) => {
                    this.isDragging = true;
                    this.setDepth(LAYERS.GUI + 10);
                    console.log(`Started dragging ${this.getAttackName()}`);
                });

                this.on('drag', (pointer, dragX, dragY) => {
                    this.setPosition(dragX, dragY);
                    this.checkColumnHighlight(dragX, dragY);
                });

                this.on('dragend', (pointer) => {
                    this.isDragging = false;
                    this.setDepth(LAYERS.GUI);

                    if (this.targetColumn >= 0) {
                        console.log(`Dropping ${this.getAttackName()} on column ${this.targetColumn}`);

                        // Jeff plays attack animation
                        if (this.scene.jeff) {
                            this.scene.jeff.playAttackAnimation();
                        }

                        this.executeAttack(this.targetColumn);
                        this.resetPosition();
                    } else {
                        console.log(`${this.getAttackName()} not dropped on valid column`);
                        this.resetPosition();
                    }

                    this.scene.clearColumnHighlight();
                    this.targetColumn = -1;
                });
            }

            checkColumnHighlight(x, y) {
                // Check if dragging over the grid area
                if (y >= this.scene.GRID_START_Y && y <= this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE)) {
                    if (x >= this.scene.GRID_START_X && x <= this.scene.GRID_START_X + (this.scene.GRID_COLS * this.scene.TILE_SIZE)) {
                        // Calculate which column we're over
                        const column = Math.floor((x - this.scene.GRID_START_X) / this.scene.TILE_SIZE);
                        if (column >= 0 && column < this.scene.GRID_COLS) {
                            if (this.targetColumn !== column) {
                                this.targetColumn = column;
                                this.scene.highlightColumn(column);
                            }
                            return;
                        }
                    }
                }

                // Not over valid grid area
                if (this.targetColumn >= 0) {
                    this.scene.clearColumnHighlight();
                    this.targetColumn = -1;
                }
            }

            resetPosition() {
                this.setPosition(this.originalX, this.originalY);
            }
        }

        // Bullet Attack - Flows down column destroying all enemies
        class BulletAttack extends Attack {
            constructor(scene, x, y) {
                super(scene, x, y, 'bullet');
            }

            getAttackName() { return 'Bullet'; }

            createVisuals() {
                this.removeAll(true);

                // Background circle
                const bg = this.scene.add.circle(0, 0, 25, 0x444444);
                bg.setStrokeStyle(3, 0x000000);
                this.add(bg);

                // Bullet visual - vertical line with arrow
                const line = this.scene.add.rectangle(0, 0, 4, 30, 0x00ff00);
                this.add(line);

                const arrowHead = this.scene.add.polygon(0, -18, [0, -8, -6, 4, 6, 4], 0x00ff00);
                this.add(arrowHead);
            }

            executeAttack(column) {
                console.log(`Executing bullet attack on column ${column}`);

                // Get bullet from pool
                const bullet = this.scene.getProjectileFromPool('bullet');
                const startX = this.scene.GRID_START_X + (column * this.scene.TILE_SIZE) + (this.scene.TILE_SIZE / 2);
                const startY = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                bullet.setPosition(startX, startY);

                // Store bullet properties
                bullet.column = column;
                bullet.hitEnemies = []; // Reset hit enemies list
                bullet.hitPositions = []; // Reset hit positions list

                // Move bullet up the column
                const bulletTween = this.scene.tweens.add({
                    targets: bullet,
                    y: this.scene.GRID_START_Y - 50,
                    duration: 2000,
                    ease: 'Linear',
                    onComplete: () => {
                        this.scene.returnProjectileToPool(bullet);
                    }
                });

                bullet.moveTween = bulletTween;

                // Add to active projectiles list
                this.scene.activeProjectiles = this.scene.activeProjectiles || [];
                this.scene.activeProjectiles.push(bullet);

                console.log(`Created bullet projectile`);
            }
        }

        // Standard Attack - Bowling ball that bounces diagonally
        class StandardAttack extends Attack {
            constructor(scene, x, y) {
                super(scene, x, y, 'standard');
            }

            getAttackName() { return 'Standard'; }

            createVisuals() {
                this.removeAll(true);

                // Background circle
                const bg = this.scene.add.circle(0, 0, 25, 0x444444);
                bg.setStrokeStyle(3, 0x000000);
                this.add(bg);

                // Bowling ball visual
                const ball = this.scene.add.circle(0, 0, 15, 0x4444ff);
                ball.setStrokeStyle(2, 0x0000aa);
                this.add(ball);

                // Bounce arrows
                const arrow1 = this.scene.add.polygon(-8, -8, [0, -6, -4, 2, 4, 2], 0xffaa00);
                arrow1.setRotation(-Math.PI / 4);
                this.add(arrow1);

                const arrow2 = this.scene.add.polygon(8, -8, [0, -6, -4, 2, 4, 2], 0xffaa00);
                arrow2.setRotation(Math.PI / 4);
                this.add(arrow2);
            }

            executeAttack(column) {
                console.log(`Executing standard bowling attack on column ${column}`);

                // Get bowling ball from pool
                const ball = this.scene.getProjectileFromPool('bowling');
                const startX = this.scene.GRID_START_X + (column * this.scene.TILE_SIZE) + (this.scene.TILE_SIZE / 2);
                const startY = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                ball.setPosition(startX, startY);

                // Reset ball properties
                ball.direction = 0; // Start straight up
                ball.damage = 1;
                ball.hitEnemies = []; // Reset hit enemies list
                ball.hitPositions = []; // Reset hit positions list

                // Add to active projectiles list
                this.scene.activeProjectiles = this.scene.activeProjectiles || [];
                this.scene.activeProjectiles.push(ball);

                // Start movement
                this.scene.moveBowlingBall(ball, column);
            }
        }

        // Bomb Attack - Explodes on contact with radius damage
        class BombAttack extends Attack {
            constructor(scene, x, y) {
                super(scene, x, y, 'bomb');
            }

            getAttackName() { return 'Bomb'; }

            createVisuals() {
                this.removeAll(true);

                // Background circle
                const bg = this.scene.add.circle(0, 0, 25, 0x444444);
                bg.setStrokeStyle(3, 0x000000);
                this.add(bg);

                // Bomb visual
                const bomb = this.scene.add.circle(0, 2, 12, 0xff4444);
                bomb.setStrokeStyle(2, 0xaa0000);
                this.add(bomb);

                // Fuse
                const fuse = this.scene.add.rectangle(-2, -8, 2, 8, 0x8B4513);
                this.add(fuse);

                // Spark
                const spark = this.scene.add.circle(-2, -12, 2, 0xffff00);
                this.add(spark);

                // Explosion radius indicator
                const radiusCircle = this.scene.add.circle(0, 0, 20, 0xff4444, 0.2);
                radiusCircle.setStrokeStyle(1, 0xff4444, 0.5);
                this.add(radiusCircle);
            }

            executeAttack(column) {
                console.log(`Executing bomb attack on column ${column}`);

                // Get bomb from pool
                const bomb = this.scene.getProjectileFromPool('bomb');
                const startX = this.scene.GRID_START_X + (column * this.scene.TILE_SIZE) + (this.scene.TILE_SIZE / 2);
                const startY = this.scene.GRID_START_Y + (this.scene.GRID_ROWS * this.scene.TILE_SIZE);
                bomb.setPosition(startX, startY);

                // Reset bomb properties
                bomb.hasExploded = false;

                // Move bomb up the column
                const bombTween = this.scene.tweens.add({
                    targets: bomb,
                    y: this.scene.GRID_START_Y - 50,
                    duration: 2500,
                    ease: 'Linear',
                    onComplete: () => {
                        if (bomb.active && !bomb.hasExploded) {
                            this.scene.returnProjectileToPool(bomb);
                        }
                    }
                });

                // Store tween reference for stopping on collision
                bomb.moveTween = bombTween;

                // Add to active projectiles list
                this.scene.activeProjectiles = this.scene.activeProjectiles || [];
                this.scene.activeProjectiles.push(bomb);
            }
        }

        // Jeff - The player character
        class Jeff extends Phaser.GameObjects.Container {
            constructor(scene, x, y) {
                super(scene, x, y);
                this.scene = scene;

                // Create sprite facing upward
                this.sprite = this.scene.add.sprite(0, 0, 'jeff', '8'); // Frame 8 for upward facing
                this.sprite.setScale(1.75); // Same scale as enemies
                this.add(this.sprite);

                // Start with idle animation
                this.sprite.play('jeff-idle');

                this.setDepth(LAYERS.ENEMIES + 1); // Above enemies
                scene.add.existing(this);

                this.targetColumn = 2; // Start in center column (0-indexed)
            }

            // Teleport to target column position
            moveToColumn(column) {
                if (column === this.targetColumn) return;

                this.targetColumn = column;
                const targetX = this.scene.GRID_START_X + (column * this.scene.TILE_SIZE) + (this.scene.TILE_SIZE / 2);

                // Instant teleport
                this.setX(targetX);
            }

            // Play attack animation
            playAttackAnimation() {
                this.sprite.play('jeff-attack');

                // Return to idle after a brief moment
                this.scene.time.delayedCall(200, () => {
                    this.sprite.play('jeff-idle');
                });
            }
        }

        class Game extends Phaser.Scene {
            constructor() {
                super({ key: "Game" });
                this.GRID_COLS = 5;
                this.GRID_ROWS = 8;
                this.GRID_START_X = 68;
                this.GRID_START_Y = 50;
                this.TILE_SIZE = 72;//(window.game.config.width - (this.GRID_START_X * 2)) / this.GRID_COLS;
            }

            createEnemyAnimations() {
                // Create animations for each enemy type
                const enemyTypes = ['basic', 'armored', 'summoner', 'summoned'];

                enemyTypes.forEach(type => {
                    // Idle animation (standing still, facing forward) - frame 0
                    this.anims.create({
                        key: `${type}-idle`,
                        frames: this.anims.generateFrameNames(type, {
                            start: 0,
                            end: 0
                        }),
                        frameRate: 1,
                        repeat: 0
                    });

                    // Walking down animation - frames 0-3 (first row of sprite sheet)
                    this.anims.create({
                        key: `${type}-walk-down`,
                        frames: this.anims.generateFrameNames(type, {
                            start: 0,
                            end: 3
                        }),
                        frameRate: 8,
                        repeat: -1
                    });
                });

                // Create Jeff animations (upward-facing)
                // Jeff idle (facing up) - frame 8 (up direction)
                this.anims.create({
                    key: 'jeff-idle',
                    frames: this.anims.generateFrameNames('jeff', {
                        start: 8,
                        end: 8
                    }),
                    frameRate: 1,
                    repeat: 0
                });

                // Jeff attack animation (walking up first frame) - frame 9
                this.anims.create({
                    key: 'jeff-attack',
                    frames: this.anims.generateFrameNames('jeff', {
                        start: 9,
                        end: 9
                    }),
                    frameRate: 1,
                    repeat: 0
                });

                console.log('Enemy and Jeff animations created');
            }

            create() {
                this.gameStarted = false;

                // Create background image
                const background = this.add.image(0, 0, 'background');
                background.setOrigin(0, 0);
                background.setDepth(LAYERS.BACKGROUND);
                background.setDisplaySize(500, 1600);

                // Create enemy animations
                this.createEnemyAnimations();

                this.initializePhysicsWorld();
                this.createEnemyPools();
                this.createProjectilePools();
                this.createGrid();
                this.createJeff();
                this.createFPSCounter();
                this.createAttacks();
                this.createFallingCardSystem();
                this.setupInput();

                // Debug timer for periodic enemy position output
                this.debugTimer = 0;

                // Initialize wave system instead of test enemies
                this.initializeWaveSystem();

                // Auto-start game after a delay if home screen was already dismissed
                this.time.delayedCall(3000, () => {
                    if (!this.gameStarted) {
                        console.log('[GAME STATE] Auto-starting game after 3 second delay');
                        this.startGame();
                    }
                });
            }

            initializePhysicsWorld() {
                // Initialize projectiles array
                this.activeProjectiles = [];
            }

            createEnemyPools() {
                this.enemyPools = {
                    basic: [],
                    armored: [],
                    summoner: [],
                    summoned: []
                };

                this.activeEnemies = [];

                // Pre-create enemies for pooling - increased pool size
                const poolSize = 20;

                // Create BasicEnemy pool
                for (let i = 0; i < poolSize; i++) {
                    const enemy = new BasicEnemy(this, 0, 0);
                    enemy.setVisible(false);
                    enemy.setActive(false);
                    this.enemyPools.basic.push(enemy);
                }

                // Create ArmoredEnemy pool
                for (let i = 0; i < poolSize; i++) {
                    const enemy = new ArmoredEnemy(this, 0, 0);
                    enemy.setVisible(false);
                    enemy.setActive(false);
                    this.enemyPools.armored.push(enemy);
                }

                // Create SummonerEnemy pool
                for (let i = 0; i < poolSize; i++) {
                    const enemy = new SummonerEnemy(this, 0, 0);
                    enemy.setVisible(false);
                    enemy.setActive(false);
                    this.enemyPools.summoner.push(enemy);
                }

                // Create SummonedEnemy pool
                for (let i = 0; i < poolSize * 2; i++) { // Larger pool since summoners create many
                    const enemy = new SummonedEnemy(this, 0, 0);
                    enemy.setVisible(false);
                    enemy.setActive(false);
                    this.enemyPools.summoned.push(enemy);
                }
            }

            createProjectilePools() {
                this.projectilePools = {
                    bullet: [],
                    bowling: [],
                    bomb: []
                };

                // Pre-create projectiles for pooling
                const poolSize = 20;

                // Create bullet pool
                for (let i = 0; i < poolSize; i++) {
                    const bullet = this.createBulletProjectile(0, 0);
                    bullet.setVisible(false);
                    bullet.setActive(false);
                    this.projectilePools.bullet.push(bullet);
                }

                // Create bowling ball pool
                for (let i = 0; i < poolSize; i++) {
                    const ball = this.createBowlingProjectile(0, 0);
                    ball.setVisible(false);
                    ball.setActive(false);
                    this.projectilePools.bowling.push(ball);
                }

                // Create bomb pool
                for (let i = 0; i < poolSize; i++) {
                    const bomb = this.createBombProjectile(0, 0);
                    bomb.setVisible(false);
                    bomb.setActive(false);
                    this.projectilePools.bomb.push(bomb);
                }
            }

            createBulletProjectile(x, y) {
                const bullet = this.add.container(x, y);
                bullet.setDepth(LAYERS.PROJECTILES);

                // Bullet visual
                const line = this.add.rectangle(0, 0, 3, 20, 0x00ff00);
                const arrow = this.add.polygon(0, -12, [0, -6, -4, 2, 4, 2], 0x00ff00);
                bullet.add([line, arrow]);

                // Store bullet properties
                bullet.attackType = 'bullet';
                bullet.damage = 999;
                bullet.hitEnemies = []; // Track which enemies this bullet has already hit
                bullet.hitPositions = []; // Track tile positions where damage has been dealt

                return bullet;
            }

            createBowlingProjectile(x, y) {
                const ball = this.add.container(x, y);
                ball.setDepth(LAYERS.PROJECTILES);

                // Ball visual
                const ballCircle = this.add.circle(0, 0, 12, 0x4444ff);
                ballCircle.setStrokeStyle(2, 0x0000aa);
                ball.add(ballCircle);

                // Store ball properties
                ball.attackType = 'bowling';
                ball.direction = 0; // 0 = straight down, -45 = left diagonal, 45 = right diagonal
                ball.damage = 1;
                ball.hitEnemies = []; // Track which enemies this ball has already hit
                ball.hitPositions = []; // Track tile positions where damage has been dealt

                return ball;
            }

            createBombProjectile(x, y) {
                const bomb = this.add.container(x, y);
                bomb.setDepth(LAYERS.PROJECTILES);

                // Bomb visual
                const bombCircle = this.add.circle(0, 2, 10, 0xff4444);
                bombCircle.setStrokeStyle(2, 0xaa0000);
                const fuse = this.add.rectangle(-2, -6, 2, 6, 0x8B4513);
                const spark = this.add.circle(-2, -9, 2, 0xffff00);
                bomb.add([bombCircle, fuse, spark]);

                // Store bomb properties
                bomb.attackType = 'bomb';
                bomb.hasExploded = false;

                return bomb;
            }

            getProjectileFromPool(type) {
                const pool = this.projectilePools[type];
                if (pool.length > 0) {
                    const projectile = pool.pop();
                    projectile.setVisible(true);
                    projectile.setActive(true);
                    return projectile;
                }

                // Create new projectile if pool is empty
                switch (type) {
                    case 'bullet': return this.createBulletProjectile(0, 0);
                    case 'bowling': return this.createBowlingProjectile(0, 0);
                    case 'bomb': return this.createBombProjectile(0, 0);
                    default: return this.createBulletProjectile(0, 0);
                }
            }

            returnProjectileToPool(projectile) {
                projectile.setVisible(false);
                projectile.setActive(false);
                projectile.setPosition(0, 0);

                // Reset projectile properties
                if (projectile.attackType === 'bowling') {
                    projectile.direction = 0;
                    projectile.hitEnemies = []; // Reset hit enemies list
                    projectile.hitPositions = []; // Reset hit positions list
                } else if (projectile.attackType === 'bullet') {
                    projectile.hitEnemies = []; // Reset hit enemies list
                    projectile.hitPositions = []; // Reset hit positions list
                } else if (projectile.attackType === 'bomb') {
                    projectile.hasExploded = false;
                }

                // Remove from active projectiles
                const index = this.activeProjectiles.indexOf(projectile);
                if (index > -1) {
                    this.activeProjectiles.splice(index, 1);
                }

                // Return to appropriate pool
                this.projectilePools[projectile.attackType].push(projectile);
            }

            getEnemyFromPool(type) {
                const pool = this.enemyPools[type];

                // Find an available enemy in the pool
                let availableEnemy = null;
                for (let i = 0; i < pool.length; i++) {
                    const enemy = pool[i];
                    if (!enemy.active && !enemy.visible) {
                        availableEnemy = enemy;
                        // Remove from pool
                        pool.splice(i, 1);
                        break;
                    }
                }

                // If no available enemy found, create a new one
                if (!availableEnemy) {
                    console.log(`[POOL] No available ${type} enemy in pool, creating new one`);
                    switch (type) {
                        case 'basic': availableEnemy = new BasicEnemy(this, 0, 0); break;
                        case 'armored': availableEnemy = new ArmoredEnemy(this, 0, 0); break;
                        case 'summoner': availableEnemy = new SummonerEnemy(this, 0, 0); break;
                        default: availableEnemy = new BasicEnemy(this, 0, 0); break;
                    }
                }

                // Reset and activate the enemy
                availableEnemy.reset();
                availableEnemy.setVisible(true);
                availableEnemy.setActive(true);
                this.activeEnemies.push(availableEnemy);
                return availableEnemy;
            }

            returnEnemyToPool(enemy) {
                // Make sure enemy is properly reset
                enemy.setVisible(false);
                enemy.setActive(false);
                enemy.setPosition(-1000, -1000); // Move far off screen
                enemy.setAlpha(1); // Reset alpha

                // Clear any ongoing tweens on this enemy
                this.tweens.killTweensOf(enemy);

                // Remove from active enemies
                const index = this.activeEnemies.indexOf(enemy);
                if (index > -1) {
                    this.activeEnemies.splice(index, 1);
                }

                // Decrement wave enemy counter
                if (this.enemiesAliveInWave > 0) {
                    this.enemiesAliveInWave--;
                    console.log(`[WAVE] Enemy defeated. Enemies remaining in wave: ${this.enemiesAliveInWave}`);

                    // Check if wave is complete
                    if (this.enemiesAliveInWave <= 0 && this.enemiesSpawnedInWave > 0) {
                        console.log(`[WAVE] All enemies defeated! Completing wave...`);
                        this.onWaveComplete();
                    }
                } else {
                    console.log(`[WAVE WARNING] Enemy died but enemiesAliveInWave was already ${this.enemiesAliveInWave}`);
                }

                // Return to appropriate pool - check SummonedEnemy before BasicEnemy since it extends it
                if (enemy instanceof SummonedEnemy) {
                    this.enemyPools.summoned.push(enemy);
                } else if (enemy instanceof BasicEnemy) {
                    this.enemyPools.basic.push(enemy);
                } else if (enemy instanceof ArmoredEnemy) {
                    this.enemyPools.armored.push(enemy);
                } else if (enemy instanceof SummonerEnemy) {
                    this.enemyPools.summoner.push(enemy);
                }
            }

            createJeff() {
                // Position Jeff 40px below the bottom of the lanes, in the center column (col 2)
                const jeffX = this.GRID_START_X + (2 * this.TILE_SIZE) + (this.TILE_SIZE / 2); // Center column
                const jeffY = this.GRID_START_Y + (this.GRID_ROWS * this.TILE_SIZE) + 40; // 40px below lanes

                this.jeff = new Jeff(this, jeffX, jeffY);
                console.log(`Jeff created at position (${jeffX}, ${jeffY})`);
            }

            createGrid() {
                this.grid = [];
                this.gridGraphics = this.add.graphics();
                this.columnHighlight = null; // For column highlighting during drag

                for (let row = 0; row < this.GRID_ROWS; row++) {
                    this.grid[row] = [];
                    for (let col = 0; col < this.GRID_COLS; col++) {
                        const x = this.GRID_START_X + col * this.TILE_SIZE;
                        const y = this.GRID_START_Y + row * this.TILE_SIZE;

                        // Varying shades of green for grass tiles
                        const greenShades = [0x4CAF50, 0x66BB6A, 0x43A047, 0x388E3C, 0x2E7D32];
                        const grassColor = greenShades[Phaser.Math.Between(0, greenShades.length - 1)];

                        const tile = this.add.rectangle(x + this.TILE_SIZE / 2, y + this.TILE_SIZE / 2,
                            this.TILE_SIZE, this.TILE_SIZE, grassColor);
                        tile.setDepth(LAYERS.TILES);

                        tile.setAlpha(0);

                        this.grid[row][col] = {
                            tile: tile,
                            x: x,
                            y: y,
                            centerX: x + this.TILE_SIZE / 2,
                            centerY: y + this.TILE_SIZE / 2,
                            occupied: false
                        };
                    }
                }

                // Create walls on left and right sides
                this.createWalls();
            }

            createWalls() {
                // Wall width and positions
                const wallWidth = 10;
                const wallHeight = this.GRID_ROWS * this.TILE_SIZE;
                const wallY = this.GRID_START_Y + wallHeight / 2;

                // Left wall
                this.leftWall = this.add.rectangle(
                    this.GRID_START_X - wallWidth / 2,
                    wallY,
                    wallWidth,
                    wallHeight,
                    0xFF0000
                );
                this.leftWall.setDepth(LAYERS.GRAPHICS + 2);

                // Right wall
                this.rightWall = this.add.rectangle(
                    this.GRID_START_X + (this.GRID_COLS * this.TILE_SIZE) + wallWidth / 2,
                    wallY,
                    wallWidth,
                    wallHeight,
                    0xFF0000
                );
                this.rightWall.setDepth(LAYERS.GRAPHICS + 2);

                this.leftWall.setAlpha(0);
                this.rightWall.setAlpha(0);

                console.log('Created left and right walls with red visualization');
            }

            createFPSCounter() {
                this.fpsText = this.add.text(10, 10, 'FPS: 0', {
                    fontSize: '16px',
                    fontFamily: 'Arial',
                    color: '#ffffff',
                    backgroundColor: 'rgba(0,0,0,0.5)',
                    padding: { x: 8, y: 4 }
                });
                this.fpsText.setDepth(LAYERS.GUI);
            }

            // Helper function to convert world coordinates to tile coordinates
            getTile(x, y) {
                const col = Math.floor((x - this.GRID_START_X) / this.TILE_SIZE);
                const row = Math.floor((y - this.GRID_START_Y) / this.TILE_SIZE);

                // Clamp to valid grid bounds
                const clampedCol = Math.max(0, Math.min(this.GRID_COLS - 1, col));
                const clampedRow = Math.max(0, Math.min(this.GRID_ROWS - 1, row));

                return {
                    col: clampedCol,
                    row: clampedRow,
                    // Also include raw unclamped values for debugging
                    rawCol: col,
                    rawRow: row
                };
            }

            spawnEnemyAtColumn(type, column, row = 0) {
                // Validate column is within bounds
                if (column < 0 || column >= this.GRID_COLS) {
                    console.warn(`Invalid column ${column}, must be between 0 and ${this.GRID_COLS - 1}`);
                    return null;
                }

                // Validate row is within bounds
                if (row < 0 || row >= this.GRID_ROWS) {
                    console.warn(`Invalid row ${row}, must be between 0 and ${this.GRID_ROWS - 1}`);
                    return null;
                }

                const enemy = this.getEnemyFromPool(type);
                const gridPos = this.grid[row][column];

                // Center enemy on the tile's x-axis, place at tile's center y
                enemy.setPosition(gridPos.centerX, gridPos.centerY);
                gridPos.occupied = true;

                return enemy;
            }

            createFallingCardSystem() {
                // Initialize falling card system
                this.fallingCards = [];
                this.cardSpawnTimer = 0;
                this.cardSpawnMinTime = 2000; // 5 seconds minimum
                this.cardSpawnMaxTime = 4000; // 10 seconds maximum
                this.nextCardSpawnTime = Phaser.Math.Between(this.cardSpawnMinTime, this.cardSpawnMaxTime);

                console.log('Falling card system initialized');
            }

            spawnFallingCard() {
                // Randomly select an attack type
                const attackTypes = ['bullet', 'standard', 'bomb'];
                const randomType = attackTypes[Phaser.Math.Between(0, attackTypes.length - 1)];

                // Random spawn position within visible area (10% to 50% of screen height)
                const spawnX = Phaser.Math.Between(this.GRID_START_X + 30, this.GRID_START_X + (this.GRID_COLS * this.TILE_SIZE) - 30);
                const minY = this.scale.height * 0.1; // 10% from top (e.g., 80px for 800px height)
                const maxY = this.scale.height * 0.5; // 50% from top (e.g., 400px for 800px height)
                const spawnY = Phaser.Math.Between(Math.floor(minY), Math.floor(maxY));

                console.log(`[CARD SPAWN] Creating ${randomType} card at position (${spawnX}, ${spawnY}) - Screen height: ${this.scale.height}, Range: ${Math.floor(minY)}-${Math.floor(maxY)}`);

                // Create card container
                const card = this.add.container(spawnX, spawnY);
                card.setDepth(LAYERS.CARDS);

                // Use scroll image as background (47x40px)
                const cardBg = this.add.image(0, 0, 'scroll');
                card.add(cardBg);

                // Add white background for icon visibility
                const iconBg = this.add.circle(0, 0, 15, 0xFFFFFF);
                card.add(iconBg);

                // Add attack icon based on type
                switch (randomType) {
                    case 'bullet':
                        // Bullet visual
                        const bulletLine = this.add.rectangle(0, 0, 3, 25, 0x00ff00);
                        const bulletArrow = this.add.polygon(0, -14, [0, -6, -5, 3, 5, 3], 0x00ff00);
                        card.add([bulletLine, bulletArrow]);
                        break;
                    case 'standard':
                        // Bowling ball visual
                        const ballCircle = this.add.circle(0, 0, 12, 0x4444ff);
                        ballCircle.setStrokeStyle(2, 0x0000aa);
                        card.add(ballCircle);
                        break;
                    case 'bomb':
                        // Bomb visual
                        const bombCircle = this.add.circle(0, 2, 10, 0xff4444);
                        bombCircle.setStrokeStyle(2, 0xaa0000);
                        const fuse = this.add.rectangle(-2, -6, 2, 6, 0x8B4513);
                        const spark = this.add.circle(-2, -9, 2, 0xffff00);
                        card.add([bombCircle, fuse, spark]);
                        break;
                }

                // Store card properties
                card.attackType = randomType;
                card.isDragging = false;
                card.fallSpeed = Phaser.Math.Between(50, 100); // pixels per second

                // Make card interactive for dragging (using scroll dimensions)
                card.setSize(47, 40);
                card.setInteractive({ draggable: true });

                // Setup drag handlers
                card.on('dragstart', (pointer) => {
                    card.isDragging = true;
                    card.setDepth(LAYERS.GUI + 10);
                    console.log(`Started dragging falling ${card.attackType} card`);
                });

                card.on('drag', (pointer, dragX, dragY) => {
                    card.setPosition(dragX, dragY);
                    this.checkCardColumnHighlight(dragX, dragY, card);
                });

                card.on('dragend', (pointer) => {
                    card.isDragging = false;

                    if (card.targetColumn >= 0) {
                        console.log(`Dropping ${card.attackType} card on column ${card.targetColumn}`);
                        this.executeCardAttack(card.attackType, card.targetColumn);

                        // Remove card from falling cards list
                        const index = this.fallingCards.indexOf(card);
                        if (index > -1) {
                            this.fallingCards.splice(index, 1);
                        }
                        card.destroy();
                    } else {
                        // Return to falling if not dropped on valid column
                        card.isDragging = false;
                        card.setDepth(LAYERS.CARDS);
                    }

                    this.clearColumnHighlight();
                    card.targetColumn = -1;
                });

                this.fallingCards.push(card);
                console.log(`[CARD SPAWN] Successfully spawned ${randomType} card. Total falling cards: ${this.fallingCards.length}`);
            }

            checkCardColumnHighlight(x, y, card) {
                // Check if dragging over the grid area
                if (y >= this.GRID_START_Y && y <= this.GRID_START_Y + (this.GRID_ROWS * this.TILE_SIZE)) {
                    if (x >= this.GRID_START_X && x <= this.GRID_START_X + (this.GRID_COLS * this.TILE_SIZE)) {
                        // Calculate which column we're over
                        const column = Math.floor((x - this.GRID_START_X) / this.TILE_SIZE);
                        if (column >= 0 && column < this.GRID_COLS) {
                            if (card.targetColumn !== column) {
                                card.targetColumn = column;
                                this.highlightColumn(column);
                            }
                            return;
                        }
                    }
                }

                // Not over valid grid area
                if (card.targetColumn >= 0) {
                    this.clearColumnHighlight();
                    card.targetColumn = -1;
                }
            }

            executeCardAttack(attackType, column) {
                // Jeff plays attack animation
                if (this.jeff) {
                    this.jeff.playAttackAnimation();
                }

                // Execute the attack based on type
                switch (attackType) {
                    case 'bullet':
                        this.executeBulletAttack(column);
                        break;
                    case 'standard':
                        this.executeStandardAttack(column);
                        break;
                    case 'bomb':
                        this.executeBombAttack(column);
                        break;
                }
            }

            executeBulletAttack(column) {
                console.log(`Executing bullet attack on column ${column}`);

                // Get bullet from pool
                const bullet = this.getProjectileFromPool('bullet');
                const startX = this.GRID_START_X + (column * this.TILE_SIZE) + (this.TILE_SIZE / 2);
                const startY = this.GRID_START_Y + (this.GRID_ROWS * this.TILE_SIZE);
                bullet.setPosition(startX, startY);

                // Store bullet properties
                bullet.column = column;
                bullet.hitEnemies = [];
                bullet.hitPositions = [];

                // Move bullet up the column
                const bulletTween = this.tweens.add({
                    targets: bullet,
                    y: this.GRID_START_Y - 50,
                    duration: 2000,
                    ease: 'Linear',
                    onComplete: () => {
                        this.returnProjectileToPool(bullet);
                    }
                });

                bullet.moveTween = bulletTween;
                this.activeProjectiles.push(bullet);
            }

            executeStandardAttack(column) {
                console.log(`Executing standard bowling attack on column ${column}`);

                // Get bowling ball from pool
                const ball = this.getProjectileFromPool('bowling');
                const startX = this.GRID_START_X + (column * this.TILE_SIZE) + (this.TILE_SIZE / 2);
                const startY = this.GRID_START_Y + (this.GRID_ROWS * this.TILE_SIZE);
                ball.setPosition(startX, startY);

                // Reset ball properties
                ball.direction = 0;
                ball.damage = 1;
                ball.hitEnemies = [];
                ball.hitPositions = [];

                this.activeProjectiles.push(ball);
                this.moveBowlingBall(ball, column);
            }

            executeBombAttack(column) {
                console.log(`Executing bomb attack on column ${column}`);

                // Get bomb from pool
                const bomb = this.getProjectileFromPool('bomb');
                const startX = this.GRID_START_X + (column * this.TILE_SIZE) + (this.TILE_SIZE / 2);
                const startY = this.GRID_START_Y + (this.GRID_ROWS * this.TILE_SIZE);
                bomb.setPosition(startX, startY);

                // Reset bomb properties
                bomb.hasExploded = false;

                // Move bomb up the column
                const bombTween = this.tweens.add({
                    targets: bomb,
                    y: this.GRID_START_Y - 50,
                    duration: 2500,
                    ease: 'Linear',
                    onComplete: () => {
                        if (bomb.active && !bomb.hasExploded) {
                            this.returnProjectileToPool(bomb);
                        }
                    }
                });

                bomb.moveTween = bombTween;
                this.activeProjectiles.push(bomb);
            }

            initializeWaveSystem() {
                // Wave configuration
                this.currentWave = 0;
                this.waveTimer = 0;
                this.enemiesSpawnedInWave = 0;
                this.enemiesAliveInWave = 0;
                this.waveActive = false;
                this.waveComplete = false;
                this.timeBetweenWaves = 1500; // 1.5 seconds between waves
                this.nextWaveTime = 500; // Start first wave after 0.5 seconds

                console.log(`[WAVE DEBUG] Wave system initialized. enemiesAliveInWave: ${this.enemiesAliveInWave}`);

                // Pre-seeded wave configurations with randomized columns
                this.waveConfigs = [
                    // Wave 1: Introduction (3 basic enemies)
                    {
                        enemies: [
                            { type: 'armored', delay: 0 },
                            { type: 'basic', delay: 1000 },
                            { type: 'summoner', delay: 2000 }
                        ],
                        message: 'Wave 1: Getting Started'
                    },
                    // Wave 2: Mixed basics (5 enemies)
                    {
                        enemies: [
                            { type: 'basic', delay: 0 },
                            { type: 'basic', delay: 500 },
                            { type: 'basic', delay: 1000 },
                            { type: 'basic', delay: 1500 },
                            { type: 'basic', delay: 2000 }
                        ],
                        message: 'Wave 2: Warming Up'
                    },
                    // Wave 3: Introduce armored (3 basic + 2 armored)
                    {
                        enemies: [
                            { type: 'armored', delay: 0 },
                            { type: 'basic', delay: 500 },
                            { type: 'basic', delay: 1000 },
                            { type: 'armored', delay: 1500 },
                            { type: 'basic', delay: 2000 }
                        ],
                        message: 'Wave 3: Armored Enemies!'
                    },
                    // Wave 4: Summoner introduction (1 summoner + basics)
                    {
                        enemies: [
                            { type: 'summoner', delay: 0 },
                            { type: 'basic', delay: 1000 },
                            { type: 'basic', delay: 1500 },
                            { type: 'basic', delay: 2500 }
                        ],
                        message: 'Wave 4: Summoners Arrive!'
                    },
                    // Wave 5: Mixed challenge (faster spawn)
                    {
                        enemies: [
                            { type: 'basic', delay: 0 },
                            { type: 'armored', delay: 300 },
                            { type: 'basic', delay: 600 },
                            { type: 'basic', delay: 900 },
                            { type: 'armored', delay: 1200 },
                            { type: 'basic', delay: 1500 }
                        ],
                        message: 'Wave 5: Speed Round!'
                    },
                    // Wave 6: Double summoners
                    {
                        enemies: [
                            { type: 'summoner', delay: 0 },
                            { type: 'summoner', delay: 500 },
                            { type: 'armored', delay: 1500 },
                            { type: 'armored', delay: 2000 }
                        ],
                        message: 'Wave 6: Double Trouble!'
                    },
                    // Wave 7: Chaos mode
                    {
                        enemies: [
                            { type: 'basic', delay: 0 },
                            { type: 'basic', delay: 200 },
                            { type: 'basic', delay: 400 },
                            { type: 'basic', delay: 600 },
                            { type: 'basic', delay: 800 },
                            { type: 'basic', delay: 1000 },
                            { type: 'armored', delay: 1500 },
                            { type: 'summoner', delay: 2000 }
                        ],
                        message: 'Wave 7: Full Assault!'
                    },
                    // Wave 8+: Generate increasingly difficult waves
                ];

                console.log('Wave system initialized');
            }

            startNextWave() {
                if (this.waveActive) return;

                this.waveActive = true;
                this.waveComplete = false;
                this.enemiesSpawnedInWave = 0;
                this.enemiesAliveInWave = 0;

                console.log(`[WAVE DEBUG] Starting wave with counters reset. Active: ${this.waveActive}, Complete: ${this.waveComplete}`);

                let waveConfig;
                if (this.currentWave < this.waveConfigs.length) {
                    waveConfig = this.waveConfigs[this.currentWave];
                } else {
                    // Generate random wave for waves beyond pre-configured ones
                    waveConfig = this.generateRandomWave(this.currentWave);
                }

                console.log(`[WAVE] Starting ${waveConfig.message} (Wave ${this.currentWave + 1}/${this.waveConfigs.length})`);

                // Show wave announcement
                this.showWaveAnnouncement(waveConfig.message);

                // Spawn enemies according to wave configuration
                waveConfig.enemies.forEach(enemyConfig => {
                    this.time.delayedCall(enemyConfig.delay, () => {
                        // Randomize column if not specified
                        const column = enemyConfig.column !== undefined ? enemyConfig.column : Phaser.Math.Between(0, this.GRID_COLS - 1);
                        const enemy = this.spawnEnemyAtColumn(enemyConfig.type, column, 0);
                        if (enemy) {
                            this.enemiesSpawnedInWave++;
                            this.enemiesAliveInWave++;
                            console.log(`[WAVE DEBUG] Spawned ${enemyConfig.type} enemy at column ${column}. Total spawned: ${this.enemiesSpawnedInWave}, Alive: ${this.enemiesAliveInWave}`);
                        }

                        // Check if all enemies have been spawned
                        if (this.enemiesSpawnedInWave >= waveConfig.enemies.length) {
                            console.log(`[WAVE] All enemies spawned for wave ${this.currentWave + 1}. Enemies alive: ${this.enemiesAliveInWave}`);
                        }
                    });
                });
            }

            onWaveComplete() {
                console.log(`[WAVE] Wave ${this.currentWave + 1} complete!`);
                this.waveActive = false;
                this.waveComplete = true;
                this.currentWave++;
                this.nextWaveTime = this.timeBetweenWaves;
            }

            showWaveAnnouncement(message) {
                // Create wave announcement text
                const centerX = this.scale.width / 2;
                const centerY = this.scale.height / 2;

                const waveText = this.add.text(centerX, centerY, message, {
                    fontSize: '36px',
                    fontFamily: 'Fredoka',
                    fontWeight: '600',
                    color: '#ffffff',
                    stroke: '#000000',
                    strokeThickness: 6,
                    align: 'center'
                });

                waveText.setOrigin(0.5, 0.5);
                waveText.setDepth(LAYERS.GUI + 20);
                waveText.setScale(0);
                waveText.setAlpha(0);

                // Animate in
                this.tweens.add({
                    targets: waveText,
                    scaleX: 1,
                    scaleY: 1,
                    alpha: 1,
                    duration: 500,
                    ease: 'Back.easeOut',
                    onComplete: () => {
                        // Hold for a moment then fade out
                        this.tweens.add({
                            targets: waveText,
                            alpha: 0,
                            scaleX: 1.2,
                            scaleY: 1.2,
                            duration: 1000,
                            delay: 1500,
                            ease: 'Power2.easeIn',
                            onComplete: () => {
                                waveText.destroy();
                            }
                        });
                    }
                });
            }

            generateRandomWave(waveNumber) {
                // Generate increasingly difficult waves
                const baseEnemyCount = 5 + Math.floor(waveNumber / 2);
                const enemyCount = Math.min(baseEnemyCount, 12); // Cap at 12 enemies

                const enemies = [];
                for (let i = 0; i < enemyCount; i++) {
                    // Increase chance of harder enemies as waves progress
                    const rand = Math.random();
                    let type = 'basic';
                    if (waveNumber > 10 && rand > 0.7) {
                        type = 'summoner';
                    } else if (waveNumber > 5 && rand > 0.5) {
                        type = 'armored';
                    }

                    enemies.push({
                        type: type,
                        column: Phaser.Math.Between(0, this.GRID_COLS - 1),
                        delay: i * Math.max(200, 1000 - (waveNumber * 50)) // Faster spawns in later waves
                    });
                }

                return {
                    enemies: enemies,
                    message: `Wave ${waveNumber + 1}: Endless Mode!`
                };
            }

            createAttacks() {
                // Create the three attack types at the bottom of the screen (hidden for now)
                const bottomY = this.scale.height - 50;
                const attackSpacing = 80;
                const startX = (this.scale.width - (attackSpacing * 2)) / 2; // Center the three attacks

                this.attacks = [
                    new BulletAttack(this, startX, bottomY),
                    new StandardAttack(this, startX + attackSpacing, bottomY),
                    new BombAttack(this, startX + (attackSpacing * 2), bottomY)
                ];

                // Hide the attacks initially
                this.attacks.forEach(attack => {
                    attack.setVisible(false);
                });

                console.log(`Created ${this.attacks.length} attack types at bottom of screen (hidden)`);
            }

            highlightColumn(column) {
                this.clearColumnHighlight();

                // Create column highlight
                this.columnHighlight = this.add.graphics();
                this.columnHighlight.setDepth(LAYERS.GRAPHICS + 1);

                const columnX = this.GRID_START_X + (column * this.TILE_SIZE);
                const columnWidth = this.TILE_SIZE;
                const columnHeight = this.GRID_ROWS * this.TILE_SIZE + 15; // Extended by 15px at bottom

                // Draw glowing column highlight
                this.columnHighlight.fillStyle(0xffff00, 0.3);
                this.columnHighlight.fillRect(columnX, this.GRID_START_Y, columnWidth, columnHeight);

                this.columnHighlight.lineStyle(3, 0xffff00, 0.8);
                this.columnHighlight.strokeRect(columnX, this.GRID_START_Y, columnWidth, columnHeight);

                // Add pulsing animation
                this.tweens.add({
                    targets: this.columnHighlight,
                    alpha: 0.5,
                    duration: 500,
                    yoyo: true,
                    repeat: -1
                });

                // Move Jeff to the highlighted column
                if (this.jeff) {
                    this.jeff.moveToColumn(column);
                }
            }

            clearColumnHighlight() {
                if (this.columnHighlight) {
                    this.columnHighlight.destroy();
                    this.columnHighlight = null;
                }
            }

            // Bowling ball movement with bouncing
            moveBowlingBall(ball, currentColumn) {
                const moveDistance = 30;
                let targetX = ball.x;
                let targetY = ball.y - moveDistance;

                // Calculate movement based on direction
                if (ball.direction === -45) {
                    // Moving left-up diagonal
                    targetX = ball.x - (moveDistance * 0.7);
                    targetY = ball.y - (moveDistance * 0.7);
                } else if (ball.direction === 45) {
                    // Moving right-up diagonal
                    targetX = ball.x + (moveDistance * 0.7);
                    targetY = ball.y - (moveDistance * 0.7);
                }

                // Check wall collisions for bouncing
                const leftBoundary = this.GRID_START_X;
                const rightBoundary = this.GRID_START_X + (this.GRID_COLS * this.TILE_SIZE);

                // Check if ball will hit a wall
                if (targetX <= leftBoundary) {
                    // Hit left wall - bounce to the right
                    targetX = leftBoundary;
                    ball.direction = 45; // Change to right diagonal
                    console.log('Bowling ball hit left wall - bouncing right');
                } else if (targetX >= rightBoundary) {
                    // Hit right wall - bounce to the left
                    targetX = rightBoundary;
                    ball.direction = -45; // Change to left diagonal
                    console.log('Bowling ball hit right wall - bouncing left');
                }

                // Check top boundary - if ball goes above game area, return to pool
                if (targetY < this.GRID_START_Y - 50) {
                    this.returnProjectileToPool(ball);
                    return;
                }

                this.tweens.add({
                    targets: ball,
                    x: targetX,
                    y: targetY,
                    duration: 150,
                    onComplete: () => {
                        if (ball.active) {
                            // Continue movement - collisions handled in main collision system
                            const newColumn = Math.floor((ball.x - this.GRID_START_X) / this.TILE_SIZE);
                            this.moveBowlingBall(ball, newColumn);
                        }
                    }
                });
            }

            // Bomb explosion with area damage
            explodeBomb(bomb, centerEnemy) {
                console.log(`Bomb exploding at enemy position: (${centerEnemy.x}, ${centerEnemy.y})`);

                // Calculate which grid tile the enemy is in
                const tileInfo = this.getTile(centerEnemy.x, centerEnemy.y);
                const enemyGridCol = tileInfo.col;
                const enemyGridRow = tileInfo.row;
                const gridCenterX = this.GRID_START_X + (enemyGridCol * this.TILE_SIZE) + (this.TILE_SIZE / 2);
                const gridCenterY = this.GRID_START_Y + (enemyGridRow * this.TILE_SIZE) + (this.TILE_SIZE / 2);

                // Check if enemy is mostly on one spot (close to tile center) vs between spots
                const distanceFromCenter = Phaser.Math.Distance.Between(centerEnemy.x, centerEnemy.y, gridCenterX, gridCenterY);
                const isOnSingleSpot = distanceFromCenter <= (this.TILE_SIZE * 0.3); // 30% of tile size tolerance

                let explosionTiles = [];

                if (isOnSingleSpot) {
                    // Enemy is mostly on one spot - 3x3 explosion (9 tiles) around the enemy's position
                    console.log(`Bomb: Enemy on single spot - 3x3 explosion at (${enemyGridCol}, ${enemyGridRow})`);
                    for (let row = -1; row <= 1; row++) {
                        for (let col = -1; col <= 1; col++) {
                            const tileRow = enemyGridRow + row;
                            const tileCol = enemyGridCol + col;
                            if (tileRow >= 0 && tileRow < this.GRID_ROWS && tileCol >= 0 && tileCol < this.GRID_COLS) {
                                explosionTiles.push({ row: tileRow, col: tileCol });
                            }
                        }
                    }
                } else {
                    // Enemy is between spots - determine the two main spots they're between
                    // Check if they're between rows or columns
                    const xOffset = (centerEnemy.x - gridCenterX) / this.TILE_SIZE;
                    const yOffset = (centerEnemy.y - gridCenterY) / this.TILE_SIZE;

                    if (Math.abs(yOffset) > Math.abs(xOffset)) {
                        // Enemy is primarily between rows (vertically between tiles)
                        const secondRow = yOffset < 0 ? enemyGridRow - 1 : enemyGridRow + 1;
                        console.log(`Bomb: Enemy between rows ${enemyGridRow} and ${secondRow} - cross explosion`);

                        // Add the 6 tiles: 2 center tiles + 2 left + 2 right
                        const crossTiles = [
                            { row: enemyGridRow, col: enemyGridCol },     // Main tile
                            { row: secondRow, col: enemyGridCol },        // Adjacent tile
                            { row: enemyGridRow, col: enemyGridCol - 1 }, // Left of main
                            { row: enemyGridRow, col: enemyGridCol + 1 }, // Right of main
                            { row: secondRow, col: enemyGridCol - 1 },    // Left of adjacent
                            { row: secondRow, col: enemyGridCol + 1 }     // Right of adjacent
                        ];

                        crossTiles.forEach(tile => {
                            if (tile.row >= 0 && tile.row < this.GRID_ROWS && tile.col >= 0 && tile.col < this.GRID_COLS) {
                                explosionTiles.push(tile);
                            }
                        });
                    } else {
                        // Enemy is primarily between columns (horizontally between tiles)
                        const secondCol = xOffset < 0 ? enemyGridCol - 1 : enemyGridCol + 1;
                        console.log(`Bomb: Enemy between cols ${enemyGridCol} and ${secondCol} - cross explosion`);

                        // Add the 6 tiles: 2 center tiles + 2 above + 2 below
                        const crossTiles = [
                            { row: enemyGridRow, col: enemyGridCol },     // Main tile
                            { row: enemyGridRow, col: secondCol },        // Adjacent tile
                            { row: enemyGridRow - 1, col: enemyGridCol }, // Above main
                            { row: enemyGridRow + 1, col: enemyGridCol }, // Below main
                            { row: enemyGridRow - 1, col: secondCol },    // Above adjacent
                            { row: enemyGridRow + 1, col: secondCol }     // Below adjacent
                        ];

                        crossTiles.forEach(tile => {
                            if (tile.row >= 0 && tile.row < this.GRID_ROWS && tile.col >= 0 && tile.col < this.GRID_COLS) {
                                explosionTiles.push(tile);
                            }
                        });
                    }
                }

                // Create explosion effects and damage enemies
                explosionTiles.forEach((tile, index) => {
                    const tileX = this.GRID_START_X + (tile.col * this.TILE_SIZE) + (this.TILE_SIZE / 2);
                    const tileY = this.GRID_START_Y + (tile.row * this.TILE_SIZE) + (this.TILE_SIZE / 2);

                    // Create smoke effect with slight delay for visual effect
                    this.time.delayedCall(index * 50, () => {
                        this.createSmokeEffect(tileX, tileY);
                    });

                    // Damage all enemies in this specific tile area (using distance-based detection)
                    this.activeEnemies.forEach(enemy => {
                        // Check if enemy is within this explosion tile using distance from tile center
                        const distanceFromTileCenter = Phaser.Math.Distance.Between(enemy.x, enemy.y, tileX, tileY);
                        const maxTileRadius = this.TILE_SIZE * 0.7; // 70% of tile size to account for tile boundaries

                        if (distanceFromTileCenter <= maxTileRadius) {
                            console.log(`Bomb: Killing enemy ${enemy.constructor.name} at tile (${tile.col}, ${tile.row}) - distance: ${Math.round(distanceFromTileCenter)}px`);
                            enemy.takeDamage(999); // Bomb kills instantly
                        }
                    });
                });

                console.log(`Bomb exploded in ${explosionTiles.length} tiles (${isOnSingleSpot ? '3x3' : '6-tile cross'} pattern)`);
            }

            // Create smoke effect for bomb explosions
            createSmokeEffect(x, y) {
                const smoke = this.add.circle(x, y, 15, 0x666666, 0.7);
                smoke.setDepth(LAYERS.PROJECTILES + 1);

                this.tweens.add({
                    targets: smoke,
                    scaleX: 2,
                    scaleY: 2,
                    alpha: 0,
                    duration: 800,
                    ease: 'Power2.easeOut',
                    onComplete: () => {
                        smoke.destroy();
                    }
                });
            }

            setupInput() {
                this.input.on('pointerdown', (pointer) => {
                    // Game input will be handled here later
                });
            }

            update(time, delta) {
                // Update FPS counter
                this.fpsText.setText('FPS: ' + Math.round(this.game.loop.actualFps));

                // Periodic debug output for enemy positions (every 1 second)
                this.debugTimer += delta;
                if (this.debugTimer >= 1000) {
                    this.debugTimer = 0;
                    this.logEnemyPositions();
                }

                // Update all active enemies (they should move even before game officially starts)
                this.activeEnemies.forEach(enemy => {
                    enemy.update(delta);
                });

                // Update falling card system
                if (this.gameStarted) {
                    // Update card spawn timer
                    this.cardSpawnTimer += delta;
                    if (this.cardSpawnTimer >= this.nextCardSpawnTime) {
                        console.log(`[CARD SYSTEM] Timer reached! Spawning new card...`);
                        this.spawnFallingCard();
                        this.cardSpawnTimer = 0;
                        this.nextCardSpawnTime = Phaser.Math.Between(this.cardSpawnMinTime, this.cardSpawnMaxTime);
                        console.log(`[CARD SYSTEM] Next card spawn in ${Math.round(this.nextCardSpawnTime / 1000)} seconds`);
                    }

                    // Update falling cards
                    this.fallingCards = this.fallingCards.filter(card => {
                        if (!card.isDragging && card.active) {
                            // Make card fall
                            card.y += (card.fallSpeed * delta) / 1000;

                            // Remove card if it falls off screen
                            if (card.y > this.scale.height + 50) {
                                card.destroy();
                                return false;
                            }
                        }
                        return card.active;
                    });

                    // Update wave system
                    if (!this.waveActive && this.waveComplete) {
                        this.nextWaveTime -= delta;
                        if (this.nextWaveTime <= 0) {
                            console.log(`[WAVE] Timer reached! Starting next wave...`);
                            this.startNextWave();
                        }
                    } else if (!this.waveActive && !this.waveComplete && this.currentWave === 0) {
                        // First wave timer
                        this.nextWaveTime -= delta;
                        if (this.nextWaveTime <= 0) {
                            console.log(`[WAVE] Starting first wave...`);
                            this.startNextWave();
                        }
                    }
                } else {
                    // Log once per second that game hasn't started
                    if (this.debugTimer === 0) {
                        console.log('[GAME STATE] Waiting for game to start. Click home screen to begin.');
                    }
                }

                // Check simple distance-based collisions
                this.checkCollisions();
            }

            logEnemyPositions() {
                console.log('=== ENEMY POSITION DEBUG ===');
                this.activeEnemies.forEach((enemy, index) => {
                    const tileInfo = this.getTile(enemy.x, enemy.y);
                    const expectedTileCenter = this.grid[tileInfo.row] && this.grid[tileInfo.row][tileInfo.col]
                        ? this.grid[tileInfo.row][tileInfo.col]
                        : { centerX: 'N/A', centerY: 'N/A' };

                    const enemyType = enemy.constructor.name;

                    console.log(`Enemy ${index + 1} (${enemyType}): 
                        Position: (${Math.round(enemy.x)}, ${Math.round(enemy.y)})
                        Calculated tile: (${tileInfo.col}, ${tileInfo.row}) ${tileInfo.rawCol !== tileInfo.col || tileInfo.rawRow !== tileInfo.row ? `[raw: (${tileInfo.rawCol}, ${tileInfo.rawRow})]` : ''}
                        Expected tile center: (${Math.round(expectedTileCenter.centerX || 0)}, ${Math.round(expectedTileCenter.centerY || 0)})
                        Distance to center: ${expectedTileCenter.centerX ? Math.round(Phaser.Math.Distance.Between(enemy.x, enemy.y, expectedTileCenter.centerX, expectedTileCenter.centerY)) : 'N/A'}px`);
                });
                console.log(`TILE_SIZE: ${Math.round(this.TILE_SIZE)}px | GRID_START: (${this.GRID_START_X}, ${this.GRID_START_Y})`);
                console.log('=========================');
            }

            checkCollisions() {
                // Clean up destroyed projectiles first
                this.activeProjectiles = this.activeProjectiles.filter(p => p.active && p.visible);

                // Check each projectile against each enemy using distance-based collision detection
                this.activeProjectiles.forEach(projectile => {
                    this.activeEnemies.forEach(enemy => {
                        const distance = Phaser.Math.Distance.Between(projectile.x, projectile.y, enemy.x, enemy.y);
                        const collisionThreshold = 25; // Collision threshold

                        if (distance < collisionThreshold) {
                            this.handleCollision(projectile, enemy);
                        }
                    });
                });
            }

            handleCollision(projectile, enemy) {
                console.log(`${projectile.attackType} hit ${enemy.constructor.name}`);

                // Calculate enemy's tile position for position-based collision tracking
                const tileInfo = this.getTile(enemy.x, enemy.y);
                const tileKey = `${tileInfo.col},${tileInfo.row}`;

                switch (projectile.attackType) {
                    case 'bullet':
                        // Check if this enemy has already been hit by this projectile
                        if (projectile.hitEnemies.includes(enemy)) {
                            return; // Skip collision if already hit
                        }

                        console.log(`Bullet hit ${enemy.constructor.name} for ${projectile.damage} damage`);
                        enemy.takeDamage(projectile.damage);

                        // Add enemy to hit list
                        projectile.hitEnemies.push(enemy);

                        // Note: Bullet continues through enemies (doesn't get destroyed)
                        break;
                    case 'bowling':
                        // For StandardAttack (bowling), use position-based collision prevention
                        if (projectile.hitPositions.includes(tileKey)) {
                            return; // Skip collision if we've already hit this position
                        }

                        console.log(`Bowling ball hit ${enemy.constructor.name} at position ${tileKey} for ${projectile.damage} damage`);
                        enemy.takeDamage(projectile.damage);

                        // Add position to hit list to prevent multiple hits at same location
                        projectile.hitPositions.push(tileKey);

                        // Implement bouncing trajectory
                        if (projectile.direction === 0) {
                            // First hit - randomly choose -45 or 45 degrees
                            projectile.direction = Math.random() < 0.5 ? -45 : 45;
                            console.log(`Bowling ball first hit - changing direction to ${projectile.direction} degrees`);
                        } else {
                            // Subsequent hits - invert the direction
                            projectile.direction = projectile.direction === 45 ? -45 : 45;
                            console.log(`Bowling ball bounce - inverting direction to ${projectile.direction} degrees`);
                        }
                        break;
                    case 'bomb':
                        console.log(`Bomb hit ${enemy.constructor.name} - exploding!`);
                        if (!projectile.hasExploded) {
                            projectile.hasExploded = true;

                            // Stop the bomb's movement tween
                            if (projectile.moveTween) {
                                projectile.moveTween.stop();
                            }

                            // Kill the enemy that was hit directly
                            enemy.takeDamage(999);

                            // Explode and damage nearby enemies
                            this.explodeBomb(projectile, enemy);

                            // Return bomb to pool
                            this.returnProjectileToPool(projectile);
                        }
                        break;
                }
            }


            startGame() {
                this.gameStarted = true;
                console.log('[GAME STATE] Game started! Initializing systems...');
                console.log(`[WAVE] First wave will start in ${this.nextWaveTime / 1000} seconds`);
                console.log(`[CARD SYSTEM] First card will spawn in ${Math.round(this.nextCardSpawnTime / 1000)} seconds`);
            }
        }

        const config = {
            type: Phaser.AUTO,
            width: 500,
            height: 800,
            scene: [Preloader, Game],
            fps: {
                target: 60,
                forceSetTimeOut: true,
            },
            backgroundColor: '#87CEEB'
        };

        window.game = new Phaser.Game(config);

        // Home screen click handler
        document.addEventListener('DOMContentLoaded', () => {
            document.addEventListener('click', (e) => {
                const homeScreen = document.getElementById('homeScreen');
                if (homeScreen && homeScreen.style.display !== 'none' && !homeScreen.classList.contains('fade-out')) {
                    homeScreen.classList.add('fade-out');

                    setTimeout(() => {
                        homeScreen.style.display = 'none';
                        const gameScene = window.game.scene.getScene('Game');
                        if (!gameScene.scene.isActive()) {
                            window.game.scene.start('Game');
                        } else {
                            gameScene.startGame();
                        }
                    }, 500);
                }
            });
        });
    </script>
</body>

</html>

Youez - 2016 - github.com/yon3zu
LinuXploit