/** * 👹 BIOME ENEMY SYSTEM * Spawns biome-specific enemies across the world * - Different enemies per biome * - Difficulty scaling * - Loot drops * - Combat integration */ class BiomeEnemySystem { constructor(scene) { this.scene = scene; // All enemies in the world this.enemies = []; // Enemy types per biome this.enemyTypes = { 'Grassland': [ { type: 'wolf', hp: 30, damage: 5, speed: 1.5, loot: ['meat', 'fur'], color: 0x8B4513 }, { type: 'boar', hp: 40, damage: 7, speed: 1.2, loot: ['meat', 'tusk'], color: 0x654321 }, { type: 'bandit', hp: 50, damage: 10, speed: 1.0, loot: ['gold', 'sword'], color: 0x696969 } ], 'Forest': [ { type: 'goblin', hp: 25, damage: 6, speed: 1.3, loot: ['gold', 'dagger'], color: 0x228B22 }, { type: 'spider', hp: 20, damage: 4, speed: 1.8, loot: ['web', 'poison'], color: 0x2F4F4F }, { type: 'ent', hp: 80, damage: 15, speed: 0.8, loot: ['wood', 'seed'], color: 0x8B4513 } ], 'Desert': [ { type: 'scorpion', hp: 35, damage: 8, speed: 1.4, loot: ['poison', 'chitin'], color: 0xD2691E }, { type: 'mummy', hp: 60, damage: 12, speed: 0.9, loot: ['bandage', 'ancient_coin'], color: 0xDEB887 }, { type: 'sand_worm', hp: 100, damage: 20, speed: 0.7, loot: ['scales', 'tooth'], color: 0xC0B090 } ], 'Mountain': [ { type: 'troll', hp: 90, damage: 18, speed: 0.8, loot: ['stone', 'club'], color: 0x708090 }, { type: 'golem', hp: 120, damage: 25, speed: 0.6, loot: ['ore', 'core'], color: 0x696969 }, { type: 'harpy', hp: 45, damage: 10, speed: 2.0, loot: ['feather', 'talon'], color: 0x9370DB } ], 'Swamp': [ { type: 'zombie', hp: 50, damage: 10, speed: 0.9, loot: ['bone', 'rotten_flesh'], color: 0x556B2F }, { type: 'will_o_wisp', hp: 30, damage: 8, speed: 2.5, loot: ['essence', 'spark'], color: 0x00FFFF }, { type: 'swamp_dragon', hp: 150, damage: 30, speed: 0.7, loot: ['scale', 'heart'], color: 0x2F4F2F } ] }; // Spawn density per biome this.spawnDensity = { 'Grassland': 0.02, // 2% per tile 'Forest': 0.03, // 3% 'Desert': 0.015, // 1.5% 'Mountain': 0.025, // 2.5% 'Swamp': 0.035 // 3.5% }; console.log('👹 BiomeEnemySystem initialized'); } // Generate enemy spawns across the world generateSpawns(biomeSystem) { if (!biomeSystem) return; let enemiesSpawned = 0; const sampleRate = 10; // Check every 10th tile for (let x = 0; x < 500; x += sampleRate) { for (let y = 0; y < 500; y += sampleRate) { const biome = biomeSystem.getBiome(x, y); const density = this.spawnDensity[biome] || 0.02; if (Math.random() < density) { this.spawnEnemy(x, y, biome); enemiesSpawned++; } } } console.log(`✅ Spawned ${enemiesSpawned} enemies across world`); } // Spawn single enemy spawnEnemy(x, y, biome) { const enemyList = this.enemyTypes[biome] || this.enemyTypes['Grassland']; const enemyTemplate = enemyList[Math.floor(Math.random() * enemyList.length)]; const enemy = { x, y, type: enemyTemplate.type, biome, hp: enemyTemplate.hp, maxHp: enemyTemplate.hp, damage: enemyTemplate.damage, speed: enemyTemplate.speed, loot: [...enemyTemplate.loot], color: enemyTemplate.color, alive: true, sprite: null, lastMoveTime: 0 }; this.enemies.push(enemy); return enemy; } // Create enemy sprite when chunk loads createEnemySprite(enemy, chunk) { if (enemy.sprite || !enemy.alive) return; const worldX = enemy.x * 48 + 24; const worldY = enemy.y * 48 + 24; // Simple circle sprite const sprite = this.scene.add.circle(worldX, worldY, 15, enemy.color); sprite.setDepth(10 + worldY); // HP bar const hpBar = this.scene.add.rectangle(worldX, worldY - 25, 30, 4, 0xFF0000); hpBar.setOrigin(0, 0.5); hpBar.setDepth(10 + worldY); const hpFill = this.scene.add.rectangle(worldX, worldY - 25, 30, 4, 0x00FF00); hpFill.setOrigin(0, 0.5); hpFill.setDepth(10 + worldY); enemy.sprite = sprite; enemy.hpBar = hpBar; enemy.hpFill = hpFill; if (chunk) { chunk.sprites.push(sprite); chunk.sprites.push(hpBar); chunk.sprites.push(hpFill); } } // Update enemies (AI, movement) update(time, delta, playerX, playerY) { for (const enemy of this.enemies) { if (!enemy.alive || !enemy.sprite) continue; // Simple AI: Move towards player if nearby const dist = Math.sqrt((enemy.x - playerX) ** 2 + (enemy.y - playerY) ** 2); if (dist < 10 && time > enemy.lastMoveTime + 500) { // Move towards player const dx = playerX - enemy.x; const dy = playerY - enemy.y; const len = Math.sqrt(dx * dx + dy * dy); if (len > 0) { enemy.x += (dx / len) * enemy.speed * 0.1; enemy.y += (dy / len) * enemy.speed * 0.1; // Update sprite position enemy.sprite.setPosition(enemy.x * 48 + 24, enemy.y * 48 + 24); if (enemy.hpBar) { enemy.hpBar.setPosition(enemy.x * 48 + 24, enemy.y * 48 - 1); enemy.hpFill.setPosition(enemy.x * 48 + 24, enemy.y * 48 - 1); } } enemy.lastMoveTime = time; } // Attack player if very close if (dist < 1.5 && time > enemy.lastAttackTime + 2000) { this.attackPlayer(enemy); enemy.lastAttackTime = time; } } } // Enemy attacks player attackPlayer(enemy) { if (this.scene.player) { console.log(`👹 ${enemy.type} attacks for ${enemy.damage} damage!`); // TODO: Integrate with player health system // Visual feedback if (this.scene.cameras) { this.scene.cameras.main.shake(200, 0.005); } } } // Player attacks enemy damageEnemy(enemy, damage) { if (!enemy.alive) return; enemy.hp -= damage; // Update HP bar if (enemy.hpFill) { const hpPercent = Math.max(0, enemy.hp / enemy.maxHp); enemy.hpFill.setScale(hpPercent, 1); } console.log(`⚔️ ${enemy.type} takes ${damage} damage! (${enemy.hp}/${enemy.maxHp} HP)`); // Death if (enemy.hp <= 0) { this.killEnemy(enemy); } } // Kill enemy and drop loot killEnemy(enemy) { enemy.alive = false; console.log(`💀 ${enemy.type} died!`); // Drop loot if (this.scene.inventorySystem && enemy.loot.length > 0) { const lootItem = enemy.loot[Math.floor(Math.random() * enemy.loot.length)]; const amount = Math.floor(Math.random() * 3) + 1; this.scene.inventorySystem.addItem(lootItem, amount); console.log(` 💰 Dropped: ${amount}x ${lootItem}`); } // Destroy sprite if (enemy.sprite) { enemy.sprite.destroy(); if (enemy.hpBar) enemy.hpBar.destroy(); if (enemy.hpFill) enemy.hpFill.destroy(); enemy.sprite = null; } } // Find nearest enemy to point findNearestEnemy(x, y, maxDistance = 2) { let nearest = null; let minDist = maxDistance; for (const enemy of this.enemies) { if (!enemy.alive) continue; const dist = Math.sqrt((enemy.x - x) ** 2 + (enemy.y - y) ** 2); if (dist < minDist) { minDist = dist; nearest = enemy; } } return nearest; } // Get statistics getStats() { const alive = this.enemies.filter(e => e.alive).length; const byBiome = {}; for (const enemy of this.enemies) { if (!enemy.alive) continue; byBiome[enemy.biome] = (byBiome[enemy.biome] || 0) + 1; } return { totalEnemies: this.enemies.length, alive, dead: this.enemies.length - alive, byBiome }; } destroy() { this.enemies.forEach(enemy => { if (enemy.sprite) enemy.sprite.destroy(); if (enemy.hpBar) enemy.hpBar.destroy(); if (enemy.hpFill) enemy.hpFill.destroy(); }); this.enemies = []; } }