This repository has been archived on 2026-05-04. You can view files and clone it, but cannot push or open issues or pull requests.
Galaxy-Strike-Online/GameServer/systems/DungeonSystem.js
2026-01-30 10:58:30 -04:00

1586 lines
49 KiB
JavaScript

/**
* Galaxy Strike Online - Server Dungeon System
* Manages dungeon instances, encounters, and rewards
*/
class DungeonSystem {
constructor() {
this.dungeons = new Map();
this.instances = new Map(); // instanceId -> dungeon instance
this.playerInstances = new Map(); // userId -> instanceId
// Initialize room templates
this.roomTypes = {
entrance: { name: 'Entrance', enemies: 0, rewards: false },
corridor: { name: 'Corridor', enemies: 1, rewards: false },
chamber: { name: 'Chamber', enemies: 2, rewards: true },
treasure: { name: 'Treasure Room', enemies: 0, rewards: true },
boss: { name: 'Boss Room', enemies: 1, rewards: true, isBoss: true },
exit: { name: 'Exit', enemies: 0, rewards: false }
};
// Initialize enemy templates
this.enemyTemplates = {
// Original enemies
training_drone: {
name: 'Training Drone',
health: 10,
attack: 5,
defense: 2,
experience: 5,
credits: 3
},
practice_target: {
name: 'Practice Target',
health: 5,
attack: 0,
defense: 0,
experience: 2,
credits: 1
},
alien_guardian: {
name: 'Alien Guardian',
health: 50,
attack: 8,
defense: 5,
experience: 25,
credits: 15
},
ancient_drone: {
name: 'Ancient Drone',
health: 30,
attack: 12,
defense: 2,
experience: 20,
credits: 10
},
crystal_golem: {
name: 'Crystal Golem',
health: 80,
attack: 6,
defense: 10,
experience: 35,
credits: 25
},
space_pirate: {
name: 'Space Pirate',
health: 25,
attack: 10,
defense: 3,
experience: 15,
credits: 12
},
pirate_captain: {
name: 'Pirate Captain',
health: 40,
attack: 15,
defense: 6,
experience: 30,
credits: 20
},
defense_turret: {
name: 'Defense Turret',
health: 20,
attack: 18,
defense: 8,
experience: 18,
credits: 8
},
security_drone: {
name: 'Security Drone',
health: 35,
attack: 14,
defense: 4,
experience: 22,
credits: 15
},
corrupted_ai: {
name: 'Corrupted AI',
health: 60,
attack: 20,
defense: 2,
experience: 40,
credits: 30
},
virus_program: {
name: 'Virus Program',
health: 15,
attack: 25,
defense: 1,
experience: 20,
credits: 12
},
mining_drone: {
name: 'Mining Drone',
health: 20,
attack: 8,
defense: 3,
experience: 12,
credits: 8
},
rock_creature: {
name: 'Rock Creature',
health: 45,
attack: 6,
defense: 12,
experience: 25,
credits: 15
},
explosive_asteroid: {
name: 'Explosive Asteroid',
health: 10,
attack: 30,
defense: 0,
experience: 15,
credits: 5
},
energy_being: {
name: 'Energy Being',
health: 55,
attack: 22,
defense: 3,
experience: 45,
credits: 35
},
phase_shifter: {
name: 'Phase Shifter',
health: 30,
attack: 28,
defense: 1,
experience: 35,
credits: 25
},
quantum_entity: {
name: 'Quantum Entity',
health: 70,
attack: 35,
defense: 5,
experience: 60,
credits: 50
},
// NEW ENEMIES - Space Theme
maintenance_drone: {
name: 'Maintenance Drone',
health: 28,
attack: 11,
defense: 4,
experience: 18,
credits: 12
},
security_android: {
name: 'Security Android',
health: 42,
attack: 16,
defense: 7,
experience: 28,
credits: 20
},
station_ai: {
name: 'Station AI',
health: 65,
attack: 24,
defense: 3,
experience: 45,
credits: 32
},
ice_elemental: {
name: 'Ice Elemental',
health: 38,
attack: 18,
defense: 8,
experience: 32,
credits: 24
},
frost_wyrm: {
name: 'Frost Wyrm',
health: 72,
attack: 26,
defense: 6,
experience: 52,
credits: 38
},
gravity_wraith: {
name: 'Gravity Wraith',
health: 85,
attack: 32,
defense: 4,
experience: 68,
credits: 48
},
void_stalker: {
name: 'Void Stalker',
health: 78,
attack: 38,
defense: 5,
experience: 72,
credits: 52
},
singularity_spawn: {
name: 'Singularity Spawn',
health: 95,
attack: 42,
defense: 8,
experience: 85,
credits: 65
},
plasma_elemental: {
name: 'Plasma Elemental',
health: 58,
attack: 28,
defense: 4,
experience: 48,
credits: 35
},
solar_guardian: {
name: 'Solar Guardian',
health: 82,
attack: 34,
defense: 7,
experience: 65,
credits: 48
},
fusion_core: {
name: 'Fusion Core',
health: 68,
attack: 30,
defense: 12,
experience: 58,
credits: 42
},
scrap_golem: {
name: 'Scrap Golem',
health: 35,
attack: 14,
defense: 9,
experience: 22,
credits: 16
},
hull_breacher: {
name: 'Hull Breacher',
health: 32,
attack: 20,
defense: 3,
experience: 26,
credits: 18
},
salage_drone: {
name: 'Salvage Drone',
health: 22,
attack: 12,
defense: 5,
experience: 16,
credits: 11
},
// NEW ENEMIES - Planet Theme
plant_beast: {
name: 'Plant Beast',
health: 48,
attack: 15,
defense: 8,
experience: 35,
credits: 26
},
tribal_warrior: {
name: 'Tribal Warrior',
health: 38,
attack: 18,
defense: 6,
experience: 28,
credits: 20
},
jungle_spirit: {
name: 'Jungle Spirit',
health: 55,
attack: 22,
defense: 4,
experience: 42,
credits: 30
},
sand_worm: {
name: 'Sand Worm',
health: 75,
attack: 28,
defense: 9,
experience: 58,
credits: 42
},
mummy_guardian: {
name: 'Mummy Guardian',
health: 62,
attack: 24,
defense: 7,
experience: 48,
credits: 35
},
heat_elemental: {
name: 'Heat Elemental',
health: 52,
attack: 26,
defense: 3,
experience: 45,
credits: 32
},
lava_elemental: {
name: 'Lava Elemental',
health: 68,
attack: 30,
defense: 5,
experience: 55,
credits: 40
},
fire_demon: {
name: 'Fire Demon',
health: 72,
attack: 32,
defense: 6,
experience: 62,
credits: 45
},
magma_beast: {
name: 'Magma Beast',
health: 85,
attack: 28,
defense: 12,
experience: 68,
credits: 50
},
cryo_mutant: {
name: 'Cryo Mutant',
health: 45,
attack: 20,
defense: 7,
experience: 38,
credits: 28
},
frost_android: {
name: 'Frost Android',
health: 52,
attack: 22,
defense: 8,
experience: 42,
credits: 30
},
ice_wraith: {
name: 'Ice Wraith',
health: 58,
attack: 25,
defense: 4,
experience: 48,
credits: 35
},
swamp_beast: {
name: 'Swamp Beast',
health: 35,
attack: 16,
defense: 9,
experience: 24,
credits: 18
},
toxic_spitter: {
name: 'Toxic Spitter',
health: 28,
attack: 19,
defense: 3,
experience: 22,
credits: 16
},
mud_golem: {
name: 'Mud Golem',
health: 42,
attack: 12,
defense: 11,
experience: 26,
credits: 19
},
// NEW ENEMIES - Technology Theme
glitch_wraith: {
name: 'Glitch Wraith',
health: 48,
attack: 26,
defense: 2,
experience: 45,
credits: 32
},
firewall_guardian: {
name: 'Firewall Guardian',
health: 65,
attack: 22,
defense: 8,
experience: 52,
credits: 38
},
data_vampire: {
name: 'Data Vampire',
health: 38,
attack: 30,
defense: 3,
experience: 35,
credits: 26
},
assembly_drone: {
name: 'Assembly Drone',
health: 32,
attack: 15,
defense: 6,
experience: 24,
credits: 17
},
welder_bot: {
name: 'Welder Bot',
health: 28,
attack: 20,
defense: 4,
experience: 22,
credits: 15
},
factory_overseer: {
name: 'Factory Overseer',
health: 58,
attack: 24,
defense: 7,
experience: 46,
credits: 33
},
quantum_phantom: {
name: 'Quantum Phantom',
health: 78,
attack: 35,
defense: 4,
experience: 68,
credits: 50
},
particle_accelerator: {
name: 'Particle Accelerator',
health: 92,
attack: 40,
defense: 6,
experience: 85,
credits: 62
},
reality_bender: {
name: 'Reality Bender',
health: 88,
attack: 45,
defense: 3,
experience: 92,
credits: 68
},
sentinel_program: {
name: 'Sentinel Program',
health: 42,
attack: 21,
defense: 8,
experience: 32,
credits: 24
},
data_corruptor: {
name: 'Data Corruptor',
health: 35,
attack: 25,
defense: 3,
experience: 28,
credits: 20
},
system_guardian: {
name: 'System Guardian',
health: 55,
attack: 23,
defense: 9,
experience: 42,
credits: 30
},
// NEW ENEMIES - Biome/Elemental Theme
shard_elemental: {
name: 'Shard Elemental',
health: 45,
attack: 19,
defense: 10,
experience: 38,
credits: 28
},
resonance_beast: {
name: 'Resonance Beast',
health: 52,
attack: 22,
defense: 6,
experience: 42,
credits: 30
},
mutant_horror: {
name: 'Mutant Horror',
health: 68,
attack: 28,
defense: 5,
experience: 58,
credits: 42
},
toxic_slime: {
name: 'Toxic Slime',
health: 42,
attack: 18,
defense: 8,
experience: 32,
credits: 24
},
radiation_beast: {
name: 'Radiation Beast',
health: 75,
attack: 30,
defense: 4,
experience: 65,
credits: 48
},
shadow_demon: {
name: 'Shadow Demon',
health: 72,
attack: 34,
defense: 3,
experience: 68,
credits: 50
},
nightmare_stalker: {
name: 'Nightmare Stalker',
health: 85,
attack: 38,
defense: 5,
experience: 78,
credits: 58
},
void_walker: {
name: 'Void Walker',
health: 92,
attack: 42,
defense: 7,
experience: 88,
credits: 65
},
temporal_paradox: {
name: 'Temporal Paradox',
health: 78,
attack: 40,
defense: 4,
experience: 75,
credits: 55
},
future_soldier: {
name: 'Future Soldier',
health: 65,
attack: 32,
defense: 9,
experience: 58,
credits: 42
},
past_guardian: {
name: 'Past Guardian',
health: 70,
attack: 28,
defense: 12,
experience: 62,
credits: 45
},
// NEW ENEMIES - Military/War Theme
enemy_soldier: {
name: 'Enemy Soldier',
health: 45,
attack: 20,
defense: 7,
experience: 35,
credits: 26
},
combat_drone: {
name: 'Combat Drone',
health: 38,
attack: 22,
defense: 5,
experience: 30,
credits: 22
},
field_commander: {
name: 'Field Commander',
health: 62,
attack: 28,
defense: 9,
experience: 52,
credits: 38
},
turret_system: {
name: 'Turret System',
health: 48,
attack: 26,
defense: 10,
experience: 38,
credits: 28
},
combat_android: {
name: 'Combat Android',
health: 55,
attack: 24,
defense: 8,
experience: 45,
credits: 33
},
base_commander: {
name: 'Base Commander',
health: 72,
attack: 30,
defense: 11,
experience: 62,
credits: 45
},
weapon_drone: {
name: 'Weapon Drone',
health: 42,
attack: 28,
defense: 4,
experience: 38,
credits: 28
},
test_subject: {
name: 'Test Subject',
health: 58,
attack: 25,
defense: 6,
experience: 48,
credits: 35
},
chief_scientist: {
name: 'Chief Scientist',
health: 35,
attack: 32,
defense: 3,
experience: 42,
credits: 30
},
// NEW ENEMIES - Special/Unique Theme
nightmare_creature: {
name: 'Nightmare Creature',
health: 62,
attack: 28,
defense: 5,
experience: 55,
credits: 40
},
dream_guardian: {
name: 'Dream Guardian',
health: 68,
attack: 30,
defense: 8,
experience: 58,
credits: 42
},
subconscious_demon: {
name: 'Subconscious Demon',
health: 75,
attack: 34,
defense: 4,
experience: 68,
credits: 50
},
memory_fragment: {
name: 'Memory Fragment',
health: 48,
attack: 26,
defense: 6,
experience: 45,
credits: 33
},
forgetfulness_demon: {
name: 'Forgetfulness Demon',
health: 55,
attack: 30,
defense: 3,
experience: 48,
credits: 35
},
nostalgia_spirit: {
name: 'Nostalgia Spirit',
health: 52,
attack: 24,
defense: 9,
experience: 42,
credits: 30
},
rift_demon: {
name: 'Rift Demon',
health: 88,
attack: 44,
defense: 5,
experience: 92,
credits: 68
},
dimensional_hunter: {
name: 'Dimensional Hunter',
health: 95,
attack: 48,
defense: 8,
experience: 105,
credits: 78
},
reality_tear: {
name: 'Reality Tear',
health: 102,
attack: 52,
defense: 3,
experience: 115,
credits: 85
}
};
this.initializeDungeons();
}
initializeDungeons() {
// Tutorial Dungeon
this.addDungeon('tutorial', {
name: 'Tutorial Dungeon',
description: 'Learn the basics of dungeon exploration in this guided tutorial',
difficulty: 'tutorial',
enemyTypes: ['training_drone', 'practice_target'],
rewardMultiplier: 0.5,
oneTimeOnly: true,
healthType: 'player', // Ground mission
energyCost: 0,
minLevel: 1,
maxLevel: 5,
maxPlayers: 4,
estimatedTime: 15
});
// Space Theme Dungeons
this.addDungeon('alien_ruins', {
name: 'Alien Ruins',
description: 'Ancient alien structures filled with mysterious technology',
difficulty: 'medium',
enemyTypes: ['alien_guardian', 'ancient_drone', 'crystal_golem'],
rewardMultiplier: 1.2,
healthType: 'player', // Ground mission
energyCost: 20,
minLevel: 5,
maxLevel: 15,
maxPlayers: 4,
estimatedTime: 25
});
this.addDungeon('pirate_lair', {
name: 'Pirate Lair',
description: 'Dangerous pirate hideouts with valuable loot',
difficulty: 'easy',
enemyTypes: ['space_pirate', 'pirate_captain', 'defense_turret'],
rewardMultiplier: 1.0,
healthType: 'ship', // Space mission
energyCost: 15,
minLevel: 3,
maxLevel: 10,
maxPlayers: 4,
estimatedTime: 20
});
this.addDungeon('corrupted_vault', {
name: 'Corrupted AI Vault',
description: ' malfunctioning AI facilities with corrupted security',
difficulty: 'hard',
enemyTypes: ['security_drone', 'corrupted_ai', 'virus_program'],
rewardMultiplier: 1.5,
healthType: 'ship', // Space mission
energyCost: 25,
minLevel: 10,
maxLevel: 20,
maxPlayers: 4,
estimatedTime: 35
});
this.addDungeon('asteroid_mine', {
name: 'Asteroid Mine',
description: 'Abandoned mining facilities in asteroid fields',
difficulty: 'easy',
enemyTypes: ['mining_drone', 'rock_creature', 'explosive_asteroid'],
rewardMultiplier: 0.8,
healthType: 'ship', // Space mission
energyCost: 10,
minLevel: 2,
maxLevel: 8,
maxPlayers: 4,
estimatedTime: 18
});
this.addDungeon('nebula_anomaly', {
name: 'Nebula Anomaly',
description: 'Strange energy anomalies in deep space',
difficulty: 'extreme',
enemyTypes: ['energy_being', 'phase_shifter', 'quantum_entity'],
rewardMultiplier: 2.0,
healthType: 'ship', // Space mission
energyCost: 30,
minLevel: 15,
maxLevel: 25,
maxPlayers: 4,
estimatedTime: 40
});
this.addDungeon('space_station', {
name: 'Abandoned Space Station',
description: 'A derelict space station floating in the void',
difficulty: 'medium',
enemyTypes: ['maintenance_drone', 'security_android', 'station_ai'],
rewardMultiplier: 1.3,
healthType: 'player',
energyCost: 22,
minLevel: 6,
maxLevel: 16,
maxPlayers: 4,
estimatedTime: 28
});
this.addDungeon('comet_core', {
name: 'Comet Core',
description: 'The frozen heart of a passing comet',
difficulty: 'hard',
enemyTypes: ['ice_elemental', 'frost_wyrm', 'crystal_guardian'],
rewardMultiplier: 1.6,
healthType: 'ship',
energyCost: 28,
minLevel: 12,
maxLevel: 22,
maxPlayers: 4,
estimatedTime: 32
});
this.addDungeon('black_hole_perimeter', {
name: 'Black Hole Perimeter',
description: 'Dangerous space near a black hole event horizon',
difficulty: 'extreme',
enemyTypes: ['gravity_wraith', 'void_stalker', 'singularity_spawn'],
rewardMultiplier: 2.5,
healthType: 'ship',
energyCost: 35,
minLevel: 18,
maxLevel: 30,
maxPlayers: 4,
estimatedTime: 45
});
this.addDungeon('star_forge', {
name: 'Star Forge',
description: 'Ancient facility that harnesses stellar energy',
difficulty: 'hard',
enemyTypes: ['plasma_elemental', 'solar_guardian', 'fusion_core'],
rewardMultiplier: 1.8,
healthType: 'ship',
energyCost: 30,
minLevel: 14,
maxLevel: 24,
maxPlayers: 4,
estimatedTime: 35
});
this.addDungeon('debris_field', {
name: 'Ship Debris Field',
description: 'Graveyard of destroyed spacecraft',
difficulty: 'easy',
enemyTypes: ['scrap_golem', 'hull_breacher', 'salage_drone'],
rewardMultiplier: 0.9,
healthType: 'ship',
energyCost: 12,
minLevel: 3,
maxLevel: 9,
maxPlayers: 4,
estimatedTime: 20
});
// Planet Theme Dungeons
this.addDungeon('jungle_temple', {
name: 'Jungle Temple',
description: 'Overgrown temple hidden in dense alien jungle',
difficulty: 'medium',
enemyTypes: ['plant_beast', 'tribal_warrior', 'jungle_spirit'],
rewardMultiplier: 1.4,
healthType: 'player',
energyCost: 25,
minLevel: 7,
maxLevel: 17,
maxPlayers: 4,
estimatedTime: 30
});
this.addDungeon('desert_pyramid', {
name: 'Desert Pyramid',
description: 'Ancient pyramid buried under endless sand dunes',
difficulty: 'hard',
enemyTypes: ['sand_worm', 'mummy_guardian', 'heat_elemental'],
rewardMultiplier: 1.7,
healthType: 'player',
energyCost: 28,
minLevel: 13,
maxLevel: 23,
maxPlayers: 4,
estimatedTime: 33
});
this.addDungeon('volcanic_caverns', {
name: 'Volcanic Caverns',
description: 'Molten caverns deep within an active volcano',
difficulty: 'hard',
enemyTypes: ['lava_elemental', 'fire_demon', 'magma_beast'],
rewardMultiplier: 1.6,
healthType: 'player',
energyCost: 26,
minLevel: 12,
maxLevel: 22,
maxPlayers: 4,
estimatedTime: 32
});
this.addDungeon('arctic_research', {
name: 'Arctic Research Base',
description: 'Frozen research facility with failed experiments',
difficulty: 'medium',
enemyTypes: ['cryo_mutant', 'frost_android', 'ice_wraith'],
rewardMultiplier: 1.5,
healthType: 'player',
energyCost: 24,
minLevel: 8,
maxLevel: 18,
maxPlayers: 4,
estimatedTime: 29
});
this.addDungeon('swamp_lair', {
name: 'Swamp Lair',
description: 'Murky swamp inhabited by strange creatures',
difficulty: 'easy',
enemyTypes: ['swamp_beast', 'toxic_spitter', 'mud_golem'],
rewardMultiplier: 1.1,
healthType: 'player',
energyCost: 18,
minLevel: 4,
maxLevel: 12,
maxPlayers: 4,
estimatedTime: 22
});
// Technology Theme Dungeons
this.addDungeon('cyber_realm', {
name: 'Cyber Realm',
description: 'Virtual reality space corrupted by malware',
difficulty: 'hard',
enemyTypes: ['glitch_wraith', 'firewall_guardian', 'data_vampire'],
rewardMultiplier: 1.9,
healthType: 'player',
energyCost: 32,
minLevel: 16,
maxLevel: 26,
maxPlayers: 4,
estimatedTime: 38
});
this.addDungeon('robot_factory', {
name: 'Robot Factory',
description: 'Automated factory producing hostile machines',
difficulty: 'medium',
enemyTypes: ['assembly_drone', 'welder_bot', 'factory_overseer'],
rewardMultiplier: 1.4,
healthType: 'player',
energyCost: 23,
minLevel: 9,
maxLevel: 19,
maxPlayers: 4,
estimatedTime: 27
});
this.addDungeon('quantum_lab', {
name: 'Quantum Laboratory',
description: 'Research facility experimenting with quantum physics',
difficulty: 'extreme',
enemyTypes: ['quantum_phantom', 'particle_accelerator', 'reality_bender'],
rewardMultiplier: 2.3,
healthType: 'player',
energyCost: 38,
minLevel: 20,
maxLevel: 30,
maxPlayers: 4,
estimatedTime: 42
});
this.addDungeon('server_farm', {
name: 'Server Farm',
description: 'Massive data center with rogue security programs',
difficulty: 'medium',
enemyTypes: ['sentinel_program', 'data_corruptor', 'system_guardian'],
rewardMultiplier: 1.3,
healthType: 'player',
energyCost: 21,
minLevel: 7,
maxLevel: 17,
maxPlayers: 4,
estimatedTime: 25
});
console.log(`[DUNGEON SYSTEM] Initialized ${this.dungeons.size} dungeons`);
}
setIO(io) {
this.io = io;
console.log('[DUNGEON SYSTEM] Socket.IO instance set for quest events');
}
generateDungeonEncounters(dungeon) {
console.log('[DUNGEON SYSTEM] Generating encounters for dungeon:', dungeon.id);
const encounters = [];
const encounterCount = Math.max(3, Math.floor(dungeon.estimatedTime / 5)); // 1 encounter per ~5 minutes
console.log('[DUNGEON SYSTEM] Encounter count:', encounterCount, 'for difficulty:', dungeon.difficulty);
// Always start with entrance
encounters.push({
type: 'entrance',
name: 'Dungeon Entrance',
description: 'The entrance to the dungeon',
enemies: [],
rewards: false
});
// Generate random encounters based on dungeon difficulty
for (let i = 1; i < encounterCount - 1; i++) {
const encounterTypes = ['corridor', 'chamber'];
if (i === Math.floor(encounterCount / 2)) {
encounterTypes.push('treasure'); // Mid-dungeon treasure room
}
const type = encounterTypes[Math.floor(Math.random() * encounterTypes.length)];
const template = this.roomTypes[type];
encounters.push({
type,
name: template.name,
description: `A ${template.name.toLowerCase()} in the dungeon`,
enemies: this.generateEnemies(dungeon.enemyTypes, template.enemies),
rewards: template.rewards
});
}
// Always end with boss room (except tutorial)
if (dungeon.difficulty !== 'tutorial') {
encounters.push({
type: 'boss',
name: 'Boss Chamber',
description: 'The final chamber with a powerful enemy',
enemies: this.generateEnemies(dungeon.enemyTypes, 1, true),
rewards: true,
isBoss: true
});
} else {
// Tutorial ends with simple chamber (only practice targets for auto-completion)
encounters.push({
type: 'chamber',
name: 'Training Room',
description: 'The final training room',
enemies: this.generateEnemies(['practice_target'], 1), // Only practice targets
rewards: true
});
}
console.log('[DUNGEON SYSTEM] Generated encounters:', encounters.map((e, i) => ({
index: i,
type: e.type,
name: e.name,
enemyCount: e.enemies?.length || 0
})));
return encounters;
}
generateEnemies(enemyTypes, count, isBoss = false) {
console.log('[DUNGEON SYSTEM] Generating enemies:', { enemyTypes, count, isBoss });
console.log('[DUNGEON SYSTEM] Available enemy templates:', Object.keys(this.enemyTemplates));
const enemies = [];
for (let i = 0; i < count; i++) {
const enemyTypeId = enemyTypes[Math.floor(Math.random() * enemyTypes.length)];
const template = this.enemyTemplates[enemyTypeId];
console.log(`[DUNGEON SYSTEM] Generating enemy ${i}: type=${enemyTypeId}, template=`, template);
if (!template) {
console.warn(`[DUNGEON SYSTEM] Enemy template not found for type: ${enemyTypeId}`);
continue;
}
// Scale enemy for boss fights
const enemy = { ...template };
if (isBoss) {
enemy.health *= 3;
enemy.attack *= 2;
enemy.defense *= 1.5;
enemy.experience *= 5;
enemy.credits *= 3;
enemy.name = `Elite ${enemy.name}`;
}
enemies.push(enemy);
}
console.log('[DUNGEON SYSTEM] Generated enemies:', enemies);
return enemies;
}
addDungeon(id, dungeon) {
// Generate encounters for this dungeon
const encounters = this.generateDungeonEncounters(dungeon);
this.dungeons.set(id, {
id,
...dungeon,
encounters,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
});
}
getDungeon(id) {
return this.dungeons.get(id);
}
getAllDungeons() {
return Array.from(this.dungeons.values());
}
getDungeonsGroupedByDifficulty() {
const dungeonsByDifficulty = {
tutorial: [],
easy: [],
medium: [],
hard: [],
extreme: []
};
this.dungeons.forEach(dungeon => {
if (dungeonsByDifficulty[dungeon.difficulty]) {
dungeonsByDifficulty[dungeon.difficulty].push(dungeon);
}
});
return dungeonsByDifficulty;
}
getRoomTypes() {
return this.roomTypes;
}
getEnemyTemplates() {
return this.enemyTemplates;
}
getEnemyTemplate(enemyId) {
return this.enemyTemplates[enemyId];
}
getDungeonsByDifficulty(difficulty) {
return Array.from(this.dungeons.values()).filter(dungeon => dungeon.difficulty === difficulty);
}
createInstance(dungeonId, creatorId, playerIds = []) {
console.log('[DUNGEON SYSTEM] Creating instance:', { dungeonId, creatorId, playerIds });
const dungeon = this.getDungeon(dungeonId);
if (!dungeon) {
throw new Error('Dungeon not found');
}
console.log('[DUNGEON SYSTEM] Dungeon found:', {
id: dungeon.id,
encountersCount: dungeon.encounters?.length || 0,
encounters: dungeon.encounters?.map((e, i) => ({ index: i, type: e.type, name: e.name }))
});
// Validate requirements
if (playerIds.length > dungeon.maxPlayers) {
throw new Error('Too many players for this dungeon');
}
const instanceId = `instance_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
const instance = {
id: instanceId,
dungeonId,
creatorId,
players: new Set([creatorId, ...playerIds]),
currentEncounter: 0,
status: 'active',
startedAt: new Date().toISOString(),
completedAt: null,
progress: {},
rewards: null,
deaths: new Map() // userId -> death count
};
// Initialize progress tracking
dungeon.encounters.forEach((encounter, index) => {
instance.progress[index] = {
completed: false,
attempts: 0,
deaths: 0
};
});
this.instances.set(instanceId, instance);
// Track player instances
for (const playerId of instance.players) {
this.playerInstances.set(playerId, instanceId);
}
return instance;
}
getInstance(instanceId) {
return this.instances.get(instanceId);
}
getPlayerInstance(userId) {
const instanceId = this.playerInstances.get(userId);
return instanceId ? this.getInstance(instanceId) : null;
}
joinInstance(instanceId, userId) {
const instance = this.getInstance(instanceId);
if (!instance) {
throw new Error('Instance not found');
}
if (instance.status !== 'active') {
throw new Error('Instance is not active');
}
const dungeon = this.getDungeon(instance.dungeonId);
if (instance.players.size >= dungeon.maxPlayers) {
throw new Error('Instance is full');
}
// Remove from existing instance if any
const existingInstanceId = this.playerInstances.get(userId);
if (existingInstanceId) {
this.leaveInstance(userId);
}
// Add to new instance
instance.players.add(userId);
this.playerInstances.set(userId, instanceId);
return instance;
}
leaveInstance(userId) {
const instanceId = this.playerInstances.get(userId);
if (!instanceId) {
return null;
}
const instance = this.getInstance(instanceId);
if (instance) {
instance.players.delete(userId);
// If instance is empty, clean it up
if (instance.players.size === 0) {
this.instances.delete(instanceId);
}
}
this.playerInstances.delete(userId);
return instance;
}
startEncounter(instanceId, userId) {
const instance = this.getInstance(instanceId);
if (!instance) {
throw new Error('Instance not found');
}
if (!instance.players.has(userId)) {
throw new Error('Player not in instance');
}
const dungeon = this.getDungeon(instance.dungeonId);
const encounter = dungeon.encounters[instance.currentEncounter];
if (!encounter) {
throw new Error('No more encounters');
}
return {
encounter,
encounterIndex: instance.currentEncounter,
instance
};
}
completeEncounter(instanceId, userId, result) {
const instance = this.getInstance(instanceId);
if (!instance) {
throw new Error('Instance not found');
}
const dungeon = this.getDungeon(instance.dungeonId);
const encounter = dungeon.encounters[instance.currentEncounter];
if (!encounter) {
throw new Error('No encounter to complete');
}
const progress = instance.progress[instance.currentEncounter];
progress.completed = true;
progress.attempts++;
if (result.deaths) {
progress.deaths += result.deaths;
instance.deaths.set(userId, (instance.deaths.get(userId) || 0) + result.deaths);
}
// Move to next encounter
instance.currentEncounter++;
// Check if dungeon is complete
if (instance.currentEncounter >= dungeon.encounters.length) {
return this.completeDungeon(instanceId);
}
return {
success: true,
nextEncounter: instance.currentEncounter < dungeon.encounters.length ? dungeon.encounters[instance.currentEncounter] : null,
encounterIndex: instance.currentEncounter,
instance
};
}
completeDungeon(instanceId) {
const instance = this.getInstance(instanceId);
if (!instance) {
throw new Error('Instance not found');
}
const dungeon = this.getDungeon(instance.dungeonId);
// Calculate rewards
const rewards = this.calculateRewards(dungeon, instance);
// Mark as completed
instance.status = 'completed';
instance.completedAt = new Date().toISOString();
instance.rewards = rewards;
// Remove players from instance tracking
for (const playerId of instance.players) {
this.playerInstances.delete(playerId);
// Check for quest completion
this.checkQuestCompletion(playerId, instance.dungeonId);
}
return {
success: true,
dungeon,
rewards,
instance,
encounterIndex: -1, // Dungeon complete
isComplete: true
};
}
// Check if dungeon completion should trigger quests
checkQuestCompletion(userId, dungeonId) {
// Tutorial dungeon completion should trigger main story progression
if (dungeonId === 'tutorial') {
console.log('[DUNGEON SYSTEM] Tutorial dungeon completed, triggering quest progression');
// Set player stat for tutorial completion
if (this.io) {
this.io.emit('player_stat_update', {
userId: userId,
stat: 'tutorialDungeonCompleted',
value: true
});
// Emit quest completion event for quest system
this.io.emit('quest_completed', {
userId: userId,
questId: 'main_story_first_dungeon',
questType: 'dungeon',
dungeonId: dungeonId,
rewards: {
experience: 50,
credits: 25
}
});
}
}
}
getPlayerCompletedDungeons(userId) {
const instances = Array.from(this.instances.values()).filter(instance =>
instance.players.has(userId) && instance.status === 'completed'
);
return instances.map(instance => instance.dungeonId);
}
calculateRewards(dungeon, instance) {
const rewards = {
experience: 0,
credits: 0,
items: []
};
// Check if dungeon has rewards defined
if (!dungeon.rewards) {
console.warn('[DUNGEON SYSTEM] No rewards defined for dungeon:', dungeon.id);
return rewards;
}
// Calculate base rewards
const expRange = dungeon.rewards.experience;
const creditRange = dungeon.rewards.credits;
if (!expRange || !creditRange) {
console.warn('[DUNGEON SYSTEM] Incomplete rewards defined for dungeon:', dungeon.id);
return rewards;
}
rewards.experience = Math.floor(Math.random() * (expRange.max - expRange.min + 1)) + expRange.min;
rewards.credits = Math.floor(Math.random() * (creditRange.max - creditRange.min + 1)) + creditRange.min;
// Add death penalty
const totalDeaths = Array.from(instance.deaths.values()).reduce((sum, deaths) => sum + deaths, 0);
const deathPenalty = Math.floor(totalDeaths * 0.1); // 10% penalty per death
rewards.experience = Math.max(0, rewards.experience - deathPenalty);
rewards.credits = Math.max(0, rewards.credits - (deathPenalty * 2));
// Add items (chance based on performance)
const itemChance = Math.max(0.1, 0.5 - (totalDeaths * 0.1)); // Lower chance with more deaths
if (Math.random() < itemChance) {
const itemPool = dungeon.rewards.items;
if (itemPool && itemPool.length > 0) {
rewards.items.push(itemPool[Math.floor(Math.random() * itemPool.length)]);
}
}
return rewards;
}
getAvailableDungeons(playerLevel, playerCount = 1) {
return Array.from(this.dungeons.values()).filter(dungeon =>
dungeon.minLevel <= playerLevel &&
dungeon.maxLevel >= playerLevel &&
dungeon.maxPlayers >= playerCount
);
}
moveToNextRoom(instanceId, userId) {
console.log('[DUNGEON SYSTEM] moveToNextRoom called:', { instanceId, userId });
const instance = this.getInstance(instanceId);
if (!instance) {
throw new Error('Instance not found');
}
if (!instance.players.has(userId)) {
throw new Error('Player not in instance');
}
const dungeon = this.getDungeon(instance.dungeonId);
console.log('[DUNGEON SYSTEM] Current state:', {
currentEncounter: instance.currentEncounter,
totalEncounters: dungeon.encounters.length,
dungeonId: dungeon.id
});
// Move to next encounter
instance.currentEncounter++;
console.log('[DUNGEON SYSTEM] After increment:', {
newEncounter: instance.currentEncounter,
isComplete: instance.currentEncounter >= dungeon.encounters.length
});
// Check if dungeon is complete
if (instance.currentEncounter >= dungeon.encounters.length) {
return this.completeDungeon(instanceId);
}
// Get next encounter
const encounter = dungeon.encounters[instance.currentEncounter];
console.log('[DUNGEON SYSTEM] Next encounter:', {
encounterIndex: instance.currentEncounter,
encounterType: encounter.type,
encounterName: encounter.name,
enemies: encounter.enemies
});
return {
success: true,
encounter,
encounterIndex: instance.currentEncounter,
instance,
isComplete: false
};
}
getDungeonStatistics(userId) {
const instances = Array.from(this.instances.values()).filter(instance =>
instance.players.has(userId)
);
const completed = instances.filter(instance => instance.status === 'completed');
const active = instances.filter(instance => instance.status === 'active');
return {
totalDungeons: instances.length,
completedDungeons: completed.length,
activeDungeons: active.length,
totalDeaths: Array.from(this.playerInstances.values()).length,
recentCompletions: completed.slice(-5).map(instance => ({
dungeonId: instance.dungeonId,
completedAt: instance.completedAt,
rewards: instance.rewards
}))
};
}
cleanupExpiredInstances() {
const now = Date.now();
const expiredInstances = [];
for (const [instanceId, instance] of this.instances) {
const age = now - new Date(instance.startedAt).getTime();
const maxAge = 2 * 60 * 60 * 1000; // 2 hours
if (age > maxAge && instance.status === 'active') {
expiredInstances.push(instanceId);
}
}
// Clean up expired instances
for (const instanceId of expiredInstances) {
const instance = this.instances.get(instanceId);
if (instance) {
for (const playerId of instance.players) {
this.playerInstances.delete(playerId);
}
this.instances.delete(instanceId);
}
}
return expiredInstances.length;
}
}
module.exports = DungeonSystem;