1978 lines
69 KiB
JavaScript
1978 lines
69 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Dungeon System
|
|
* Manages procedural dungeon generation and exploration
|
|
*/
|
|
|
|
class DungeonSystem {
|
|
constructor(gameEngine) {
|
|
this.game = gameEngine;
|
|
|
|
// Dungeon configuration
|
|
this.dungeonTypes = {
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
|
|
// NEW DUNGEONS - Space Theme
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
|
|
// NEW DUNGEONS - Planet Theme
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
|
|
// NEW DUNGEONS - Technology Theme
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
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
|
|
},
|
|
|
|
// NEW DUNGEONS - Biome/Elemental Theme
|
|
crystal_caves: {
|
|
name: 'Crystal Caves',
|
|
description: 'Caves filled with energy-infused crystals',
|
|
difficulty: 'medium',
|
|
enemyTypes: ['crystal_golem', 'shard_elemental', 'resonance_beast'],
|
|
rewardMultiplier: 1.4,
|
|
healthType: 'player',
|
|
energyCost: 22
|
|
},
|
|
toxic_wastes: {
|
|
name: 'Toxic Wastes',
|
|
description: 'Polluted wasteland filled with mutated creatures',
|
|
difficulty: 'hard',
|
|
enemyTypes: ['mutant_horror', 'toxic_slime', 'radiation_beast'],
|
|
rewardMultiplier: 1.7,
|
|
healthType: 'player',
|
|
energyCost: 27
|
|
},
|
|
shadow_realm: {
|
|
name: 'Shadow Realm',
|
|
description: 'Dark dimension inhabited by shadow creatures',
|
|
difficulty: 'extreme',
|
|
enemyTypes: ['shadow_demon', 'nightmare_stalker', 'void_walker'],
|
|
rewardMultiplier: 2.2,
|
|
healthType: 'player',
|
|
energyCost: 36
|
|
},
|
|
time_anomaly: {
|
|
name: 'Time Anomaly',
|
|
description: 'Area where time flows unpredictably',
|
|
difficulty: 'extreme',
|
|
enemyTypes: ['temporal_paradox', 'future_soldier', 'past_guardian'],
|
|
rewardMultiplier: 2.4,
|
|
healthType: 'player',
|
|
energyCost: 40
|
|
},
|
|
|
|
// NEW DUNGEONS - Military/War Theme
|
|
war_zone: {
|
|
name: 'Active War Zone',
|
|
description: 'Battlefield with ongoing combat operations',
|
|
difficulty: 'hard',
|
|
enemyTypes: ['enemy_soldier', 'combat_drone', 'field_commander'],
|
|
rewardMultiplier: 1.8,
|
|
healthType: 'player',
|
|
energyCost: 29
|
|
},
|
|
military_base: {
|
|
name: 'Abandoned Military Base',
|
|
description: 'Former military installation with automated defenses',
|
|
difficulty: 'medium',
|
|
enemyTypes: ['turret_system', 'combat_android', 'base_commander'],
|
|
rewardMultiplier: 1.5,
|
|
healthType: 'player',
|
|
energyCost: 24
|
|
},
|
|
weapons_testing: {
|
|
name: 'Weapons Testing Facility',
|
|
description: 'Secret facility testing advanced weaponry',
|
|
difficulty: 'hard',
|
|
enemyTypes: ['weapon_drone', 'test_subject', 'chief_scientist'],
|
|
rewardMultiplier: 1.9,
|
|
healthType: 'player',
|
|
energyCost: 31
|
|
},
|
|
|
|
// NEW DUNGEONS - Special/Unique Theme
|
|
dream_scape: {
|
|
name: 'Dream Scape',
|
|
description: 'Surreal landscape shaped by collective dreams',
|
|
difficulty: 'medium',
|
|
enemyTypes: ['nightmare_creature', 'dream_guardian', 'subconscious_demon'],
|
|
rewardMultiplier: 1.6,
|
|
healthType: 'player',
|
|
energyCost: 26
|
|
},
|
|
memory_palace: {
|
|
name: 'Memory Palace',
|
|
description: 'Mental realm storing forgotten memories',
|
|
difficulty: 'hard',
|
|
enemyTypes: ['memory_fragment', 'forgetfulness_demon', 'nostalgia_spirit'],
|
|
rewardMultiplier: 1.7,
|
|
healthType: 'player',
|
|
energyCost: 28
|
|
},
|
|
dimension_rift: {
|
|
name: 'Dimension Rift',
|
|
description: 'Tear between dimensions with interdimensional invaders',
|
|
difficulty: 'extreme',
|
|
enemyTypes: ['rift_demon', 'dimensional_hunter', 'reality_tear'],
|
|
rewardMultiplier: 2.6,
|
|
healthType: 'player',
|
|
energyCost: 42
|
|
}
|
|
};
|
|
|
|
// Current dungeon state
|
|
this.currentDungeon = null;
|
|
this.currentRoom = null;
|
|
this.dungeonProgress = 0;
|
|
this.isExploring = false;
|
|
|
|
// Dungeon 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 }
|
|
};
|
|
|
|
// 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
|
|
}
|
|
};
|
|
|
|
// Statistics
|
|
this.stats = {
|
|
dungeonsAttempted: 0,
|
|
dungeonsCompleted: 0,
|
|
totalEnemiesDefeated: 0,
|
|
bestTime: Infinity,
|
|
totalLootEarned: 0
|
|
};
|
|
}
|
|
|
|
async initialize() {
|
|
this.generateDungeonList();
|
|
}
|
|
|
|
generateDungeonList() {
|
|
|
|
const dungeonListElement = document.getElementById('dungeonList');
|
|
if (!dungeonListElement) {
|
|
console.error('Dungeon list element not found!');
|
|
return;
|
|
}
|
|
|
|
// Clear existing list
|
|
dungeonListElement.innerHTML = '';
|
|
|
|
const questSystem = this.game.systems.questSystem;
|
|
const firstStepsQuest = questSystem ? questSystem.findQuest('tutorial_complete') : null;
|
|
const showTutorialDungeon = firstStepsQuest && firstStepsQuest.status === 'active';
|
|
|
|
Object.entries(this.dungeonTypes).forEach(([key, dungeon]) => {
|
|
// Skip tutorial dungeon unless First Steps quest is active
|
|
if (key === 'tutorial' && !showTutorialDungeon) {
|
|
return;
|
|
}
|
|
|
|
const dungeonElement = document.createElement('div');
|
|
dungeonElement.className = 'dungeon-item';
|
|
dungeonElement.dataset.dungeonType = key;
|
|
|
|
// Check if tutorial dungeon is completed
|
|
const isCompleted = key === 'tutorial' && this.game.systems.player.stats.tutorialDungeonCompleted;
|
|
const statusClass = isCompleted ? 'completed' : '';
|
|
const statusText = isCompleted ? 'COMPLETED' : '';
|
|
|
|
dungeonElement.innerHTML = `
|
|
<div class="dungeon-name">${dungeon.name}</div>
|
|
<div class="dungeon-difficulty ${dungeon.difficulty}">${dungeon.difficulty.toUpperCase()}</div>
|
|
${statusText ? `<div class="dungeon-status ${statusClass}">${statusText}</div>` : ''}
|
|
<div class="dungeon-description">${dungeon.description}</div>
|
|
<div class="dungeon-rewards">Rewards: ${dungeon.rewardMultiplier}x</div>
|
|
<div class="dungeon-cost">Energy Cost: ${dungeon.energyCost || this.getEnergyCost(key)}</div>
|
|
`;
|
|
|
|
dungeonElement.addEventListener('click', () => {
|
|
if (isCompleted) {
|
|
this.game.showNotification('Tutorial dungeon has already been completed!', 'warning', 3000);
|
|
} else {
|
|
this.selectDungeon(key);
|
|
}
|
|
});
|
|
|
|
dungeonListElement.appendChild(dungeonElement);
|
|
});
|
|
|
|
}
|
|
|
|
selectDungeon(type) {
|
|
|
|
// Check energy cost
|
|
const energyCost = this.getEnergyCost(type);
|
|
const player = this.game.systems.player;
|
|
|
|
|
|
if (!player.useEnergy(energyCost)) {
|
|
this.game.showNotification(`Not enough energy! Need ${energyCost} energy`, 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
|
|
// Ensure we're on the Dungeons tab so the user can see the dungeon
|
|
if (this.game.ui && this.game.ui.currentTab !== 'dungeons') {
|
|
this.game.ui.switchTab('dungeons');
|
|
}
|
|
|
|
// Remove previous selection
|
|
document.querySelectorAll('.dungeon-item').forEach(item => {
|
|
item.classList.remove('selected');
|
|
});
|
|
|
|
// Add selection to clicked dungeon
|
|
const selectedElement = document.querySelector(`[data-dungeon-type="${type}"]`);
|
|
if (selectedElement) {
|
|
selectedElement.classList.add('selected');
|
|
}
|
|
|
|
|
|
// Generate dungeon
|
|
this.generateDungeon(type);
|
|
this.displayDungeon();
|
|
|
|
|
|
this.game.showNotification(`Entered dungeon! -${energyCost} energy`, 'info', 3000);
|
|
}
|
|
|
|
getEnergyCost(type) {
|
|
const costs = {
|
|
tutorial: 0,
|
|
alien_ruins: 20,
|
|
pirate_lair: 15,
|
|
corrupted_vault: 25,
|
|
asteroid_mine: 10,
|
|
nebula_anomaly: 30
|
|
};
|
|
return costs[type] || 15;
|
|
}
|
|
|
|
calculateDungeonRewards(type, difficulty) {
|
|
const dungeonTemplate = this.dungeonTypes[type];
|
|
const baseRewards = {
|
|
credits: 50,
|
|
experience: 25,
|
|
items: []
|
|
};
|
|
|
|
// Apply difficulty multiplier
|
|
const difficultyMultipliers = {
|
|
tutorial: 0.5,
|
|
easy: 1.0,
|
|
medium: 1.5,
|
|
hard: 2.0
|
|
};
|
|
|
|
const multiplier = difficultyMultipliers[difficulty] || 1.0;
|
|
const rewardMultiplier = dungeonTemplate.rewardMultiplier || 1.0;
|
|
|
|
baseRewards.credits = Math.floor(baseRewards.credits * multiplier * rewardMultiplier);
|
|
baseRewards.experience = Math.floor(baseRewards.experience * multiplier * rewardMultiplier);
|
|
|
|
return baseRewards;
|
|
}
|
|
|
|
generateDungeon(type) {
|
|
|
|
const dungeonTemplate = this.dungeonTypes[type];
|
|
|
|
// Check if tutorial dungeon has already been completed
|
|
if (type === 'tutorial' && this.game.systems.player.stats.tutorialDungeonCompleted) {
|
|
this.game.showNotification('Tutorial dungeon has already been completed!', 'warning', 3000);
|
|
return;
|
|
}
|
|
|
|
|
|
this.currentDungeon = {
|
|
type: type,
|
|
name: dungeonTemplate.name,
|
|
description: dungeonTemplate.description,
|
|
difficulty: dungeonTemplate.difficulty,
|
|
healthType: dungeonTemplate.healthType,
|
|
enemyTypes: dungeonTemplate.enemyTypes,
|
|
rewardMultiplier: dungeonTemplate.rewardMultiplier,
|
|
rooms: [],
|
|
currentRoomIndex: 0,
|
|
startTime: Date.now(),
|
|
completed: false
|
|
};
|
|
|
|
|
|
// Generate rooms - ensure minimum of 3 rooms (entrance, at least 1 middle, boss)
|
|
const roomCount = Math.max(3, this.game.getRandomInt(5, 8));
|
|
this.currentDungeon.rooms = this.generateRoomLayout(roomCount, dungeonTemplate);
|
|
|
|
// Set current room
|
|
this.currentRoom = this.currentDungeon.rooms[0];
|
|
this.dungeonProgress = 0;
|
|
|
|
|
|
// Show dungeon view and hide list
|
|
this.showDungeonView();
|
|
|
|
}
|
|
|
|
generateRoomLayout(roomCount, dungeonTemplate) {
|
|
const rooms = [];
|
|
|
|
|
|
// Always start with entrance
|
|
rooms.push(this.createRoom('entrance', dungeonTemplate));
|
|
|
|
// Generate middle rooms (subtract 2 for entrance and boss room)
|
|
const middleRoomCount = roomCount - 2;
|
|
|
|
for (let i = 0; i < middleRoomCount; i++) {
|
|
const roomType = this.getRandomRoomType();
|
|
const room = this.createRoom(roomType, dungeonTemplate);
|
|
rooms.push(room);
|
|
}
|
|
|
|
// Always end with boss room (exit is handled by completing the boss room)
|
|
rooms.push(this.createRoom('boss', dungeonTemplate));
|
|
|
|
|
|
// Verify room accessibility
|
|
for (let i = 0; i < rooms.length; i++) {
|
|
}
|
|
|
|
return rooms;
|
|
}
|
|
|
|
getRandomRoomType() {
|
|
const weights = {
|
|
corridor: 40,
|
|
chamber: 30,
|
|
treasure: 0, // Temporarily disabled
|
|
entrance: 5,
|
|
boss: 5,
|
|
exit: 0
|
|
};
|
|
|
|
const totalWeight = Object.values(weights).reduce((sum, weight) => sum + weight, 0);
|
|
let random = Math.random() * totalWeight;
|
|
|
|
for (const [type, weight] of Object.entries(weights)) {
|
|
random -= weight;
|
|
if (random <= 0) {
|
|
return type;
|
|
}
|
|
}
|
|
|
|
return 'corridor';
|
|
}
|
|
|
|
createRoom(roomType, dungeonTemplate) {
|
|
const template = this.roomTypes[roomType];
|
|
const room = {
|
|
type: roomType,
|
|
name: template.name,
|
|
enemies: [],
|
|
rewards: null,
|
|
explored: false,
|
|
completed: false
|
|
};
|
|
|
|
// Generate enemies
|
|
if (template.enemies > 0) {
|
|
for (let i = 0; i < template.enemies; i++) {
|
|
const enemyType = dungeonTemplate.enemyTypes[
|
|
Math.floor(Math.random() * dungeonTemplate.enemyTypes.length)
|
|
];
|
|
room.enemies.push(this.createEnemy(enemyType, template.isBoss));
|
|
}
|
|
}
|
|
|
|
// Generate rewards
|
|
if (template.rewards) {
|
|
room.rewards = this.generateRoomRewards(dungeonTemplate.difficulty, template.isBoss);
|
|
}
|
|
|
|
return room;
|
|
}
|
|
|
|
createEnemy(enemyType, isBoss = false) {
|
|
const template = this.enemyTemplates[enemyType];
|
|
const bossMultiplier = isBoss ? 2.5 : 1.0;
|
|
|
|
return {
|
|
id: Date.now() + Math.random().toString(36).substr(2, 9),
|
|
type: enemyType,
|
|
name: isBoss ? `Boss ${template.name}` : template.name,
|
|
health: Math.floor(template.health * bossMultiplier),
|
|
maxHealth: Math.floor(template.health * bossMultiplier),
|
|
attack: Math.floor(template.attack * bossMultiplier),
|
|
defense: Math.floor(template.defense * bossMultiplier),
|
|
experience: Math.floor(template.experience * bossMultiplier),
|
|
credits: Math.floor(template.credits * bossMultiplier),
|
|
isBoss: isBoss
|
|
};
|
|
}
|
|
|
|
generateRoomRewards(difficulty, isBoss = false) {
|
|
const baseRewards = this.game.systems.economy.generateRewards(difficulty, 'dungeon');
|
|
const multiplier = isBoss ? 2.0 : 1.0;
|
|
|
|
const rewards = {
|
|
credits: Math.floor(baseRewards.credits * multiplier),
|
|
experience: Math.floor(baseRewards.experience * multiplier),
|
|
materials: []
|
|
};
|
|
|
|
// Add crafting materials based on chance and difficulty
|
|
const materialChance = isBoss ? 0.9 : 0.4;
|
|
if (Math.random() < materialChance) {
|
|
const materialCount = isBoss ? this.game.getRandomInt(3, 6) : this.game.getRandomInt(1, 3);
|
|
|
|
// Define material pools with weights for better balance
|
|
const materialPools = {
|
|
tutorial: [
|
|
{ id: 'iron_ore', weight: 40 },
|
|
{ id: 'copper_wire', weight: 30 },
|
|
{ id: 'herbs', weight: 20 },
|
|
{ id: 'bandages', weight: 10 }
|
|
],
|
|
easy: [
|
|
{ id: 'iron_ore', weight: 30 },
|
|
{ id: 'copper_wire', weight: 25 },
|
|
{ id: 'energy_crystal', weight: 15 },
|
|
{ id: 'leather', weight: 15 },
|
|
{ id: 'herbs', weight: 10 },
|
|
{ id: 'bandages', weight: 5 }
|
|
],
|
|
medium: [
|
|
{ id: 'iron_ore', weight: 25 },
|
|
{ id: 'steel_plate', weight: 20 },
|
|
{ id: 'energy_crystal', weight: 20 },
|
|
{ id: 'copper_wire', weight: 15 },
|
|
{ id: 'rare_metal', weight: 5 },
|
|
{ id: 'bandages', weight: 15 }
|
|
],
|
|
hard: [
|
|
{ id: 'steel_plate', weight: 30 },
|
|
{ id: 'energy_crystal', weight: 25 },
|
|
{ id: 'rare_metal', weight: 15 },
|
|
{ id: 'battery', weight: 20 },
|
|
{ id: 'bandages', weight: 10 }
|
|
],
|
|
extreme: [
|
|
{ id: 'rare_metal', weight: 30 },
|
|
{ id: 'energy_crystal', weight: 25 },
|
|
{ id: 'battery', weight: 25 },
|
|
{ id: 'advanced_components', weight: 20 }
|
|
]
|
|
};
|
|
|
|
const pool = materialPools[difficulty] || materialPools.easy;
|
|
|
|
// Helper function to get weighted random material
|
|
function getWeightedRandomMaterial(materialPool) {
|
|
const totalWeight = materialPool.reduce((sum, mat) => sum + mat.weight, 0);
|
|
let random = Math.random() * totalWeight;
|
|
|
|
for (const material of materialPool) {
|
|
random -= material.weight;
|
|
if (random <= 0) {
|
|
return material.id;
|
|
}
|
|
}
|
|
return materialPool[0].id; // Fallback
|
|
}
|
|
|
|
for (let i = 0; i < materialCount; i++) {
|
|
const material = getWeightedRandomMaterial(pool);
|
|
const quantity = this.game.getRandomInt(1, isBoss ? 3 : 2);
|
|
|
|
rewards.materials.push({
|
|
id: material,
|
|
quantity: quantity
|
|
});
|
|
}
|
|
}
|
|
|
|
return rewards;
|
|
}
|
|
|
|
displayDungeon() {
|
|
|
|
const dungeonViewElement = document.getElementById('dungeonView');
|
|
|
|
if (!dungeonViewElement) {
|
|
const allElements = document.querySelectorAll('[id*="dungeon"]');
|
|
return;
|
|
}
|
|
|
|
if (!this.currentDungeon) {
|
|
return;
|
|
}
|
|
|
|
const room = this.currentRoom;
|
|
if (room) {
|
|
// Room exists, continue processing
|
|
}
|
|
|
|
const progress = Math.floor((this.currentDungeon.currentRoomIndex / this.currentDungeon.rooms.length) * 100);
|
|
|
|
|
|
let content = `
|
|
<div class="dungeon-display">
|
|
<div class="dungeon-header">
|
|
<h2>${this.currentDungeon.name}</h2>
|
|
<div class="dungeon-progress">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${progress}%"></div>
|
|
</div>
|
|
<span>Room ${this.currentDungeon.currentRoomIndex + 1} / ${this.currentDungeon.rooms.length}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="health-status">
|
|
${this.getHealthDisplay()}
|
|
</div>
|
|
|
|
<div class="current-room">
|
|
<h3>${room.name}</h3>
|
|
${this.getRoomDescription(room)}
|
|
</div>
|
|
|
|
<div class="room-content">
|
|
${this.getRoomContent(room)}
|
|
</div>
|
|
|
|
<div class="room-actions">
|
|
${this.getRoomActions(room)}
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
|
|
dungeonViewElement.innerHTML = content;
|
|
|
|
|
|
// Only add event listeners for buttons that don't use inline onclick handlers
|
|
const completeDungeonBtn = dungeonViewElement.querySelector('button[onclick*="completeDungeon"]');
|
|
if (completeDungeonBtn) {
|
|
completeDungeonBtn.addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
this.completeDungeon();
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
getHealthDisplay() {
|
|
const player = this.game.systems.player;
|
|
const healthType = this.currentDungeon.healthType;
|
|
|
|
|
|
if (healthType === 'ship') {
|
|
const shipHealth = player.ship.health || 0;
|
|
const shipMaxHealth = player.ship.maxHealth || 1000;
|
|
const healthPercent = Math.round((shipHealth / shipMaxHealth) * 100);
|
|
return `
|
|
<div class="health-bar ship-health">
|
|
<div class="health-label">Ship Health</div>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill ship-health-fill" style="width: ${healthPercent}%"></div>
|
|
</div>
|
|
<span>${shipHealth} / ${shipMaxHealth}</span>
|
|
</div>
|
|
`;
|
|
} else {
|
|
const playerHealth = player.attributes.health || 0;
|
|
const playerMaxHealth = player.attributes.maxHealth || 100;
|
|
const healthPercent = Math.round((playerHealth / playerMaxHealth) * 100);
|
|
return `
|
|
<div class="health-bar player-health">
|
|
<div class="health-label">Player Health</div>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill player-health-fill" style="width: ${healthPercent}%"></div>
|
|
</div>
|
|
<span>${playerHealth} / ${playerMaxHealth}</span>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
getRoomDescription(room) {
|
|
const descriptions = {
|
|
entrance: 'You enter the dungeon. The air is thick with anticipation.',
|
|
corridor: 'A narrow corridor stretches ahead. You can hear distant sounds.',
|
|
chamber: 'You enter a large chamber. The echoes of past battles linger here.',
|
|
treasure: 'Golden light glimmers from piles of treasure in this room.',
|
|
boss: 'A massive presence fills the room. This is the guardian of this dungeon.',
|
|
exit: 'You can see the exit. Freedom awaits!'
|
|
};
|
|
|
|
return `<p class="room-description">${descriptions[room.type] || 'You continue exploring...'}</p>`;
|
|
}
|
|
|
|
getRoomContent(room) {
|
|
if (room.completed) {
|
|
return '<p class="room-completed">This room has been cleared.</p>';
|
|
}
|
|
|
|
if (room.enemies.length > 0) {
|
|
const enemiesHtml = room.enemies.map(enemy => `
|
|
<div class="enemy ${enemy.isBoss ? 'boss' : ''}">
|
|
<div class="enemy-name">${enemy.name}</div>
|
|
<div class="enemy-health">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${(enemy.health / enemy.maxHealth) * 100}%"></div>
|
|
</div>
|
|
<span>${enemy.health} / ${enemy.maxHealth}</span>
|
|
</div>
|
|
<div class="enemy-stats">ATK: ${enemy.attack} | DEF: ${enemy.defense}</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
return `<div class="enemies">${enemiesHtml}</div>`;
|
|
}
|
|
|
|
if (room.rewards && !room.completed) {
|
|
return '<div class="treasure"><i class="fas fa-treasure-chest"></i> <p>Treasure awaits!</p></div>';
|
|
}
|
|
|
|
return '<p>The room is empty and quiet.</p>';
|
|
}
|
|
|
|
getRoomActions(room) {
|
|
|
|
if (room.completed) {
|
|
if (this.currentDungeon.currentRoomIndex < this.currentDungeon.rooms.length - 1) {
|
|
return '<button class="btn btn-primary" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.nextRoom(); else { console.error(\'Game not available for nextRoom\'); } } catch(e) { console.error(\'Next room button error:\', e); }">Continue to Next Room</button>';
|
|
} else {
|
|
return '<button class="btn btn-success" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.completeDungeon(); else { console.error(\'Game not available for completeDungeon\'); } } catch(e) { console.error(\'Complete dungeon button error:\', e); }">Complete Dungeon</button>';
|
|
}
|
|
}
|
|
|
|
if (room.enemies.length > 0) {
|
|
const buttonHtml = '<button class="btn btn-danger" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.startCombat(); else { console.error(\'Game not available, retrying...\'); setTimeout(() => { if(window.game && window.game.systems) window.game.systems.dungeonSystem.startCombat(); }, 100); } } catch(e) { console.error(\'Combat button error:\', e); }">Start Combat</button>';
|
|
return buttonHtml;
|
|
}
|
|
|
|
if (room.rewards) {
|
|
return '<button class="btn btn-success" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.claimRewards();} else { console.error(\'Game not available for claimRewards\'); } } catch(e) { console.error(\'Claim rewards button error:\', e); }">Claim Rewards</button>';
|
|
}
|
|
|
|
// Check if this is the final room
|
|
if (this.currentDungeon.currentRoomIndex >= this.currentDungeon.rooms.length - 1) {
|
|
return '<button class="btn btn-success" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.completeDungeon(); else { console.error(\'Game not available for completeDungeon\'); } } catch(e) { console.error(\'Complete dungeon button error:\', e); }">Complete Dungeon</button>';
|
|
}
|
|
|
|
return '<button class="btn btn-primary" onclick="try { if(window.game && window.game.systems) window.game.systems.dungeonSystem.nextRoom(); else { console.error(\'Game not available for nextRoom\'); alert(\'Game not ready. Please try again.\'); } } catch(e) { console.error(\'Move forward button error:\', e); alert(\'Error moving forward. Please try again.\'); }">Move Forward</button>';
|
|
}
|
|
async startCombat() {
|
|
|
|
if (this.isExploring) {
|
|
return;
|
|
}
|
|
|
|
this.isExploring = true;
|
|
const room = this.currentRoom;
|
|
const enemies = room.enemies.filter(e => e.health > 0);
|
|
|
|
|
|
if (enemies.length === 0) {
|
|
this.completeRoom();
|
|
return;
|
|
}
|
|
|
|
// Simulate combat
|
|
await this.simulateCombat(enemies);
|
|
}
|
|
|
|
async simulateCombat(enemies) {
|
|
|
|
try {
|
|
const player = this.game.systems.player;
|
|
|
|
const healthType = this.currentDungeon.healthType;
|
|
|
|
let combatLog = [];
|
|
|
|
// Handle case where there are no enemies
|
|
if (enemies.length === 0) {
|
|
combatLog.push('Room was empty - no enemies found');
|
|
this.completeRoom();
|
|
return;
|
|
}
|
|
|
|
for (const [index, enemy] of enemies.entries()) {
|
|
|
|
// Player attacks
|
|
const playerDamage = player.calculateDamage(this.currentDungeon.difficulty);
|
|
|
|
const actualDamage = Math.max(1, playerDamage.damage - enemy.defense);
|
|
enemy.health = Math.max(0, enemy.health - actualDamage);
|
|
|
|
combatLog.push(`You dealt ${actualDamage} damage to ${enemy.name}${playerDamage.isCritical ? ' (CRITICAL!)' : ''}`);
|
|
|
|
// Update UI after player attack to show enemy health change
|
|
this.displayDungeon();
|
|
// Also update global player UI to ensure health bars are updated
|
|
if (player.updateUI) {
|
|
player.updateUI();
|
|
}
|
|
|
|
// Small delay to make the combat visible
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// Enemy attacks if still alive
|
|
if (enemy.health > 0) {
|
|
let enemyDamage, damageTarget;
|
|
|
|
if (healthType === 'ship') {
|
|
// Space missions: higher damage, target ship health
|
|
enemyDamage = Math.max(1, Math.floor(enemy.attack * 1.5) - player.ship.defense);
|
|
damageTarget = 'ship';
|
|
this.applyShipDamage(enemyDamage);
|
|
combatLog.push(`${enemy.name} dealt ${enemyDamage} damage to your ship`);
|
|
} else {
|
|
// Ground missions: normal damage, target player health
|
|
enemyDamage = Math.max(1, enemy.attack - player.attributes.defense);
|
|
damageTarget = 'player';
|
|
player.takeDamage(enemyDamage);
|
|
combatLog.push(`${enemy.name} dealt ${enemyDamage} damage to you`);
|
|
}
|
|
|
|
// Update UI after enemy attack to show player health change
|
|
this.displayDungeon();
|
|
// Also update global player UI to ensure health bars are updated
|
|
if (player.updateUI) {
|
|
player.updateUI();
|
|
}
|
|
|
|
// Small delay to make the combat visible
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
|
// Check for destruction
|
|
if (healthType === 'ship' && player.ship.health <= 0) {
|
|
this.handleShipDestruction();
|
|
} else if (healthType === 'player' && player.attributes.health <= 0) {
|
|
this.handlePlayerDefeat();
|
|
}
|
|
} else {
|
|
// Enemy defeated
|
|
player.addExperience(enemy.experience);
|
|
this.game.systems.economy.addCredits(enemy.credits, 'dungeon');
|
|
player.incrementKills();
|
|
this.stats.totalEnemiesDefeated++;
|
|
|
|
// Update quest progress for combat objectives
|
|
if (this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.onEnemyDefeated();
|
|
}
|
|
|
|
combatLog.push(`${enemy.name} defeated! +${enemy.experience} XP, +${enemy.credits} credits`);
|
|
|
|
// Update UI after enemy defeat
|
|
this.displayDungeon();
|
|
// Also update global player UI to ensure health bars are updated
|
|
if (player.updateUI) {
|
|
player.updateUI();
|
|
}
|
|
|
|
// Small delay to make the combat visible
|
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
}
|
|
}
|
|
|
|
// Show combat results
|
|
this.game.showNotification('Combat completed!', 'success', 3000);
|
|
combatLog.forEach(message => this.game.showNotification(message, 'info', 2000));
|
|
|
|
// Check if all enemies defeated
|
|
const remainingEnemies = this.currentRoom.enemies.filter(e => e.health > 0);
|
|
if (remainingEnemies.length === 0) {
|
|
this.completeRoom();
|
|
}
|
|
|
|
this.isExploring = false;
|
|
this.displayDungeon();
|
|
} catch (error) {
|
|
console.error('[DUNGEON] Error in simulateCombat:', error);
|
|
console.error('[DUNGEON] Error stack:', error.stack);
|
|
this.isExploring = false;
|
|
}
|
|
}
|
|
|
|
// Health system methods
|
|
applyShipDamage(amount) {
|
|
const player = this.game.systems.player;
|
|
player.ship.health = Math.max(0, player.ship.health - amount);
|
|
player.updateUI();
|
|
|
|
// Check for ship destruction
|
|
if (player.ship.health <= 0) {
|
|
this.handleShipDestruction();
|
|
}
|
|
}
|
|
|
|
handleShipDestruction() {
|
|
const player = this.game.systems.player;
|
|
|
|
// Show destruction message
|
|
this.game.showNotification('Your ship has been destroyed!', 'error', 5000);
|
|
this.game.showNotification('Dungeon failed - all progress lost.', 'warning', 4000);
|
|
|
|
// Remove the current ship from inventory
|
|
if (this.game.systems.inventory) {
|
|
this.game.systems.inventory.removeItem(player.ship);
|
|
}
|
|
|
|
// Reset to a basic ship if available in inventory
|
|
const availableShips = this.game.systems.inventory.getItemsByType('ship');
|
|
if (availableShips.length > 0) {
|
|
player.ship = availableShips[0];
|
|
this.game.showNotification(`Switched to ${player.ship.name}`, 'info', 3000);
|
|
} else {
|
|
// No ships available - create a basic one
|
|
player.ship = {
|
|
name: 'Basic Fighter',
|
|
health: 1000,
|
|
maxHealth: 1000,
|
|
defense: 5,
|
|
attack: 10,
|
|
type: 'ship'
|
|
};
|
|
this.game.showNotification('No ships available - using emergency fighter', 'warning', 3000);
|
|
}
|
|
|
|
// Apply dungeon failure penalty
|
|
this.applyDungeonFailurePenalty();
|
|
|
|
// Exit dungeon
|
|
this.exitDungeon();
|
|
}
|
|
|
|
applyDungeonFailurePenalty() {
|
|
const player = this.game.systems.player;
|
|
|
|
// Lose some credits as penalty
|
|
const creditPenalty = Math.floor(this.game.systems.economy.credits * 0.1); // 10% credit loss
|
|
this.game.systems.economy.removeCredits(creditPenalty);
|
|
|
|
// Lose some experience
|
|
const expPenalty = Math.floor(player.experience * 0.05); // 5% exp loss
|
|
player.experience = Math.max(0, player.experience - expPenalty);
|
|
|
|
// Update failure statistics
|
|
this.stats.dungeonsFailed++;
|
|
|
|
this.game.showNotification(`Dungeon penalty: -${creditPenalty} credits, -${expPenalty} XP`, 'warning', 4000);
|
|
}
|
|
|
|
handlePlayerDefeat() {
|
|
this.game.showNotification('You have been defeated!', 'error', 5000);
|
|
this.game.showNotification('You\'ve been forced to retreat from the dungeon.', 'warning', 4000);
|
|
|
|
// Heal player to prevent death loop
|
|
const player = this.game.systems.player;
|
|
player.attributes.health = Math.floor(player.attributes.maxHealth * 0.5);
|
|
|
|
// Exit dungeon
|
|
this.exitDungeon();
|
|
}
|
|
|
|
exitDungeon() {
|
|
this.currentDungeon = null;
|
|
this.currentRoom = null;
|
|
this.dungeonProgress = 0;
|
|
this.isExploring = false;
|
|
|
|
// Return to main view
|
|
this.generateDungeonList();
|
|
}
|
|
|
|
claimRewards() {
|
|
const room = this.currentRoom;
|
|
if (!room.rewards || room.completed) return;
|
|
|
|
// Give all rewards including materials
|
|
this.game.systems.economy.giveRewards(room.rewards, 'dungeon');
|
|
|
|
room.rewards = null; // Remove rewards after claiming
|
|
|
|
this.game.showNotification('Rewards claimed!', 'success', 3000);
|
|
|
|
// Use the proper completeRoom method to ensure consistent behavior
|
|
this.completeRoom();
|
|
}
|
|
|
|
completeRoom() {
|
|
const room = this.currentRoom;
|
|
room.completed = true;
|
|
room.explored = true;
|
|
|
|
// Reset exploring flag when completing a room
|
|
this.isExploring = false;
|
|
|
|
|
|
// Auto-claim rewards if available
|
|
if (room.rewards) {
|
|
// Give credits and experience
|
|
this.game.systems.economy.giveRewards(room.rewards, 'dungeon');
|
|
|
|
// Add crafting materials to inventory
|
|
if (room.rewards.materials && room.rewards.materials.length > 0) {
|
|
let materialText = '';
|
|
room.rewards.materials.forEach(material => {
|
|
this.game.systems.inventory.addItem(material.id, material.quantity);
|
|
materialText += `${material.quantity}x ${material.id}, `;
|
|
});
|
|
|
|
materialText = materialText.slice(0, -2);
|
|
|
|
this.game.showNotification(`Materials found: ${materialText}`, 'success', 4000);
|
|
}
|
|
|
|
room.rewards = null;
|
|
}
|
|
|
|
this.game.showNotification(`${room.name} completed!`, 'success', 3000);
|
|
|
|
// Check if this is a boss room - if so, automatically complete the dungeon
|
|
if (room.type === 'boss') {
|
|
setTimeout(() => {
|
|
this.completeDungeon();
|
|
}, 2000); // Small delay to show the completion message first
|
|
} else {
|
|
this.displayDungeon();
|
|
}
|
|
|
|
}
|
|
|
|
nextRoom() {
|
|
|
|
// Log all rooms for debugging
|
|
this.currentDungeon.rooms.forEach((room, index) => {
|
|
});
|
|
|
|
if (this.currentDungeon.currentRoomIndex >= this.currentDungeon.rooms.length - 1) {
|
|
return;
|
|
}
|
|
|
|
const oldIndex = this.currentDungeon.currentRoomIndex;
|
|
this.currentDungeon.currentRoomIndex++;
|
|
this.currentRoom = this.currentDungeon.rooms[this.currentDungeon.currentRoomIndex];
|
|
|
|
|
|
this.displayDungeon();
|
|
}
|
|
|
|
completeDungeon() {
|
|
if (!this.currentDungeon) {
|
|
return;
|
|
}
|
|
|
|
const completionTime = Date.now() - this.currentDungeon.startTime;
|
|
const player = this.game.systems.player;
|
|
const economy = this.game.systems.economy;
|
|
|
|
// Generate proper rewards including materials
|
|
const baseRewards = this.generateRoomRewards(this.currentDungeon.difficulty, false);
|
|
|
|
// Apply time bonus
|
|
const timeBonus = Math.floor(completionTime < 300000 ? 50 : 0); // Bonus for completing in under 5 minutes
|
|
baseRewards.credits += timeBonus;
|
|
baseRewards.experience += Math.floor(timeBonus / 2);
|
|
|
|
// Give rewards
|
|
economy.giveRewards(baseRewards, 'dungeon');
|
|
player.addExperience(baseRewards.experience);
|
|
|
|
// Update statistics
|
|
this.stats.dungeonsCompleted++;
|
|
this.stats.totalTimeInDungeons += completionTime;
|
|
|
|
// Update player dungeons cleared stat
|
|
player.stats.dungeonsCleared++;
|
|
|
|
// Update quest progress for dungeon objectives
|
|
if (this.game.systems.questSystem) {
|
|
// Check if this is a tutorial dungeon
|
|
if (this.currentDungeon.type === 'tutorial') {
|
|
// Mark tutorial dungeon as completed in player stats
|
|
player.stats.tutorialDungeonCompleted = true;
|
|
// Update tutorial dungeon quest progress
|
|
this.game.systems.questSystem.updateTutorialDungeonProgress();
|
|
} else {
|
|
// Update regular dungeon quest progress using the standard method
|
|
this.game.systems.questSystem.onDungeonCompleted();
|
|
}
|
|
}
|
|
|
|
// Show completion message
|
|
this.game.showNotification(`Dungeon completed! Time: ${this.game.formatTime(completionTime)}`, 'success', 5000);
|
|
if (timeBonus > 0) {
|
|
this.game.showNotification(`Time bonus: +${timeBonus} credits!`, 'info', 3000);
|
|
}
|
|
|
|
// Reset dungeon state
|
|
this.currentDungeon = null;
|
|
this.currentRoom = null;
|
|
this.isExploring = false;
|
|
|
|
// Return to dungeon list view
|
|
this.showDungeonList();
|
|
this.generateDungeonList();
|
|
|
|
// Force UI refresh
|
|
this.updateUI();
|
|
}
|
|
|
|
showDungeonList() {
|
|
const dungeonListElement = document.getElementById('dungeonList');
|
|
const dungeonViewElement = document.getElementById('dungeonView');
|
|
|
|
if (dungeonListElement) {
|
|
dungeonListElement.style.display = 'flex';
|
|
}
|
|
|
|
if (dungeonViewElement) {
|
|
dungeonViewElement.style.display = 'none';
|
|
// Clear the dungeon view content to prevent frozen display
|
|
dungeonViewElement.innerHTML = '';
|
|
}
|
|
}
|
|
|
|
showDungeonView() {
|
|
|
|
const dungeonListElement = document.getElementById('dungeonList');
|
|
const dungeonViewElement = document.getElementById('dungeonView');
|
|
|
|
|
|
if (dungeonListElement) {
|
|
dungeonListElement.style.display = 'none';
|
|
}
|
|
|
|
if (dungeonViewElement) {
|
|
dungeonViewElement.style.display = 'flex';
|
|
}
|
|
|
|
|
|
// Display the current dungeon
|
|
this.displayDungeon();
|
|
|
|
}
|
|
|
|
// UI updates
|
|
updateUI() {
|
|
// Update dungeon statistics if elements exist
|
|
const dungeonsClearedElement = document.getElementById('dungeonsCleared');
|
|
if (dungeonsClearedElement) {
|
|
dungeonsClearedElement.textContent = this.stats.dungeonsCompleted;
|
|
}
|
|
}
|
|
|
|
// Save/Load
|
|
save() {
|
|
return {
|
|
stats: this.stats,
|
|
currentDungeon: this.currentDungeon,
|
|
currentRoom: this.currentRoom,
|
|
dungeonProgress: this.dungeonProgress
|
|
};
|
|
}
|
|
|
|
load(data) {
|
|
if (data.stats) this.stats = { ...this.stats, ...data.stats };
|
|
if (data.currentDungeon) this.currentDungeon = data.currentDungeon;
|
|
if (data.currentRoom) this.currentRoom = data.currentRoom;
|
|
if (data.dungeonProgress !== undefined) this.dungeonProgress = data.dungeonProgress;
|
|
}
|
|
}
|