436 lines
12 KiB
JavaScript
436 lines
12 KiB
JavaScript
/**
|
|
* HordeWaveSystem.js
|
|
* ==================
|
|
* KRVAVA ŽETEV - Horde Mode Wave Manager
|
|
*
|
|
* Features:
|
|
* - Wave spawning system
|
|
* - Difficulty scaling
|
|
* - Enemy type pools
|
|
* - Boss waves
|
|
* - Rewards
|
|
*
|
|
* @author NovaFarma Team
|
|
* @date 2025-12-23
|
|
*/
|
|
|
|
export default class HordeWaveSystem {
|
|
constructor(scene) {
|
|
this.scene = scene;
|
|
|
|
// Wave state
|
|
this.currentWave = 0;
|
|
this.isWaveActive = false;
|
|
this.waveStartTime = 0;
|
|
this.enemiesRemaining = 0;
|
|
this.enemiesKilled = 0;
|
|
|
|
// Spawn points
|
|
this.spawnPoints = [];
|
|
this.spawnRadius = 500; // Pixels from player
|
|
|
|
// Wave definitions
|
|
this.waves = [];
|
|
|
|
// Statistics
|
|
this.stats = {
|
|
totalWavesCompleted: 0,
|
|
totalEnemiesKilled: 0,
|
|
highestWave: 0,
|
|
totalRewards: 0
|
|
};
|
|
|
|
console.log('🌊 HordeWaveSystem initialized');
|
|
|
|
// Generate wave definitions
|
|
this.generateWaves();
|
|
}
|
|
|
|
/**
|
|
* Generate infinite wave definitions
|
|
*/
|
|
generateWaves() {
|
|
// Pre-generate 100 waves (can generate more on-demand)
|
|
for (let i = 1; i <= 100; i++) {
|
|
this.waves.push(this.generateWave(i));
|
|
}
|
|
|
|
console.log(`✅ Generated ${this.waves.length} wave definitions`);
|
|
}
|
|
|
|
/**
|
|
* Generate single wave definition
|
|
*/
|
|
generateWave(waveNumber) {
|
|
const wave = {
|
|
number: waveNumber,
|
|
enemies: [],
|
|
isBossWave: waveNumber % 10 === 0, // Every 10th wave is boss
|
|
rewards: {
|
|
zlatniki: 10 * waveNumber,
|
|
xp: 50 * waveNumber,
|
|
items: []
|
|
}
|
|
};
|
|
|
|
// Boss wave
|
|
if (wave.isBossWave) {
|
|
wave.enemies = this.generateBossWave(waveNumber);
|
|
} else {
|
|
// Normal wave
|
|
wave.enemies = this.generateNormalWave(waveNumber);
|
|
}
|
|
|
|
return wave;
|
|
}
|
|
|
|
/**
|
|
* Generate normal wave enemies
|
|
*/
|
|
generateNormalWave(waveNumber) {
|
|
const enemies = [];
|
|
|
|
// Base enemy count scales with wave
|
|
const baseCount = 5 + Math.floor(waveNumber * 1.5);
|
|
|
|
// Enemy types unlock progressively
|
|
const availableTypes = this.getAvailableEnemyTypes(waveNumber);
|
|
|
|
for (let i = 0; i < baseCount; i++) {
|
|
const enemyType = Phaser.Utils.Array.GetRandom(availableTypes);
|
|
const enemy = {
|
|
type: enemyType.id,
|
|
health: enemyType.baseHealth * (1 + waveNumber * 0.1), // +10% HP per wave
|
|
damage: enemyType.baseDamage * (1 + waveNumber * 0.05), // +5% damage per wave
|
|
speed: enemyType.baseSpeed,
|
|
spawnDelay: i * 500 // Stagger spawns
|
|
};
|
|
enemies.push(enemy);
|
|
}
|
|
|
|
return enemies;
|
|
}
|
|
|
|
/**
|
|
* Generate boss wave
|
|
*/
|
|
generateBossWave(waveNumber) {
|
|
const enemies = [];
|
|
|
|
// Boss
|
|
const bossLevel = Math.floor(waveNumber / 10);
|
|
const boss = {
|
|
type: 'boss_zombie',
|
|
health: 1000 * bossLevel,
|
|
damage: 50 * bossLevel,
|
|
speed: 80,
|
|
isBoss: true,
|
|
spawnDelay: 0
|
|
};
|
|
enemies.push(boss);
|
|
|
|
// Add minions (scales with boss level)
|
|
const minionCount = 5 + (bossLevel * 2);
|
|
for (let i = 0; i < minionCount; i++) {
|
|
const minion = {
|
|
type: 'elite_zombie',
|
|
health: 200 * bossLevel,
|
|
damage: 20 * bossLevel,
|
|
speed: 120,
|
|
spawnDelay: 1000 + (i * 500)
|
|
};
|
|
enemies.push(minion);
|
|
}
|
|
|
|
return enemies;
|
|
}
|
|
|
|
/**
|
|
* Get available enemy types for wave
|
|
*/
|
|
getAvailableEnemyTypes(waveNumber) {
|
|
const types = [
|
|
// Tier 1: Waves 1-5
|
|
{ id: 'basic_zombie', tier: 1, baseHealth: 100, baseDamage: 10, baseSpeed: 80 },
|
|
{ id: 'crawler_zombie', tier: 1, baseHealth: 80, baseDamage: 15, baseSpeed: 100 },
|
|
|
|
// Tier 2: Waves 6-15
|
|
{ id: 'runner_zombie', tier: 2, baseHealth: 120, baseDamage: 12, baseSpeed: 150 },
|
|
{ id: 'spitter_zombie', tier: 2, baseHealth: 90, baseDamage: 20, baseSpeed: 70 },
|
|
|
|
// Tier 3: Waves 16-30
|
|
{ id: 'tank_zombie', tier: 3, baseHealth: 300, baseDamage: 25, baseSpeed: 60 },
|
|
{ id: 'exploder_zombie', tier: 3, baseHealth: 150, baseDamage: 50, baseSpeed: 90 },
|
|
|
|
// Tier 4: Waves 31-50
|
|
{ id: 'mutant_zombie', tier: 4, baseHealth: 500, baseDamage: 40, baseSpeed: 110 },
|
|
{ id: 'alpha_zombie', tier: 4, baseHealth: 800, baseDamage: 60, baseSpeed: 100 },
|
|
|
|
// Tier 5: Waves 51+
|
|
{ id: 'nightmare_zombie', tier: 5, baseHealth: 1200, baseDamage: 80, baseSpeed: 130 },
|
|
{ id: 'omega_zombie', tier: 5, baseHealth: 2000, baseDamage: 100, baseSpeed: 120 }
|
|
];
|
|
|
|
// Filter by tier
|
|
let availableTier = 1;
|
|
if (waveNumber >= 51) availableTier = 5;
|
|
else if (waveNumber >= 31) availableTier = 4;
|
|
else if (waveNumber >= 16) availableTier = 3;
|
|
else if (waveNumber >= 6) availableTier = 2;
|
|
|
|
return types.filter(t => t.tier <= availableTier);
|
|
}
|
|
|
|
/**
|
|
* Start wave
|
|
*/
|
|
startWave(waveNumber = null) {
|
|
if (this.isWaveActive) {
|
|
console.log('⚠️ Wave already active!');
|
|
return false;
|
|
}
|
|
|
|
// Use next wave if not specified
|
|
if (waveNumber === null) {
|
|
waveNumber = this.currentWave + 1;
|
|
}
|
|
|
|
// Generate more waves if needed
|
|
if (waveNumber > this.waves.length) {
|
|
for (let i = this.waves.length + 1; i <= waveNumber; i++) {
|
|
this.waves.push(this.generateWave(i));
|
|
}
|
|
}
|
|
|
|
const wave = this.waves[waveNumber - 1];
|
|
if (!wave) {
|
|
console.error(`Wave ${waveNumber} not found!`);
|
|
return false;
|
|
}
|
|
|
|
this.currentWave = waveNumber;
|
|
this.isWaveActive = true;
|
|
this.waveStartTime = Date.now();
|
|
this.enemiesRemaining = wave.enemies.length;
|
|
this.enemiesKilled = 0;
|
|
|
|
console.log(`🌊 Wave ${waveNumber} ${wave.isBossWave ? '👑 BOSS ' : ''}starting!`);
|
|
console.log(` Enemies: ${wave.enemies.length}`);
|
|
|
|
// Spawn enemies
|
|
this.spawnWaveEnemies(wave);
|
|
|
|
// Show wave notification
|
|
this.showNotification({
|
|
title: wave.isBossWave ? '👑 BOSS WAVE!' : `Wave ${waveNumber}`,
|
|
text: `${wave.enemies.length} enemies incoming!`,
|
|
icon: '🌊'
|
|
});
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Spawn wave enemies
|
|
*/
|
|
spawnWaveEnemies(wave) {
|
|
wave.enemies.forEach(enemy => {
|
|
setTimeout(() => {
|
|
this.spawnEnemy(enemy);
|
|
}, enemy.spawnDelay || 0);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Spawn single enemy
|
|
*/
|
|
spawnEnemy(enemyData) {
|
|
// Get spawn point (random around player)
|
|
const spawnPoint = this.getRandomSpawnPoint();
|
|
|
|
// TODO: Create actual enemy sprite
|
|
console.log(`👾 Spawning ${enemyData.type} at (${spawnPoint.x}, ${spawnPoint.y})`);
|
|
|
|
// Create enemy using ZombieSystem or EnemySystem
|
|
// For now, just log
|
|
const enemy = {
|
|
...enemyData,
|
|
x: spawnPoint.x,
|
|
y: spawnPoint.y,
|
|
isAlive: true,
|
|
currentHealth: enemyData.health
|
|
};
|
|
|
|
// TODO: Add to enemy tracking
|
|
|
|
return enemy;
|
|
}
|
|
|
|
/**
|
|
* Get random spawn point
|
|
*/
|
|
getRandomSpawnPoint() {
|
|
const playerX = this.scene.player?.x || 0;
|
|
const playerY = this.scene.player?.y || 0;
|
|
|
|
// Random angle
|
|
const angle = Math.random() * Math.PI * 2;
|
|
|
|
// Spawn at radius distance
|
|
const x = playerX + Math.cos(angle) * this.spawnRadius;
|
|
const y = playerY + Math.sin(angle) * this.spawnRadius;
|
|
|
|
return { x, y };
|
|
}
|
|
|
|
/**
|
|
* Enemy killed callback
|
|
*/
|
|
onEnemyKilled(enemy) {
|
|
if (!this.isWaveActive) return;
|
|
|
|
this.enemiesKilled++;
|
|
this.enemiesRemaining--;
|
|
this.stats.totalEnemiesKilled++;
|
|
|
|
console.log(`💀 Enemy killed! (${this.enemiesKilled}/${this.currentWave ? this.waves[this.currentWave - 1].enemies.length : 0})`);
|
|
|
|
// Check if wave complete
|
|
if (this.enemiesRemaining <= 0) {
|
|
this.completeWave();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Complete wave
|
|
*/
|
|
completeWave() {
|
|
if (!this.isWaveActive) return;
|
|
|
|
const wave = this.waves[this.currentWave - 1];
|
|
const duration = Date.now() - this.waveStartTime;
|
|
|
|
this.isWaveActive = false;
|
|
this.stats.totalWavesCompleted++;
|
|
this.stats.highestWave = Math.max(this.stats.highestWave, this.currentWave);
|
|
|
|
console.log(`✅ Wave ${this.currentWave} complete!`);
|
|
console.log(` Time: ${Math.floor(duration / 1000)}s`);
|
|
console.log(` Killed: ${this.enemiesKilled}`);
|
|
|
|
// Grant rewards
|
|
this.grantWaveRewards(wave);
|
|
|
|
// Show completion notification
|
|
this.showNotification({
|
|
title: 'Wave Complete!',
|
|
text: `✅ Wave ${this.currentWave} cleared! Rewards granted!`,
|
|
icon: '🏆'
|
|
});
|
|
|
|
// Auto-start next wave after delay
|
|
setTimeout(() => {
|
|
this.showWaveCountdown();
|
|
}, 5000);
|
|
}
|
|
|
|
/**
|
|
* Grant wave rewards
|
|
*/
|
|
grantWaveRewards(wave) {
|
|
const rewards = wave.rewards;
|
|
|
|
console.log(`🎁 Rewards:`);
|
|
console.log(` 💰 ${rewards.zlatniki} Zlatniki`);
|
|
console.log(` ⭐ ${rewards.xp} XP`);
|
|
|
|
// TODO: Actually grant rewards to player
|
|
this.stats.totalRewards += rewards.zlatniki;
|
|
|
|
// Rare loot on boss waves
|
|
if (wave.isBossWave) {
|
|
console.log(` 👑 BONUS: Boss loot!`);
|
|
// TODO: Grant rare items
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show wave countdown
|
|
*/
|
|
showWaveCountdown() {
|
|
const nextWave = this.currentWave + 1;
|
|
|
|
console.log(`⏰ Next wave (${nextWave}) in 10 seconds...`);
|
|
|
|
this.showNotification({
|
|
title: 'Next Wave Soon',
|
|
text: `⏰ Wave ${nextWave} starts in 10 seconds!`,
|
|
icon: '⚔️'
|
|
});
|
|
|
|
// Auto-start after countdown
|
|
setTimeout(() => {
|
|
this.startWave(nextWave);
|
|
}, 10000);
|
|
}
|
|
|
|
/**
|
|
* End horde mode
|
|
*/
|
|
endHordeMode() {
|
|
this.isWaveActive = false;
|
|
|
|
console.log('🛑 Horde mode ended');
|
|
console.log('📊 Final Stats:');
|
|
console.log(` Waves: ${this.stats.totalWavesCompleted}`);
|
|
console.log(` Kills: ${this.stats.totalEnemiesKilled}`);
|
|
console.log(` Highest: ${this.stats.highestWave}`);
|
|
|
|
this.showNotification({
|
|
title: 'Horde Mode Ended',
|
|
text: `Survived ${this.stats.highestWave} waves! ${this.stats.totalEnemiesKilled} kills!`,
|
|
icon: '🏆'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get wave info
|
|
*/
|
|
getWaveInfo(waveNumber) {
|
|
return this.waves[waveNumber - 1];
|
|
}
|
|
|
|
/**
|
|
* Get statistics
|
|
*/
|
|
getStats() {
|
|
return {
|
|
...this.stats,
|
|
currentWave: this.currentWave,
|
|
isActive: this.isWaveActive
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Helper: Show notification
|
|
*/
|
|
showNotification(notification) {
|
|
console.log(`📢 ${notification.icon} ${notification.title}: ${notification.text}`);
|
|
|
|
const ui = this.scene.scene.get('UIScene');
|
|
if (ui && ui.showNotification) {
|
|
ui.showNotification(notification);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update system
|
|
*/
|
|
update(delta) {
|
|
if (!this.isWaveActive) return;
|
|
|
|
// Update wave timer, check conditions, etc.
|
|
// TODO: Implement wave updates
|
|
}
|
|
}
|