463 lines
16 KiB
JavaScript
463 lines
16 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - Client Dungeon System
|
|
* Server-driven dungeon management client
|
|
*/
|
|
|
|
class DungeonSystem {
|
|
constructor(gameEngine) {
|
|
this.game = gameEngine;
|
|
|
|
// Current dungeon state (runtime only)
|
|
this.currentDungeon = null;
|
|
this.currentRoom = null;
|
|
this.dungeonProgress = 0;
|
|
this.isExploring = false;
|
|
|
|
// Server data loaded from server
|
|
this.serverDungeons = [];
|
|
this.roomTypes = {};
|
|
this.enemyTemplates = {};
|
|
|
|
console.log('[DUNGEON SYSTEM] Client DungeonSystem initialized - server-driven mode');
|
|
|
|
// Set up socket event listeners
|
|
this.setupSocketListeners();
|
|
}
|
|
|
|
/**
|
|
* Set up Socket.IO event listeners for dungeon data
|
|
*/
|
|
setupSocketListeners() {
|
|
if (!this.game.socket) {
|
|
console.warn('[DUNGEON SYSTEM] No socket available for event listeners');
|
|
return;
|
|
}
|
|
|
|
// Listen for dungeon data response
|
|
this.game.socket.on('dungeons_data', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Received dungeons data:', data);
|
|
this.serverDungeons = data.dungeons || data;
|
|
console.log('[DUNGEON SYSTEM] Loaded grouped dungeons from server:', Object.keys(this.serverDungeons));
|
|
// Update UI when data is loaded
|
|
this.generateDungeonList();
|
|
});
|
|
|
|
// Listen for room types response
|
|
this.game.socket.on('room_types_data', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Received room types data:', data);
|
|
this.roomTypes = data;
|
|
console.log('[DUNGEON SYSTEM] Loaded room types from server');
|
|
});
|
|
|
|
// Listen for enemy templates response
|
|
this.game.socket.on('enemy_templates_data', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Received enemy templates data:', data);
|
|
this.enemyTemplates = data;
|
|
console.log(`[DUNGEON SYSTEM] Loaded ${Object.keys(this.enemyTemplates).length} enemy templates from server`);
|
|
// Update UI when enemy data is loaded
|
|
this.generateDungeonList();
|
|
});
|
|
|
|
// Listen for dungeon start response
|
|
this.game.socket.on('dungeon_started', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Dungeon started:', data);
|
|
this.currentDungeon = data.instance;
|
|
this.isExploring = true;
|
|
this.dungeonProgress = 0;
|
|
});
|
|
|
|
// Listen for encounter response
|
|
this.game.socket.on('encounter_data', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Encounter received:', data);
|
|
this.currentRoom = data.encounter;
|
|
this.dungeonProgress++;
|
|
});
|
|
|
|
// Listen for dungeon completion response
|
|
this.game.socket.on('dungeon_completed', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Dungeon completed:', data);
|
|
// Reset dungeon state
|
|
this.currentDungeon = null;
|
|
this.currentRoom = null;
|
|
this.isExploring = false;
|
|
this.dungeonProgress = 0;
|
|
});
|
|
|
|
// Listen for dungeon status response
|
|
this.game.socket.on('dungeon_status', (data) => {
|
|
console.log('[DUNGEON SYSTEM] Dungeon status received:', data);
|
|
});
|
|
|
|
console.log('[DUNGEON SYSTEM] Socket event listeners set up');
|
|
}
|
|
|
|
/**
|
|
* Load dungeon data from server using Socket.IO packets
|
|
*/
|
|
async loadServerData() {
|
|
try {
|
|
console.log('[DUNGEON SYSTEM] Loading dungeon data from server via packets...');
|
|
|
|
if (!this.game.socket) {
|
|
console.error('[DUNGEON SYSTEM] No socket connection available');
|
|
return;
|
|
}
|
|
|
|
// Request dungeons from server
|
|
this.game.socket.emit('get_dungeons');
|
|
|
|
// Request room types from server
|
|
this.game.socket.emit('get_room_types');
|
|
|
|
// Request enemy templates from server
|
|
this.game.socket.emit('get_enemy_templates');
|
|
|
|
console.log('[DUNGEON SYSTEM] Server data requests sent via packets');
|
|
|
|
} catch (error) {
|
|
console.error('[DUNGEON SYSTEM] Error loading server data:', error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get all available dungeons
|
|
*/
|
|
getAllDungeons() {
|
|
return this.serverDungeons;
|
|
}
|
|
|
|
/**
|
|
* Get dungeons by difficulty
|
|
*/
|
|
getDungeonsByDifficulty(difficulty) {
|
|
return this.serverDungeons.filter(dungeon => dungeon.difficulty === difficulty);
|
|
}
|
|
|
|
/**
|
|
* Get specific dungeon by ID
|
|
*/
|
|
getDungeon(dungeonId) {
|
|
return this.serverDungeons.find(dungeon => dungeon.id === dungeonId);
|
|
}
|
|
|
|
/**
|
|
* Get room type by ID
|
|
*/
|
|
getRoomType(roomTypeId) {
|
|
return this.roomTypes[roomTypeId];
|
|
}
|
|
|
|
/**
|
|
* Get enemy template by ID
|
|
*/
|
|
getEnemyTemplate(enemyId) {
|
|
return this.enemyTemplates[enemyId];
|
|
}
|
|
|
|
/**
|
|
* Start exploring a dungeon using Socket.IO packets
|
|
*/
|
|
async startDungeon(dungeonId) {
|
|
try {
|
|
console.log(`[DUNGEON SYSTEM] Starting dungeon: ${dungeonId}`);
|
|
|
|
if (!this.game.socket) {
|
|
console.error('[DUNGEON SYSTEM] No socket connection available');
|
|
return null;
|
|
}
|
|
|
|
// Send packet to start dungeon
|
|
this.game.socket.emit('start_dungeon', {
|
|
dungeonId: dungeonId,
|
|
userId: this.game.player?.id || 'anonymous'
|
|
});
|
|
|
|
console.log('[DUNGEON SYSTEM] Dungeon start packet sent');
|
|
return true;
|
|
|
|
} catch (error) {
|
|
console.error('[DUNGEON SYSTEM] Error starting dungeon:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Process current room encounter using Socket.IO packets
|
|
*/
|
|
async processEncounter() {
|
|
if (!this.currentDungeon || !this.isExploring) {
|
|
console.warn('[DUNGEON SYSTEM] No active dungeon to process');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
console.log(`[DUNGEON SYSTEM] Processing encounter for dungeon: ${this.currentDungeon.id}`);
|
|
|
|
if (!this.game.socket) {
|
|
console.error('[DUNGEON SYSTEM] No socket connection available');
|
|
return null;
|
|
}
|
|
|
|
// Send packet to process encounter
|
|
this.game.socket.emit('process_encounter', {
|
|
instanceId: this.currentDungeon.id,
|
|
userId: this.game.player?.id || 'anonymous'
|
|
});
|
|
|
|
console.log('[DUNGEON SYSTEM] Encounter process packet sent');
|
|
return true;
|
|
|
|
} catch (error) {
|
|
console.error('[DUNGEON SYSTEM] Error processing encounter:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Complete current dungeon using Socket.IO packets
|
|
*/
|
|
async completeDungeon() {
|
|
if (!this.currentDungeon || !this.isExploring) {
|
|
console.warn('[DUNGEON SYSTEM] No active dungeon to complete');
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
console.log(`[DUNGEON SYSTEM] Completing dungeon: ${this.currentDungeon.id}`);
|
|
|
|
if (!this.game.socket) {
|
|
console.error('[DUNGEON SYSTEM] No socket connection available');
|
|
return null;
|
|
}
|
|
|
|
// Send packet to complete dungeon
|
|
this.game.socket.emit('complete_dungeon', {
|
|
instanceId: this.currentDungeon.id,
|
|
userId: this.game.player?.id || 'anonymous'
|
|
});
|
|
|
|
console.log('[DUNGEON SYSTEM] Dungeon completion packet sent');
|
|
return true;
|
|
|
|
} catch (error) {
|
|
console.error('[DUNGEON SYSTEM] Error completing dungeon:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get player's current dungeon status using Socket.IO packets
|
|
*/
|
|
async getDungeonStatus() {
|
|
try {
|
|
if (!this.game.socket) {
|
|
console.error('[DUNGEON SYSTEM] No socket connection available');
|
|
return null;
|
|
}
|
|
|
|
// Send packet to get dungeon status
|
|
this.game.socket.emit('get_dungeon_status', {
|
|
userId: this.game.player?.id || 'anonymous'
|
|
});
|
|
|
|
console.log('[DUNGEON SYSTEM] Dungeon status request packet sent');
|
|
return true;
|
|
|
|
} catch (error) {
|
|
console.error('[DUNGEON SYSTEM] Error getting dungeon status:', error);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Generate dungeon list UI using server data
|
|
*/
|
|
generateDungeonList() {
|
|
console.log('[DUNGEON SYSTEM] Generating dungeon list UI with server data...');
|
|
|
|
const dungeonListElement = document.getElementById('dungeonList');
|
|
if (!dungeonListElement) {
|
|
console.error('[DUNGEON SYSTEM] Dungeon list element not found');
|
|
return;
|
|
}
|
|
|
|
// Clear existing content
|
|
dungeonListElement.innerHTML = '';
|
|
|
|
if (!this.serverDungeons || Object.keys(this.serverDungeons).length === 0) {
|
|
dungeonListElement.innerHTML = '<p>Loading dungeons from server...</p>';
|
|
return;
|
|
}
|
|
|
|
// Generate HTML for each difficulty category
|
|
let html = '';
|
|
|
|
Object.entries(this.serverDungeons).forEach(([difficulty, dungeons]) => {
|
|
if (!dungeons || dungeons.length === 0) return;
|
|
|
|
const difficultyClass = difficulty === 'tutorial' ? 'tutorial' : difficulty;
|
|
const difficultyTitle = difficulty === 'tutorial' ? 'Tutorial Dungeons' :
|
|
difficulty.charAt(0).toUpperCase() + difficulty.slice(1) + ' Dungeons';
|
|
const difficultyIcon = this.getDifficultyIcon(difficulty);
|
|
|
|
// Add difficulty header
|
|
html += `
|
|
<h3 class="difficulty-header ${difficultyClass}">
|
|
<i class="${difficultyIcon}"></i>
|
|
${difficultyTitle}
|
|
</h3>
|
|
`;
|
|
|
|
dungeons.forEach(dungeon => {
|
|
const canEnter = this.canEnterDungeon(dungeon);
|
|
const statusClass = canEnter ? 'available' : 'locked';
|
|
const energyCost = dungeon.energyCost || 0;
|
|
const healthType = dungeon.healthType || 'player';
|
|
const healthIcon = healthType === 'ship' ? '🚀' : '👤';
|
|
|
|
// Each dungeon in its own individual container using proper CSS classes
|
|
html += `
|
|
<div class="dungeon-item ${statusClass}" data-dungeon-id="${dungeon.id}">
|
|
<div class="dungeon-name">${dungeon.name}</div>
|
|
<div class="dungeon-difficulty ${difficulty}">
|
|
<i class="${difficultyIcon}"></i> ${difficulty} - ${energyCost} Energy
|
|
</div>
|
|
<div class="dungeon-description">${dungeon.description}</div>
|
|
<div class="health-type">${healthIcon}</div>
|
|
<div class="dungeon-enemies">
|
|
<strong>Enemies:</strong>
|
|
<div class="enemy-list">
|
|
${this.generateEnemyList(dungeon.enemyTypes || [])}
|
|
</div>
|
|
</div>
|
|
<button class="dungeon-btn" ${!canEnter ? 'disabled' : ''}
|
|
onclick="game.systems.dungeonSystem.startDungeon('${dungeon.id}')">
|
|
${canEnter ? 'Enter Dungeon' : 'Locked'}
|
|
</button>
|
|
</div>
|
|
`;
|
|
});
|
|
});
|
|
|
|
dungeonListElement.innerHTML = html;
|
|
console.log('[DUNGEON SYSTEM] Dungeon list UI generated successfully');
|
|
}
|
|
|
|
/**
|
|
* Get difficulty icon for dungeon
|
|
*/
|
|
getDifficultyIcon(difficulty) {
|
|
const icons = {
|
|
tutorial: 'fas fa-graduation-cap',
|
|
easy: 'fas fa-smile',
|
|
medium: 'fas fa-meh',
|
|
hard: 'fas fa-frown',
|
|
extreme: 'fas fa-skull'
|
|
};
|
|
return icons[difficulty] || 'fas fa-question';
|
|
}
|
|
|
|
/**
|
|
* Generate enemy list HTML for dungeon
|
|
*/
|
|
generateEnemyList(enemyTypes) {
|
|
if (!enemyTypes || enemyTypes.length === 0) {
|
|
return '<span class="no-enemies">No enemies</span>';
|
|
}
|
|
|
|
let html = '';
|
|
enemyTypes.forEach(enemyType => {
|
|
const enemy = this.getEnemyTemplate(enemyType);
|
|
if (enemy) {
|
|
html += `
|
|
<div class="enemy-item">
|
|
<span class="enemy-name">${enemy.name}</span>
|
|
<div class="enemy-stats">
|
|
<span class="health">❤️ ${enemy.health}</span>
|
|
<span class="attack">⚔️ ${enemy.attack}</span>
|
|
<span class="defense">🛡️ ${enemy.defense}</span>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
});
|
|
|
|
return html;
|
|
}
|
|
|
|
/**
|
|
* Check if player can enter dungeon
|
|
*/
|
|
canEnterDungeon(dungeon) {
|
|
if (!this.game.player) {
|
|
console.log('[DUNGEON SYSTEM] No player data available');
|
|
return false;
|
|
}
|
|
|
|
const playerLevel = this.game.player.stats?.level || 1;
|
|
const minLevel = dungeon.minLevel || 1;
|
|
const maxLevel = dungeon.maxLevel || 999;
|
|
const energyCost = dungeon.energyCost || 0;
|
|
const playerEnergy = this.game.player.stats?.energy || 0;
|
|
|
|
console.log(`[DUNGEON SYSTEM] Dungeon check for ${dungeon.name}:`, {
|
|
playerLevel,
|
|
minLevel,
|
|
maxLevel,
|
|
playerEnergy,
|
|
energyCost,
|
|
canEnter: playerLevel >= minLevel && playerLevel <= maxLevel && playerEnergy >= energyCost
|
|
});
|
|
|
|
return playerLevel >= minLevel &&
|
|
playerLevel <= maxLevel &&
|
|
playerEnergy >= energyCost;
|
|
}
|
|
|
|
/**
|
|
* Update UI with current dungeon information
|
|
*/
|
|
updateUI() {
|
|
if (this.game.uiManager) {
|
|
this.game.uiManager.updateDungeonUI({
|
|
currentDungeon: this.currentDungeon,
|
|
currentRoom: this.currentRoom,
|
|
progress: this.dungeonProgress,
|
|
isExploring: this.isExploring
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize system and load server data
|
|
*/
|
|
async initialize() {
|
|
console.log('[DUNGEON SYSTEM] Initializing client dungeon system...');
|
|
|
|
// Set up socket listeners if not already done
|
|
if (!this.game.socket) {
|
|
console.warn('[DUNGEON SYSTEM] Socket not available during initialization, will retry...');
|
|
// Retry after a short delay
|
|
setTimeout(() => {
|
|
if (this.game.socket) {
|
|
this.setupSocketListeners();
|
|
this.loadServerData();
|
|
} else {
|
|
console.error('[DUNGEON SYSTEM] Socket still not available after retry');
|
|
}
|
|
}, 1000);
|
|
} else {
|
|
this.setupSocketListeners();
|
|
await this.loadServerData();
|
|
}
|
|
|
|
console.log('[DUNGEON SYSTEM] Client dungeon system initialization complete');
|
|
}
|
|
}
|
|
|
|
// Export for use in GameEngine
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = DungeonSystem;
|
|
}
|