Source: gameState.js

/**
 * Game State Module
 * 
 * This module defines the game state and game phases
 * 
 * @module gameState
 */


/**
 * Game phases
 * 
 * @enum {string}
 * @readonly
 */
const GamePhase = {
    PLACEMENT: 'place',
    COMBAT: 'run'
};

/**
 * Tower types
 * 
 * @enum {string}
 * @readonly
 */
const TowerTypes = {
    BASIC: {
        name: 'Basic',
        cost: 5,
        range: 3,
        damage: 1,
        attackSpeed: 1,
        color: '#3498db',
        maxAmmo: 75
    },
    RAPID: {
        name: 'Fast',
        cost: 10,
        range: 2,
        damage: 1,
        attackSpeed: 3,
        color: '#16a085',
        maxAmmo: 50
    },
    SNIPER: {
        name: 'Distance',
        cost: 20,
        range: 6,
        damage: 2,
        attackSpeed: 0.5,
        color: '#8e44ad',
        maxAmmo: 50
    },
    GOOP: {
        name: 'Goop',
        cost: 20,
        range: 3,
        damage: 0,
        attackSpeed: 1,
        color: '#27ae60',
        special: 'slow',
        slowAmount: 0.75,
        maxAmmo: 25
    },
    AOE: {
        name: 'AOE',
        cost: 25,
        range: 2,
        damage: 3,
        attackSpeed: 0.25,
        color: '#d35400',
        special: 'aoe',
        aoeRadius: 2,
        maxAmmo: 25
    }
};

/**
 * Particle types
 * 
 * @enum {string}
 * @readonly
 */
const ParticleTypes = {
    DEATH_PARTICLE: {
        lifetime: 1000, // milliseconds
        speed: 0.1,
        colors: ['#e74c3c', '#c0392b', '#d35400', '#e67e22']
    },
    PROJECTILE: {
        lifetime: 300,
        speed: 0.3,
        color: '#ecf0f1'
    },
    AOE_EXPLOSION: {
        lifetime: 500,
        initialRadius: 10,
        finalRadius: 60,
        color: '#d35400',
        ringWidth: 3
    },
    SLIME_TRAIL: {
        lifetime: 800,
        color: '#27ae60',  // Same as Goop tower
        size: 12,
        fadeStart: 0.2     // When the fade should begin (percentage of lifetime)
    }
};

/**
 * Enemy types
 * 
 * @enum {string}
 * @readonly
 */
const EnemyTypes = {
    BASIC: {
        color: '#c0392b',
        baseHealth: { min: 2, max: 6 },
        speed: { min: 1, max: 1.5 },
        damage: 0,
        isRanged: false
    },
    RANGED: {
        color: '#2c3e50',
        baseHealth: { min: 1, max: 4 },
        speed: { min: 0.7, max: 1.2 },
        damage: 0.3,
        attackRange: 3,
        attackSpeed: 1, // attacks per second
        isRanged: true
    }
};

/**
 * Creates a tower
 * 
 * @param {string} type - Tower type
 * @param {Object} position - Position of the tower
 */
function createTower(type, position) {
    const towerType = TowerTypes[type];
    return {
        ...towerType,
        type,
        position,
        lastAttackTime: 0,
        currentHealth: 10,
        maxHealth: 10,
        ammo: towerType.maxAmmo  // Initialize ammo
    };
}

/**
 * Creates an enemy
 * 
 * @param {Object} startPosition - Starting position of the enemy
 */
function createEnemy(startPosition) {
    // 20% chance for ranged enemy
    const type = Math.random() < 0.2 ? 'RANGED' : 'BASIC';
    const enemyType = EnemyTypes[type];
    
    // Scale health ranges with level
    const levelScaling = 1 + (gameState.level - 1) * 0.25; // increase health by 25% per level
    const minHealth = Math.floor(enemyType.baseHealth.min * levelScaling);
    const maxHealth = Math.floor(enemyType.baseHealth.max * levelScaling);
    
    const health = Math.floor(Math.random() * 
        (maxHealth - minHealth + 1)) + minHealth;
    
    return {
        position: { ...startPosition },
        currentHealth: health,
        maxHealth: health,
        speed: enemyType.speed.min + Math.random() * (enemyType.speed.max - enemyType.speed.min),
        pathIndex: 0,
        type,
        lastAttackTime: 0,
        damage: enemyType.damage
    };
}

/**
 * Creates a particle
 * 
 * @param {string} type - Particle type
 * @param {Object} position - Position of the particle
 */
function createParticle(type, position, angle) {
    return {
        position: { ...position },
        velocity: {
            x: Math.cos(angle) * type.speed,
            y: Math.sin(angle) * type.speed
        },
        color: Array.isArray(type.colors) 
            ? type.colors[Math.floor(Math.random() * type.colors.length)]
            : type.color,
        createdAt: performance.now(),
        lifetime: type.lifetime,
        size: 3 + Math.random() * 2
    };
}


/**
 * Game state
 * 
 * @type {Object}
 */
const gameState = {
    grid: Array(20).fill().map(() => Array(20).fill('empty')),
    path: [],
    towers: [],
    enemies: [],
    currency: 100,
    phase: GamePhase.PLACEMENT,
    isGameOver: false,
    particles: [],
    projectiles: [],
    enemiesDestroyed: 0,
    enemiesEscaped: 0,
    level: 1,
    
    /**
     * Resets the game state
     */
    resetGame() {
        this.grid = Array(20).fill().map(() => Array(20).fill('empty'));
        this.path = [];
        this.towers = [];
        this.enemies = [];
        this.currency = 100;
        this.phase = GamePhase.PLACEMENT;
        this.isGameOver = false;
        this.particles = [];
        this.projectiles = [];
        this.enemiesDestroyed = 0;
        this.enemiesEscaped = 0;
        this.level = 1;
    },
    

    /**
     * Awards the enemy destroyed
     */
    awardEnemyDestroyed() {
        this.enemiesDestroyed++;
        // Random reward between 1 and 3
        const reward = Math.floor(Math.random() * 3) + 1;
        this.currency += reward;
    },
    

    /**
     * Checks if the level is complete
     * 
     * @returns {boolean}
     */
    checkLevelComplete() {
        return this.enemies.length === 0 && 
               enemiesRemaining === 0 && 
               this.phase === GamePhase.COMBAT;
    },
    

    /**
     * Advances to the next level
     */
    advanceToNextLevel() {

        let ammoBonus = 0;
        this.towers.forEach(tower => {
            ammoBonus += tower.ammo * 0.25;
        });
        this.currency += Math.floor(ammoBonus);  // Round down to nearest whole number
        
        this.level++;
        this.phase = GamePhase.PLACEMENT;
        this.towers = [];
        this.enemies = [];
        this.projectiles = [];
        this.particles = [];
        this.grid = Array(20).fill().map(() => Array(20).fill('empty'));
    }
};