/** * FARM RAID SYSTEM * Spawn raider waves, defend farm, rewards * Integrates with DefenseSystem and NomadRaiderAI */ export class FarmRaidSystem { constructor(scene) { this.scene = scene; // Raid state this.isRaidActive = false; this.currentWave = 0; this.totalWaves = 0; this.raidDifficulty = 1; // Spawn management this.activeRaiders = []; this.spawnPoints = []; // Raid triggers this.fameThreshold = 500; // Trigger raid at 500 fame this.resourceThreshold = 5000; // Or 5000 resources this.timeBetweenRaids = 600000; // 10 minutes minimum this.lastRaidTime = 0; // Rewards this.defenseRewards = new Map(); this.init(); } init() { this.initializeSpawnPoints(); this.initializeRewards(); // Check for raid triggers periodically this.scene.time.addEvent({ delay: 30000, // Check every 30s callback: () => this.checkRaidTriggers(), loop: true }); } /** * Initialize raid spawn points around farm */ initializeSpawnPoints() { const farmCenter = { x: 400, y: 300 }; // Adjust to actual farm center const spawnDistance = 400; // 8 spawn points around farm (N, NE, E, SE, S, SW, W, NW) for (let angle = 0; angle < 360; angle += 45) { const rad = Phaser.Math.DegToRad(angle); this.spawnPoints.push({ x: farmCenter.x + Math.cos(rad) * spawnDistance, y: farmCenter.y + Math.sin(rad) * spawnDistance, angle: angle }); } } /** * Initialize defense rewards */ initializeRewards() { this.defenseRewards.set(1, { xp: 200, currency: 500, items: ['raider_loot_common'] }); this.defenseRewards.set(2, { xp: 400, currency: 1000, items: ['raider_loot_common', 'raider_weapon'] }); this.defenseRewards.set(3, { xp: 800, currency: 2000, items: ['raider_loot_rare', 'raider_armor'] }); } /** * Check if raid should trigger */ checkRaidTriggers() { if (this.isRaidActive) return; const now = Date.now(); const timeSinceLastRaid = now - this.lastRaidTime; // Cooldown check if (timeSinceLastRaid < this.timeBetweenRaids) return; const fame = this.scene.gameState?.fame || 0; const totalResources = this.scene.inventorySystem?.getTotalResourceValue() || 0; // Trigger conditions if (fame >= this.fameThreshold || totalResources >= this.resourceThreshold) { this.startRaid(); } } /** * Start a raid */ startRaid(difficulty = null) { if (this.isRaidActive) return; this.isRaidActive = true; this.currentWave = 0; this.raidDifficulty = difficulty || this.calculateDifficulty(); this.totalWaves = 2 + this.raidDifficulty; // 3-5 waves this.lastRaidTime = Date.now(); // Notification this.scene.uiSystem?.showNotification( `RAID INCOMING! ${this.totalWaves} waves approaching!`, 'danger', { priority: 'high' } ); // SFX: Raid horn this.scene.soundSystem?.play('raid_horn'); // VFX: Red screen flash this.scene.cameras.main.flash(1000, 255, 0, 0); // Start first wave this.scene.time.delayedCall(3000, () => this.spawnWave()); console.log(`🚨 RAID STARTED: Difficulty ${this.raidDifficulty}, ${this.totalWaves} waves`); } /** * Calculate raid difficulty based on game progress */ calculateDifficulty() { const fame = this.scene.gameState?.fame || 0; const population = this.scene.gameState?.population || 0; // Scale difficulty return Math.min(5, Math.floor((fame / 500) + (population / 20))); } /** * Spawn a wave of raiders */ spawnWave() { this.currentWave++; const raiderCount = 3 + (this.raidDifficulty * 2); // 5-13 raiders const waveRaiders = []; // Spawn raiders for (let i = 0; i < raiderCount; i++) { const spawnPoint = Phaser.Utils.Array.GetRandom(this.spawnPoints); const raider = this.spawnRaider(spawnPoint.x, spawnPoint.y); waveRaiders.push(raider); } this.activeRaiders.push(...waveRaiders); // Notification this.scene.uiSystem?.showNotification( `Wave ${this.currentWave}/${this.totalWaves}: ${raiderCount} raiders!`, 'warning' ); console.log(`🔥 Wave ${this.currentWave}: Spawned ${raiderCount} raiders`); // Check for next wave this.scene.time.delayedCall(5000, () => this.checkWaveProgress()); } /** * Spawn individual raider */ spawnRaider(x, y) { // Create raider sprite const raider = this.scene.physics.add.sprite(x, y, 'nomad_raider'); // Stats based on difficulty raider.maxHealth = 50 + (this.raidDifficulty * 20); raider.health = raider.maxHealth; raider.attackDamage = 10 + (this.raidDifficulty * 5); raider.active = true; // Add AI raider.ai = new NomadRaiderAI(this.scene, raider); // Collisions this.scene.physics.add.collider(raider, this.scene.player); this.scene.physics.add.collider(raider, this.scene.zombieScout); // Health bar raider.healthBar = this.scene.add.graphics(); // Death handler raider.takeDamage = (amount) => this.raiderTakeDamage(raider, amount); return raider; } /** * Raider takes damage */ raiderTakeDamage(raider, amount) { raider.health -= amount; // Update health bar this.updateRaiderHealthBar(raider); // VFX raider.setTint(0xff0000); this.scene.time.delayedCall(100, () => raider.clearTint()); // Death if (raider.health <= 0) { this.raiderDeath(raider); } } /** * Raider death */ raiderDeath(raider) { raider.active = false; // Drop loot this.dropRaiderLoot(raider.x, raider.y); // VFX this.scene.vfxSystem?.playEffect('raider_death', raider.x, raider.y); // Remove from active list const index = this.activeRaiders.indexOf(raider); if (index > -1) { this.activeRaiders.splice(index, 1); } // Cleanup raider.ai?.destroy(); raider.healthBar?.destroy(); raider.destroy(); // Check if wave complete this.checkWaveProgress(); } /** * Update raider health bar */ updateRaiderHealthBar(raider) { if (!raider.healthBar) return; raider.healthBar.clear(); const barWidth = 40; const barHeight = 4; const healthPercent = raider.health / raider.maxHealth; // Background raider.healthBar.fillStyle(0x000000); raider.healthBar.fillRect(raider.x - barWidth / 2, raider.y - 30, barWidth, barHeight); // Health raider.healthBar.fillStyle(0xff0000); raider.healthBar.fillRect(raider.x - barWidth / 2, raider.y - 30, barWidth * healthPercent, barHeight); } /** * Drop loot from raider */ dropRaiderLoot(x, y) { const lootTable = ['wood', 'stone', 'metal', 'raider_weapon', 'medicine']; const drop = Phaser.Utils.Array.GetRandom(lootTable); const amount = Phaser.Math.Between(1, 5); // Create loot drop this.scene.lootSystem?.createDrop(x, y, drop, amount); } /** * Check if wave is complete */ checkWaveProgress() { if (!this.isRaidActive) return; const aliveRaiders = this.activeRaiders.filter(r => r.active); if (aliveRaiders.length === 0) { // Wave complete if (this.currentWave < this.totalWaves) { // Next wave this.scene.uiSystem?.showNotification( `Wave ${this.currentWave} cleared! Next wave incoming...`, 'success' ); this.scene.time.delayedCall(5000, () => this.spawnWave()); } else { // Raid complete this.endRaid(true); } } } /** * End raid (success or failure) */ endRaid(success) { this.isRaidActive = false; if (success) { // Victory! const rewards = this.defenseRewards.get(this.raidDifficulty) || this.defenseRewards.get(1); this.scene.uiSystem?.showNotification( `RAID DEFENDED! +${rewards.xp} XP, +${rewards.currency} coins`, 'victory', { priority: 'high' } ); // Grant rewards this.scene.zombieScoutLeveling?.awardXP(rewards.xp, 'raid_defense'); this.scene.economySystem?.addCurrency(rewards.currency); rewards.items.forEach(item => { this.scene.inventorySystem?.addItem(item, 1); }); // VFX this.scene.vfxSystem?.playEffect('victory', 400, 300); this.scene.cameras.main.flash(1000, 0, 255, 0); console.log(`✅ RAID DEFENDED! Rewards granted.`); } else { // Defeat this.scene.uiSystem?.showNotification( 'RAID DEFEATED YOU! Farm damaged.', 'defeat', { priority: 'high' } ); // Damage farm buildings this.damageFarm(); console.log(`❌ RAID FAILED! Farm damaged.`); } // Cleanup remaining raiders this.activeRaiders.forEach(raider => { raider.ai?.destroy(); raider.healthBar?.destroy(); raider.destroy(); }); this.activeRaiders = []; } /** * Damage farm on raid failure */ damageFarm() { // Damage random buildings const buildings = this.scene.buildingSystem?.getAllBuildings() || []; const damagedCount = Math.min(3, buildings.length); for (let i = 0; i < damagedCount; i++) { const building = Phaser.Utils.Array.GetRandom(buildings); building.takeDamage?.(50); } // Destroy random crops const crops = this.scene.crops || []; const destroyedCrops = Math.min(10, crops.length); for (let i = 0; i < destroyedCrops; i++) { const crop = Phaser.Utils.Array.GetRandom(crops); crop.destroy?.(); } } /** * Manual raid trigger (for testing/quests) */ triggerRaid(difficulty = 1) { this.startRaid(difficulty); } /** * Get raid state */ getRaidState() { return { isActive: this.isRaidActive, currentWave: this.currentWave, totalWaves: this.totalWaves, difficulty: this.raidDifficulty, activeRaiders: this.activeRaiders.filter(r => r.active).length }; } }