2638 lines
107 KiB
JavaScript
2638 lines
107 KiB
JavaScript
/**
|
|
* Galaxy Strike Online - UI Manager
|
|
* Handles all user interface interactions and updates
|
|
*/
|
|
|
|
class UIManager {
|
|
constructor(gameEngine) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.constructor', {
|
|
gameEngineProvided: !!gameEngine
|
|
});
|
|
|
|
this.game = gameEngine;
|
|
|
|
// UI state
|
|
this.currentTab = 'dashboard';
|
|
this.modalOpen = false;
|
|
this.notifications = [];
|
|
|
|
// Note: setupEventListeners() called in proceedWithInitialization() to prevent duplicates
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.constructor', {
|
|
currentTab: this.currentTab,
|
|
modalOpen: this.modalOpen,
|
|
notificationsCount: this.notifications.length,
|
|
gameEngineSet: !!this.game,
|
|
eventListenersSetup: true
|
|
});
|
|
}
|
|
|
|
async initialize() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.initialize', {
|
|
currentTab: this.currentTab,
|
|
modalOpen: this.modalOpen,
|
|
notificationsCount: this.notifications.length
|
|
});
|
|
|
|
// Wait for DOM to be ready and game interface to be visible
|
|
const waitForDOM = () => {
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
const navButtons = document.querySelectorAll('.nav-btn');
|
|
|
|
console.log('[UI MANAGER] DOM Check:', {
|
|
gameInterfaceExists: !!gameInterface,
|
|
gameInterfaceHidden: gameInterface?.classList.contains('hidden'),
|
|
navButtonsFound: navButtons.length,
|
|
documentReady: document.readyState
|
|
});
|
|
|
|
// Less strict condition - proceed if we have nav buttons, even if interface is still hidden
|
|
if (navButtons.length > 0) {
|
|
console.log('[UI MANAGER] Navigation buttons found, proceeding with initialization');
|
|
this.proceedWithInitialization();
|
|
} else {
|
|
console.log('[UI MANAGER] Waiting for navigation buttons...');
|
|
setTimeout(waitForDOM, 100);
|
|
}
|
|
};
|
|
|
|
// Start the DOM check
|
|
waitForDOM();
|
|
}
|
|
|
|
proceedWithInitialization() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// Setup navigation
|
|
// if (debugLogger) debugLogger.logStep('Setting up navigation');
|
|
this.setupNavigation();
|
|
|
|
// Setup event listeners
|
|
// if (debugLogger) debugLogger.logStep('Setting up event listeners');
|
|
this.setupEventListeners();
|
|
|
|
// Setup resource display
|
|
// if (debugLogger) debugLogger.logStep('Setting up resource display');
|
|
this.setupResourceDisplay();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.initialize', {
|
|
currentTab: this.currentTab,
|
|
modalOpen: this.modalOpen,
|
|
notificationsCount: this.notifications.length,
|
|
navigationSetup: true,
|
|
eventListenersSetup: true,
|
|
resourceDisplaySetup: true
|
|
});
|
|
}
|
|
|
|
setupNavigation() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.setupNavigation');
|
|
|
|
// Navigation setup moved to setupEventListeners to fix scope issues
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
|
|
success: true
|
|
});
|
|
|
|
const craftingCatButtons = document.querySelectorAll('.crafting-cat-btn');
|
|
if (debugLogger) debugLogger.logStep('Setting up crafting category navigation', {
|
|
craftingCatButtonsCount: craftingCatButtons.length
|
|
});
|
|
|
|
craftingCatButtons.forEach(btn => {
|
|
btn.addEventListener('click', (e) => {
|
|
const category = e.currentTarget.dataset.category;
|
|
|
|
if (debugLogger) debugLogger.log('Crafting category button clicked', {
|
|
buttonElement: btn.tagName,
|
|
buttonText: btn.textContent,
|
|
category: category
|
|
});
|
|
|
|
this.switchCraftingCategory(category);
|
|
});
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
|
|
craftingCatButtonsSetup: craftingCatButtons.length
|
|
});
|
|
}
|
|
|
|
setupEventListeners() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.setupEventListeners');
|
|
|
|
// Setup tab navigation here to fix scope issues with endStep
|
|
const navButtons = document.querySelectorAll('.nav-btn');
|
|
console.log(`[UIManager] Found ${navButtons.length} navigation buttons`);
|
|
if (debugLogger) debugLogger.logStep('Setting up tab navigation', {
|
|
navButtonsCount: navButtons.length
|
|
});
|
|
|
|
if (navButtons.length === 0) {
|
|
console.warn('[UIManager] No navigation buttons found!');
|
|
if (debugLogger) debugLogger.logStep('No navigation buttons found');
|
|
return;
|
|
}
|
|
|
|
navButtons.forEach((btn, index) => {
|
|
console.log(`[UIManager] Setting up button ${index}:`, btn.dataset.tab, btn);
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
|
console.log(`[UIManager] Button ${btn.dataset.tab} already has listener, skipping`);
|
|
return;
|
|
}
|
|
|
|
btn.addEventListener('click', (e) => {
|
|
console.log(`[UIManager] Navigation button clicked: ${btn.dataset.tab}`, e);
|
|
const tab = btn.dataset.tab;
|
|
if (tab) {
|
|
this.switchTab(tab);
|
|
} else {
|
|
console.warn('[UIManager] Button clicked but no tab data found');
|
|
}
|
|
});
|
|
|
|
// Mark as having listener
|
|
btn.setAttribute('data-has-listener', 'true');
|
|
console.log(`[UIManager] Event listener added to button: ${btn.dataset.tab}`);
|
|
});
|
|
|
|
// Add a global fallback click handler for navigation buttons
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.classList.contains('nav-btn') || e.target.closest('.nav-btn')) {
|
|
const button = e.target.classList.contains('nav-btn') ? e.target : e.target.closest('.nav-btn');
|
|
const tab = button.dataset.tab;
|
|
if (tab && window.game && window.game.systems && window.game.systems.ui) {
|
|
console.log('[UI MANAGER] Global fallback: Navigation button clicked:', tab);
|
|
window.game.systems.ui.switchTab(tab);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Set up UI update event listener from GameEngine
|
|
if (this.game) {
|
|
this.game.addEventListener('uiUpdate', (event) => {
|
|
this.handleUIUpdate(event.detail);
|
|
});
|
|
|
|
// if (debugLogger) debugLogger.logStep('UI update event listener set up');
|
|
}
|
|
|
|
// Modal controls
|
|
const modalClose = document.getElementById('modalClose');
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
|
|
if (debugLogger) debugLogger.logStep('Setting up modal controls', {
|
|
modalCloseExists: !!modalClose,
|
|
modalOverlayExists: !!modalOverlay
|
|
});
|
|
|
|
if (modalClose) {
|
|
// Check if already has listener
|
|
if (modalClose.getAttribute('data-has-listener') === 'true') {
|
|
if (debugLogger) debugLogger.log('Modal close button already has listener, skipping');
|
|
} else {
|
|
modalClose.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Modal close button clicked');
|
|
this.closeModal();
|
|
});
|
|
modalClose.setAttribute('data-has-listener', 'true');
|
|
}
|
|
}
|
|
|
|
if (modalOverlay) {
|
|
// Check if already has listener
|
|
if (modalOverlay.getAttribute('data-has-listener') === 'true') {
|
|
if (debugLogger) debugLogger.log('Modal overlay already has listener, skipping');
|
|
} else {
|
|
modalOverlay.addEventListener('click', (e) => {
|
|
if (e.target === modalOverlay) {
|
|
if (debugLogger) debugLogger.log('Modal overlay clicked - closing modal');
|
|
this.closeModal();
|
|
}
|
|
});
|
|
modalOverlay.setAttribute('data-has-listener', 'true');
|
|
}
|
|
}
|
|
|
|
// Quick action buttons
|
|
const claimOfflineBtn = document.getElementById('claimOfflineBtn');
|
|
if (claimOfflineBtn) {
|
|
// Check if already has listener
|
|
if (claimOfflineBtn.getAttribute('data-has-listener') === 'true') {
|
|
if (debugLogger) debugLogger.log('Claim offline button already has listener, skipping');
|
|
} else {
|
|
// if (debugLogger) debugLogger.logStep('Setting up claim offline rewards button');
|
|
claimOfflineBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Claim offline rewards button clicked');
|
|
this.game.systems.idleSystem.claimOfflineRewards();
|
|
});
|
|
claimOfflineBtn.setAttribute('data-has-listener', 'true');
|
|
}
|
|
}
|
|
|
|
const quickDungeonBtn = document.getElementById('quickDungeonBtn');
|
|
if (quickDungeonBtn) {
|
|
// if (debugLogger) debugLogger.logStep('Setting up quick dungeon button');
|
|
quickDungeonBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Quick dungeon button clicked', {
|
|
currentTab: this.currentTab,
|
|
targetTab: 'dungeons'
|
|
});
|
|
this.switchTab('dungeons');
|
|
});
|
|
}
|
|
|
|
// Settings and Discord buttons
|
|
const settingsBtn = document.getElementById('settingsBtn');
|
|
if (settingsBtn) {
|
|
// Check if already has listener
|
|
if (settingsBtn.getAttribute('data-has-listener') === 'true') {
|
|
if (debugLogger) debugLogger.log('Settings button already has listener, skipping');
|
|
} else {
|
|
// if (debugLogger) debugLogger.logStep('Setting up settings button');
|
|
settingsBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Settings button clicked');
|
|
this.showSettingsMenu();
|
|
});
|
|
settingsBtn.setAttribute('data-has-listener', 'true');
|
|
}
|
|
}
|
|
|
|
const discordBtn = document.getElementById('discordBtn');
|
|
if (discordBtn) {
|
|
// if (debugLogger) debugLogger.logStep('Setting up Discord button');
|
|
discordBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Discord button clicked');
|
|
this.showDiscordIntegration();
|
|
});
|
|
}
|
|
|
|
// Local Server button
|
|
const localServerBtn = document.getElementById('localServerBtn');
|
|
if (localServerBtn) {
|
|
// if (debugLogger) debugLogger.logStep('Setting up local server button');
|
|
localServerBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Local server button clicked');
|
|
this.showLocalServerControls();
|
|
});
|
|
}
|
|
|
|
// Return to Main Menu button
|
|
const returnToMenuBtn = document.getElementById('returnToMenuBtn');
|
|
if (returnToMenuBtn) {
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (returnToMenuBtn.getAttribute('data-has-listener') === 'true') {
|
|
if (debugLogger) debugLogger.log('Return to menu button already has listener, skipping');
|
|
return;
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.logStep('Setting up return to menu button');
|
|
returnToMenuBtn.addEventListener('click', () => {
|
|
if (debugLogger) debugLogger.log('Return to menu button clicked');
|
|
this.showReturnToMainMenuModal();
|
|
});
|
|
|
|
// Mark as having listener
|
|
returnToMenuBtn.setAttribute('data-has-listener', 'true');
|
|
}
|
|
|
|
// Setup sub-panel category buttons
|
|
const skillCatButtons = document.querySelectorAll('.skill-cat-btn');
|
|
if (debugLogger) debugLogger.logStep('Setting up skill category navigation', {
|
|
skillCatButtonsCount: skillCatButtons.length
|
|
});
|
|
|
|
skillCatButtons.forEach(btn => {
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
|
return;
|
|
}
|
|
|
|
btn.addEventListener('click', (e) => {
|
|
const category = btn.dataset.category;
|
|
if (debugLogger) debugLogger.log('Skill category button clicked', {
|
|
buttonElement: btn.tagName,
|
|
buttonText: btn.textContent,
|
|
category: category
|
|
});
|
|
|
|
this.switchSkillCategory(category);
|
|
});
|
|
|
|
// Mark button as having a listener
|
|
btn.setAttribute('data-has-listener', 'true');
|
|
});
|
|
|
|
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
|
|
if (debugLogger) debugLogger.logStep('Setting up quest tab navigation', {
|
|
questTabButtonsCount: questTabButtons.length
|
|
});
|
|
|
|
questTabButtons.forEach(btn => {
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
|
return;
|
|
}
|
|
|
|
btn.addEventListener('click', (e) => {
|
|
const type = btn.dataset.type;
|
|
if (debugLogger) debugLogger.log('Quest tab button clicked', {
|
|
buttonElement: btn.tagName,
|
|
buttonText: btn.textContent,
|
|
type: type
|
|
});
|
|
|
|
this.switchQuestType(type);
|
|
});
|
|
|
|
// Mark button as having a listener
|
|
btn.setAttribute('data-has-listener', 'true');
|
|
});
|
|
|
|
const craftingCatButtons = document.querySelectorAll('.crafting-cat-btn');
|
|
if (debugLogger) debugLogger.logStep('Setting up crafting category navigation', {
|
|
craftingCatButtonsCount: craftingCatButtons.length
|
|
});
|
|
|
|
craftingCatButtons.forEach(btn => {
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
|
return;
|
|
}
|
|
|
|
btn.addEventListener('click', (e) => {
|
|
const category = e.currentTarget.dataset.category;
|
|
|
|
if (debugLogger) debugLogger.log('Crafting category button clicked', {
|
|
buttonElement: btn.tagName,
|
|
buttonText: btn.textContent,
|
|
category: category
|
|
});
|
|
|
|
this.switchCraftingCategory(category);
|
|
});
|
|
|
|
// Mark button as having a listener
|
|
btn.setAttribute('data-has-listener', 'true');
|
|
});
|
|
|
|
const shopCatButtons = document.querySelectorAll('.shop-cat-btn');
|
|
if (debugLogger) debugLogger.logStep('Setting up shop category navigation', {
|
|
shopCatButtonsCount: shopCatButtons.length
|
|
});
|
|
|
|
shopCatButtons.forEach(btn => {
|
|
// Check if button already has a listener to prevent duplicates
|
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
|
return;
|
|
}
|
|
|
|
btn.addEventListener('click', (e) => {
|
|
const category = btn.dataset.category;
|
|
if (debugLogger) debugLogger.log('Shop category button clicked', {
|
|
buttonElement: btn.tagName,
|
|
buttonText: btn.textContent,
|
|
category: category
|
|
});
|
|
|
|
this.switchShopCategory(category);
|
|
});
|
|
|
|
// Mark button as having a listener
|
|
btn.setAttribute('data-has-listener', 'true');
|
|
});
|
|
|
|
// Keyboard shortcuts for tab switching removed
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.setupEventListeners', {
|
|
modalControlsSetup: !!(modalClose || modalOverlay),
|
|
quickActionButtonsSetup: !!(claimOfflineBtn || quickDungeonBtn),
|
|
settingsButtonsSetup: !!(settingsBtn || discordBtn),
|
|
returnMenuButtonSetup: !!returnToMenuBtn,
|
|
navigationButtonsSetup: navButtons.length > 0,
|
|
navigationButtonsCount: navButtons.length,
|
|
skillCategoryButtonsSetup: skillCatButtons.length,
|
|
questTabButtonsSetup: questTabButtons.length,
|
|
craftingCategoryButtonsSetup: craftingCatButtons.length,
|
|
shopCategoryButtonsSetup: shopCatButtons.length
|
|
});
|
|
}
|
|
|
|
async saveGame() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// if (debugLogger) debugLogger.startStep('UIManager.saveGame');
|
|
|
|
try {
|
|
|
|
// Show saving notification
|
|
// this.game.showNotification('Saving game...', 'info', 2000);
|
|
|
|
// Call the game engine's save method
|
|
await this.game.save();
|
|
|
|
// Show success notification
|
|
// this.game.showNotification('Game saved successfully!', 'success', 3000);
|
|
|
|
|
|
// if (debugLogger) debugLogger.endStep('UIManager.saveGame', {
|
|
// success: true
|
|
// });
|
|
|
|
} catch (error) {
|
|
|
|
// Show error notification
|
|
this.game.showNotification('Failed to save game!', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.saveGame');
|
|
}
|
|
}
|
|
|
|
showLocalServerControls() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.showLocalServerControls');
|
|
|
|
|
|
// Get current server status
|
|
const serverInfo = window.localServerManager ? window.localServerManager.getServerInfo() : {
|
|
isRunning: false,
|
|
status: 'Unknown',
|
|
port: null,
|
|
url: null,
|
|
connectedClients: 0,
|
|
uptime: 0
|
|
};
|
|
|
|
let content = '<div class="local-server-controls">';
|
|
content += '<div class="server-status">';
|
|
content += `<p><strong>Status:</strong> <span class="status-${serverInfo.isRunning ? 'online' : 'offline'}">${serverInfo.status}</span></p>`;
|
|
|
|
if (serverInfo.isRunning) {
|
|
content += `<p><strong>Port:</strong> ${serverInfo.port}</p>`;
|
|
content += `<p><strong>URL:</strong> <a href="${serverInfo.url}" target="_blank">${serverInfo.url}</a></p>`;
|
|
content += `<p><strong>Connected Clients:</strong> ${serverInfo.connectedClients}</p>`;
|
|
content += `<p><strong>Uptime:</strong> ${Math.floor(serverInfo.uptime)}s</p>`;
|
|
}
|
|
content += '</div>';
|
|
|
|
// Control buttons
|
|
content += '<div class="server-actions">';
|
|
|
|
if (serverInfo.isRunning) {
|
|
content += '<button class="btn btn-warning" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.stopLocalServer(); }">';
|
|
content += '<i class="fas fa-stop"></i> Stop Server';
|
|
content += '</button>';
|
|
|
|
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.restartLocalServer(); }">';
|
|
content += '<i class="fas fa-redo"></i> Restart Server';
|
|
content += '</button>';
|
|
} else {
|
|
content += '<button class="btn btn-success" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.startLocalServer(); }">';
|
|
content += '<i class="fas fa-play"></i> Start Server';
|
|
content += '</button>';
|
|
}
|
|
|
|
content += '</div>';
|
|
|
|
// Information section
|
|
content += '<div class="server-info">';
|
|
content += '<p>The local server enables singleplayer mode when external servers are unavailable. Save data is stored locally on your computer. No internet connection required for local gameplay.</p>';
|
|
content += '</div>';
|
|
|
|
content += '</div>';
|
|
|
|
this.showModal('Local Server', content);
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.showLocalServerControls', {
|
|
serverRunning: serverInfo.isRunning,
|
|
serverPort: serverInfo.port
|
|
});
|
|
}
|
|
|
|
async startLocalServer() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.startLocalServer');
|
|
|
|
try {
|
|
|
|
if (!window.localServerManager) {
|
|
this.game.showNotification('Local server manager not available', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
const result = await window.localServerManager.startServer();
|
|
|
|
if (result.success) {
|
|
this.game.showNotification(`Local server started on port ${result.port}`, 'success', 3000);
|
|
this.closeModal();
|
|
|
|
// Refresh the modal to show updated status
|
|
setTimeout(() => {
|
|
this.showLocalServerControls();
|
|
}, 500);
|
|
} else {
|
|
this.game.showNotification(`Failed to start server: ${result.error}`, 'error', 3000);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.startLocalServer', {
|
|
success: result.success,
|
|
port: result.port
|
|
});
|
|
|
|
} catch (error) {
|
|
this.game.showNotification('Error starting local server', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.startLocalServer');
|
|
}
|
|
}
|
|
|
|
async stopLocalServer() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.stopLocalServer');
|
|
|
|
try {
|
|
|
|
if (!window.localServerManager) {
|
|
this.game.showNotification('Local server manager not available', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
const result = await window.localServerManager.stopServer();
|
|
|
|
if (result.success) {
|
|
this.game.showNotification('Local server stopped', 'success', 3000);
|
|
this.closeModal();
|
|
|
|
// Refresh the modal to show updated status
|
|
setTimeout(() => {
|
|
this.showLocalServerControls();
|
|
}, 500);
|
|
} else {
|
|
this.game.showNotification(`Failed to stop server: ${result.error}`, 'error', 3000);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.stopLocalServer', {
|
|
success: result.success
|
|
});
|
|
|
|
} catch (error) {
|
|
this.game.showNotification('Error stopping local server', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.stopLocalServer');
|
|
}
|
|
}
|
|
|
|
async restartLocalServer() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.restartLocalServer');
|
|
|
|
try {
|
|
|
|
if (!window.localServerManager) {
|
|
this.game.showNotification('Local server manager not available', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
// Stop first
|
|
await this.stopLocalServer();
|
|
|
|
// Wait a moment
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
// Start again
|
|
await this.startLocalServer();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.restartLocalServer', {
|
|
success: true
|
|
});
|
|
|
|
} catch (error) {
|
|
this.game.showNotification('Error restarting local server', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.restartLocalServer');
|
|
}
|
|
}
|
|
|
|
returnToMainMenu() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.returnToMainMenu');
|
|
|
|
// Go directly to server selection without confirmation modal
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.returnToMainMenu', {
|
|
success: true,
|
|
directToServerSelection: true
|
|
});
|
|
}
|
|
|
|
async stopLocalServer() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.stopLocalServer');
|
|
|
|
try {
|
|
|
|
if (!window.localServerManager) {
|
|
this.game.showNotification('Local server manager not available', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
const result = await window.localServerManager.stopServer();
|
|
|
|
if (result.success) {
|
|
this.game.showNotification('Local server stopped', 'success', 3000);
|
|
this.closeModal();
|
|
|
|
// Refresh the modal to show updated status
|
|
setTimeout(() => {
|
|
this.showLocalServerControls();
|
|
}, 500);
|
|
} else {
|
|
this.game.showNotification(`Failed to stop server: ${result.error}`, 'error', 3000);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.stopLocalServer', {
|
|
success: result.success
|
|
});
|
|
|
|
} catch (error) {
|
|
this.game.showNotification('Error stopping local server', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.stopLocalServer');
|
|
}
|
|
}
|
|
|
|
async restartLocalServer() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.restartLocalServer');
|
|
|
|
try {
|
|
|
|
if (!window.localServerManager) {
|
|
this.game.showNotification('Local server manager not available', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
// Stop first
|
|
await this.stopLocalServer();
|
|
|
|
// Wait a moment
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
// Start again
|
|
await this.startLocalServer();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.restartLocalServer', {
|
|
success: true
|
|
});
|
|
|
|
} catch (error) {
|
|
this.game.showNotification('Error restarting local server', 'error', 3000);
|
|
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.restartLocalServer');
|
|
}
|
|
}
|
|
|
|
showReturnToMainMenuModal() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// Show confirmation modal instead of browser confirm dialog
|
|
let content = '<div class="confirmation-content">';
|
|
content += '<p>Are you sure you want to return to the main menu?</p>';
|
|
content += '<p><strong>Warning:</strong> Any unsaved progress will be lost.</p>';
|
|
content += '<div class="confirmation-actions">';
|
|
|
|
// Check if using fallback GameEngine
|
|
if (window.game && window.game.isFallback) {
|
|
content += '<button class="btn btn-primary" onclick="if(window.uiManager) { window.uiManager.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
|
content += '<button class="btn btn-secondary" onclick="if(window.uiManager) { window.uiManager.closeModal(); }">Cancel</button>';
|
|
} else {
|
|
content += '<button class="btn btn-primary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
|
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems && window.game.systems.ui) { window.game.systems.ui.closeModal(); }">Cancel</button>';
|
|
}
|
|
|
|
content += '</div>';
|
|
content += '</div>';
|
|
|
|
this.showModal('Return to Main Menu', content);
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.returnToMainMenu', {
|
|
success: true,
|
|
confirmationShown: true
|
|
});
|
|
}
|
|
|
|
async confirmReturnToMainMenu() {
|
|
try {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// Reset multiplayer mode when returning to main menu
|
|
if (window.smartSaveManager) {
|
|
window.smartSaveManager.setMultiplayerMode(false);
|
|
}
|
|
|
|
// Check if we're in multiplayer mode - if so, don't save locally
|
|
const isMultiplayer = window.smartSaveManager?.isMultiplayer;
|
|
|
|
// Always stop the game and clear timers regardless of mode
|
|
this.game.isRunning = false;
|
|
|
|
// Force save before stopping in multiplayer mode
|
|
if (isMultiplayer && this.game && this.game.save) {
|
|
console.log('[UI MANAGER] Force saving game before leaving multiplayer mode');
|
|
try {
|
|
await this.game.save();
|
|
console.log('[UI MANAGER] Game saved successfully before leaving server');
|
|
} catch (error) {
|
|
console.error('[UI MANAGER] Error saving game before leaving server:', error);
|
|
}
|
|
}
|
|
|
|
// Clear game logic timer
|
|
if (this.game.gameLogicTimer) {
|
|
clearInterval(this.game.gameLogicTimer);
|
|
this.game.gameLogicTimer = null;
|
|
}
|
|
|
|
// Clear auto-save timer
|
|
if (this.game.autoSaveTimer) {
|
|
clearInterval(this.game.autoSaveTimer);
|
|
this.game.autoSaveTimer = null;
|
|
}
|
|
|
|
// Stop economy system timers
|
|
if (this.game.systems.economy) {
|
|
this.game.systems.economy.stopShopRefreshTimer();
|
|
}
|
|
|
|
if (isMultiplayer) {
|
|
console.log('[UI MANAGER] Skipping local save - returning from multiplayer mode');
|
|
|
|
// Show main menu immediately
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
|
success: true,
|
|
multiplayerMode: true,
|
|
localSaveSkipped: true,
|
|
mainMenuShown: true
|
|
});
|
|
} else {
|
|
// Handle async stop properly for singleplayer mode
|
|
this.game.stop().then(() => {
|
|
try {
|
|
|
|
// if (debugLogger) debugLogger.logStep('Game saved successfully');
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
|
success: true,
|
|
gameStopped: true,
|
|
mainMenuShown: true
|
|
});
|
|
} catch (error) {
|
|
try {
|
|
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
|
phase: 'game_stop_and_save'
|
|
});
|
|
|
|
// Still return to menu even if save fails
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
|
success: true,
|
|
gameStopped: true,
|
|
saveError: true,
|
|
mainMenuShown: true
|
|
});
|
|
} catch (loggerError) {
|
|
console.error('[UI MANAGER] Debug logger error:', loggerError);
|
|
}
|
|
}
|
|
}).catch(error => {
|
|
try {
|
|
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
|
phase: 'game_stop_and_save'
|
|
});
|
|
|
|
// Still return to menu even if save fails
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
|
success: true,
|
|
gameStopped: true,
|
|
saveError: true,
|
|
mainMenuShown: true
|
|
});
|
|
} catch (loggerError) {
|
|
console.error('[UI MANAGER] Debug logger error:', loggerError);
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('[UI MANAGER] Error in confirmReturnToMainMenu:', error);
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
|
phase: 'main_logic'
|
|
});
|
|
}
|
|
|
|
// Always show main menu regardless of game state
|
|
try {
|
|
setTimeout(() => {
|
|
this.showMainMenu();
|
|
this.closeModal();
|
|
}, 5000); // 5 second delay to ensure full cleanup and menu readiness
|
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
|
success: true,
|
|
gameStopped: this.game ? !this.game.isRunning : false,
|
|
mainMenuShown: true
|
|
});
|
|
} catch (error) {
|
|
console.error('[UI MANAGER] Error during return to main menu:', error);
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.confirmReturnToMainMenu', error, {
|
|
phase: 'return_to_main_menu'
|
|
});
|
|
}
|
|
}
|
|
showMainMenu() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.showMainMenu');
|
|
|
|
|
|
// Disconnect from server first
|
|
if (window.gameInitializer && window.gameInitializer.socket) {
|
|
window.gameInitializer.socket.disconnect();
|
|
}
|
|
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
if (gameInterface) {
|
|
gameInterface.classList.add('hidden');
|
|
|
|
// if (debugLogger) debugLogger.logStep('Game interface hidden');
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Game interface element not found');
|
|
}
|
|
|
|
// Show main menu
|
|
if (window.liveMainMenu) {
|
|
// if (debugLogger) debugLogger.logStep('About to show main menu using LiveMainMenu');
|
|
|
|
try {
|
|
// Show the main menu DOM element and use LiveMainMenu to show appropriate section
|
|
const mainMenuElement = document.getElementById('mainMenu');
|
|
if (mainMenuElement) {
|
|
mainMenuElement.classList.remove('hidden');
|
|
}
|
|
|
|
// Show the server section (most appropriate for returning to menu)
|
|
if (window.liveMainMenu && typeof window.liveMainMenu.showServerSection === 'function') {
|
|
window.liveMainMenu.showServerSection();
|
|
} else {
|
|
// Fallback: manually show server section
|
|
console.warn('LiveMainMenu.showServerSection not available, using fallback');
|
|
|
|
// Ensure main menu is visible (using the already declared mainMenuElement)
|
|
if (mainMenuElement) {
|
|
mainMenuElement.classList.remove('hidden');
|
|
}
|
|
|
|
const serverSection = document.getElementById('serverSection');
|
|
const loginSection = document.getElementById('loginSection');
|
|
const serverConfirmSection = document.getElementById('serverConfirmSection');
|
|
const optionsSection = document.getElementById('optionsSection');
|
|
|
|
// Hide all sections first
|
|
if (loginSection) loginSection.classList.add('hidden');
|
|
if (serverConfirmSection) serverConfirmSection.classList.add('hidden');
|
|
if (optionsSection) optionsSection.classList.add('hidden');
|
|
|
|
// Show server section
|
|
if (serverSection) {
|
|
serverSection.classList.remove('hidden');
|
|
}
|
|
|
|
// Try to refresh server list if available
|
|
if (window.liveMainMenu && typeof window.liveMainMenu.refreshServerList === 'function') {
|
|
window.liveMainMenu.refreshServerList();
|
|
}
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.logStep('LiveMainMenu showServerSection() completed successfully');
|
|
} catch (error) {
|
|
// if (debugLogger) debugLogger.logStep('Error in LiveMainMenu operations', { error: error.message });
|
|
}
|
|
|
|
// Show save section specifically for returning to menu
|
|
setTimeout(() => {
|
|
try {
|
|
// Note: LiveMainMenu doesn't have save methods, so we'll just log this
|
|
if (debugLogger) debugLogger.logStep('Save section operations skipped - LiveMainMenu doesn\'t have save methods');
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.logStep('Error in save section operations', { error: error.message });
|
|
}
|
|
}, 500);
|
|
} else if (window.mainMenu) {
|
|
// Fallback to just showing the DOM element
|
|
// if (debugLogger) debugLogger.logStep('Using fallback DOM display for main menu');
|
|
|
|
try {
|
|
const mainMenuElement = document.getElementById('mainMenu');
|
|
if (mainMenuElement) {
|
|
mainMenuElement.classList.remove('hidden');
|
|
|
|
// Also show server section in fallback mode
|
|
const serverSection = document.getElementById('serverSection');
|
|
const loginSection = document.getElementById('loginSection');
|
|
const serverConfirmSection = document.getElementById('serverConfirmSection');
|
|
const optionsSection = document.getElementById('optionsSection');
|
|
|
|
// Hide all sections first
|
|
if (loginSection) loginSection.classList.add('hidden');
|
|
if (serverConfirmSection) serverConfirmSection.classList.add('hidden');
|
|
if (optionsSection) optionsSection.classList.add('hidden');
|
|
|
|
// Show server section
|
|
if (serverSection) {
|
|
serverSection.classList.remove('hidden');
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.logStep('Main menu DOM element shown via fallback with server section');
|
|
}
|
|
} catch (error) {
|
|
// if (debugLogger) debugLogger.logStep('Error in fallback main menu display', { error: error.message });
|
|
}
|
|
} else {
|
|
// Final fallback: directly manipulate DOM to show server section
|
|
console.warn('Neither LiveMainMenu nor mainMenu available, using final fallback');
|
|
try {
|
|
const mainMenuElement = document.getElementById('mainMenu');
|
|
const serverSection = document.getElementById('serverSection');
|
|
const loginSection = document.getElementById('loginSection');
|
|
const serverConfirmSection = document.getElementById('serverConfirmSection');
|
|
const optionsSection = document.getElementById('optionsSection');
|
|
const gameInterface = document.getElementById('gameInterface');
|
|
|
|
// Hide game interface
|
|
if (gameInterface) {
|
|
gameInterface.classList.add('hidden');
|
|
}
|
|
|
|
// Show main menu
|
|
if (mainMenuElement) {
|
|
mainMenuElement.classList.remove('hidden');
|
|
}
|
|
|
|
// Hide all sections first
|
|
if (loginSection) loginSection.classList.add('hidden');
|
|
if (serverConfirmSection) serverConfirmSection.classList.add('hidden');
|
|
if (optionsSection) optionsSection.classList.add('hidden');
|
|
|
|
// Show server section
|
|
if (serverSection) {
|
|
serverSection.classList.remove('hidden');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error in final fallback server section display', error);
|
|
}
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.showMainMenu', {
|
|
success: true,
|
|
mainMenuShown: !!window.mainMenu
|
|
});
|
|
}
|
|
|
|
// Tab management
|
|
switchTab(tabName) {
|
|
if (debugLogger) debugLogger.startStep('UIManager.switchTab', {
|
|
fromTab: this.currentTab,
|
|
toTab: tabName,
|
|
sameTab: this.currentTab === tabName
|
|
});
|
|
|
|
if (this.currentTab === tabName) {
|
|
if (debugLogger) debugLogger.log('Switching to same tab, no action needed', {
|
|
tabName: tabName
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchTab', {
|
|
success: true,
|
|
action: 'no_change_needed',
|
|
currentTab: this.currentTab
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
const oldTab = this.currentTab;
|
|
|
|
// Update navigation buttons
|
|
const navButtons = document.querySelectorAll('.nav-btn');
|
|
let navButtonsUpdated = 0;
|
|
|
|
navButtons.forEach(btn => {
|
|
const wasActive = btn.classList.contains('active');
|
|
const shouldBeActive = btn.dataset.tab === tabName;
|
|
btn.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
navButtonsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Navigation buttons updated', {
|
|
totalButtons: navButtons.length,
|
|
buttonsUpdated: navButtonsUpdated
|
|
});
|
|
|
|
// Update tab content
|
|
const tabContents = document.querySelectorAll('.tab-content');
|
|
let tabContentsUpdated = 0;
|
|
|
|
tabContents.forEach(content => {
|
|
const wasActive = content.classList.contains('active');
|
|
const shouldBeActive = content.id === `${tabName}-tab`;
|
|
content.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
tabContentsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Tab contents updated', {
|
|
totalContents: tabContents.length,
|
|
contentsUpdated: tabContentsUpdated
|
|
});
|
|
|
|
this.currentTab = tabName;
|
|
this.game.state.currentTab = tabName;
|
|
|
|
if (debugLogger) debugLogger.logStep('Tab state updated', {
|
|
oldTab: oldTab,
|
|
newTab: this.currentTab,
|
|
gameStateUpdated: true
|
|
});
|
|
|
|
// Update specific tab content only if in multiplayer mode or game is actively running
|
|
if (this.shouldUpdateUI()) {
|
|
this.updateTabContent(tabName);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchTab', {
|
|
success: true,
|
|
oldTab: oldTab,
|
|
newTab: this.currentTab,
|
|
navButtonsUpdated: navButtonsUpdated,
|
|
tabContentsUpdated: tabContentsUpdated,
|
|
tabContentUpdated: true
|
|
});
|
|
}
|
|
|
|
updateTabContent(tabName) {
|
|
if (!this.shouldUpdateUI()) {
|
|
return;
|
|
}
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.updateTabContent', {
|
|
tabName: tabName,
|
|
currentTab: this.currentTab
|
|
});
|
|
|
|
let contentUpdated = false;
|
|
let updateError = null;
|
|
|
|
try {
|
|
switch(tabName) {
|
|
case 'dashboard':
|
|
// if (debugLogger) debugLogger.logStep('Updating dashboard tab content');
|
|
// Dashboard is the default view, no additional content to update
|
|
contentUpdated = true;
|
|
break;
|
|
case 'dungeons':
|
|
// if (debugLogger) debugLogger.logStep('Updating dungeons tab content');
|
|
|
|
// Ensure dungeon list is generated
|
|
if (window.game && window.game.systems && window.game.systems.dungeonSystem) {
|
|
// if (debugLogger) debugLogger.logStep('Ensuring dungeon list is generated...');
|
|
try {
|
|
window.game.systems.dungeonSystem.generateDungeonList();
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.updateTabContent', error, {
|
|
tabName: tabName
|
|
});
|
|
}
|
|
}
|
|
|
|
// Only regenerate dungeon list if it's empty (first time load)
|
|
const dungeonListElement = document.getElementById('dungeonList');
|
|
if (dungeonListElement && dungeonListElement.children.length === 0) {
|
|
if (this.game && this.game.systems && this.game.systems.dungeonSystem) {
|
|
this.game.systems.dungeonSystem.generateDungeonList();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Dungeon system not available');
|
|
}
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'skills':
|
|
// if (debugLogger) debugLogger.logStep('Updating skills tab content');
|
|
if (this.game && this.game.systems && this.game.systems.skillSystem) {
|
|
this.game.systems.skillSystem.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Skill system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'base':
|
|
// if (debugLogger) debugLogger.logStep('Updating base tab content');
|
|
if (this.game && this.game.systems && this.game.systems.baseSystem) {
|
|
this.game.systems.baseSystem.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Base system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'quests':
|
|
// if (debugLogger) debugLogger.logStep('Updating quests tab content');
|
|
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Quest system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'inventory':
|
|
// if (debugLogger) debugLogger.logStep('Updating inventory tab content');
|
|
if (this.game && this.game.systems && this.game.systems.inventory) {
|
|
this.game.systems.inventory.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Inventory system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'shop':
|
|
// if (debugLogger) debugLogger.logStep('Updating shop tab content');
|
|
if (this.game && this.game.systems && this.game.systems.economy) {
|
|
this.game.systems.economy.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Economy system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
case 'crafting':
|
|
// if (debugLogger) debugLogger.logStep('Updating crafting tab content');
|
|
if (this.game && this.game.systems && this.game.systems.crafting) {
|
|
this.game.systems.crafting.updateUI();
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Crafting system not available');
|
|
}
|
|
contentUpdated = true;
|
|
break;
|
|
default:
|
|
// if (debugLogger) debugLogger.log('Unknown tab name, no content updated', {
|
|
// tabName: tabName
|
|
// });
|
|
contentUpdated = false;
|
|
}
|
|
} catch (error) {
|
|
updateError = error;
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.updateTabContent', error, {
|
|
tabName: tabName
|
|
});
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.updateTabContent', {
|
|
tabName: tabName,
|
|
contentUpdated: contentUpdated,
|
|
updateError: updateError ? updateError.message : null
|
|
});
|
|
}
|
|
|
|
// Category switching
|
|
switchSkillCategory(category) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.switchSkillCategory', {
|
|
category: category
|
|
});
|
|
|
|
const skillCatButtons = document.querySelectorAll('.skill-cat-btn');
|
|
let buttonsUpdated = 0;
|
|
|
|
skillCatButtons.forEach(btn => {
|
|
const wasActive = btn.classList.contains('active');
|
|
const shouldBeActive = btn.dataset.category === category;
|
|
btn.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
buttonsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Skill category buttons updated', {
|
|
totalButtons: skillCatButtons.length,
|
|
buttonsUpdated: buttonsUpdated
|
|
});
|
|
|
|
try {
|
|
this.game.systems.skillSystem.updateUI();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchSkillCategory', {
|
|
success: true,
|
|
category: category,
|
|
buttonsUpdated: buttonsUpdated,
|
|
skillUIUpdated: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.switchSkillCategory', error, {
|
|
category: category
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchSkillCategory', {
|
|
success: false,
|
|
category: category,
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
switchShopCategory(category) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.switchShopCategory', {
|
|
category: category
|
|
});
|
|
|
|
const shopCatButtons = document.querySelectorAll('.shop-cat-btn');
|
|
let buttonsUpdated = 0;
|
|
|
|
shopCatButtons.forEach(btn => {
|
|
const wasActive = btn.classList.contains('active');
|
|
const shouldBeActive = btn.dataset.category === category;
|
|
btn.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
buttonsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Shop category buttons updated', {
|
|
totalButtons: shopCatButtons.length,
|
|
buttonsUpdated: buttonsUpdated
|
|
});
|
|
|
|
try {
|
|
// Call economy system update
|
|
this.game.systems.economy.updateUI();
|
|
|
|
// Also call global shop display function for additional debugging
|
|
if (typeof updateShopDisplay === 'function') {
|
|
updateShopDisplay();
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchShopCategory', {
|
|
success: true,
|
|
category: category,
|
|
buttonsUpdated: buttonsUpdated,
|
|
economyUIUpdated: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.switchShopCategory', error, {
|
|
category: category
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchShopCategory', {
|
|
success: false,
|
|
category: category,
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
updateQuestTabs(type) {
|
|
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
|
|
let buttonsUpdated = 0;
|
|
|
|
questTabButtons.forEach(btn => {
|
|
const wasActive = btn.classList.contains('active');
|
|
const shouldBeActive = btn.dataset.type === type;
|
|
btn.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
buttonsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Quest tab buttons updated', {
|
|
totalButtons: questTabButtons.length,
|
|
buttonsUpdated: buttonsUpdated
|
|
});
|
|
|
|
try {
|
|
// REMOVED: Client-side QuestSystem is now server-driven
|
|
// this.game.systems.questSystem.updateUI();
|
|
|
|
// Call the global quest display update function instead
|
|
if (typeof updateQuestDisplay === 'function') {
|
|
updateQuestDisplay();
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchQuestType', {
|
|
success: true,
|
|
type: type,
|
|
buttonsUpdated: buttonsUpdated,
|
|
questUIUpdated: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.switchQuestType', error, {
|
|
type: type
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchQuestType', {
|
|
success: false,
|
|
type: type,
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
switchCraftingCategory(category) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.switchCraftingCategory', {
|
|
category: category
|
|
});
|
|
|
|
const craftingCatButtons = document.querySelectorAll('.crafting-cat-btn');
|
|
let buttonsUpdated = 0;
|
|
|
|
craftingCatButtons.forEach(btn => {
|
|
const wasActive = btn.classList.contains('active');
|
|
const shouldBeActive = btn.dataset.category === category;
|
|
btn.classList.toggle('active', shouldBeActive);
|
|
|
|
if (wasActive !== shouldBeActive) {
|
|
buttonsUpdated++;
|
|
}
|
|
});
|
|
|
|
if (debugLogger) debugLogger.logStep('Crafting category buttons updated', {
|
|
totalButtons: craftingCatButtons.length,
|
|
buttonsUpdated: buttonsUpdated
|
|
});
|
|
|
|
try {
|
|
this.game.systems.crafting.switchCategory(category);
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchCraftingCategory', {
|
|
success: true,
|
|
category: category,
|
|
buttonsUpdated: buttonsUpdated,
|
|
craftingUIUpdated: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('UIManager.switchCraftingCategory', error, {
|
|
category: category
|
|
});
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.switchCraftingCategory', {
|
|
success: false,
|
|
category: category,
|
|
error: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
// Modal management
|
|
showModal(title, content) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.showModal', {
|
|
title: title,
|
|
contentLength: content.length,
|
|
modalWasOpen: this.modalOpen
|
|
});
|
|
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const modalBody = document.getElementById('modalBody');
|
|
|
|
if (!modalOverlay || !modalTitle || !modalBody) {
|
|
const missingElements = {
|
|
modalOverlay: !modalOverlay,
|
|
modalTitle: !modalTitle,
|
|
modalBody: !modalBody
|
|
};
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.showModal', {
|
|
success: false,
|
|
reason: 'missing_modal_elements',
|
|
missingElements: missingElements
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
const oldTitle = modalTitle.textContent;
|
|
const oldContent = modalBody.innerHTML;
|
|
|
|
modalTitle.textContent = title;
|
|
modalBody.innerHTML = content;
|
|
|
|
modalOverlay.classList.remove('hidden');
|
|
this.modalOpen = true;
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.showModal', {
|
|
success: true,
|
|
title: title,
|
|
contentLength: content.length,
|
|
oldTitle: oldTitle,
|
|
oldContentLength: oldContent.length,
|
|
modalNowOpen: true
|
|
});
|
|
}
|
|
|
|
closeModal() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.closeModal', {
|
|
modalWasOpen: this.modalOpen
|
|
});
|
|
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
|
|
if (modalOverlay) {
|
|
const wasHidden = modalOverlay.classList.contains('hidden');
|
|
modalOverlay.classList.add('hidden');
|
|
|
|
if (debugLogger) debugLogger.logStep('Modal overlay hidden', {
|
|
wasAlreadyHidden: wasHidden
|
|
});
|
|
} else {
|
|
if (debugLogger) debugLogger.log('Modal overlay element not found');
|
|
}
|
|
|
|
const wasModalOpen = this.modalOpen;
|
|
this.modalOpen = false;
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.closeModal', {
|
|
success: true,
|
|
modalOverlayFound: !!modalOverlay,
|
|
wasModalOpen: wasModalOpen,
|
|
modalNowClosed: !this.modalOpen
|
|
});
|
|
}
|
|
|
|
// Force refresh all UI elements (called when server data is updated)
|
|
forceRefreshAllUI() {
|
|
if (window.smartSaveManager?.isMultiplayer) {
|
|
console.log('[UI MANAGER] Force refreshing all UI elements with server data');
|
|
|
|
// Update all resource displays
|
|
this.updateResourceDisplay();
|
|
|
|
// Update current tab content
|
|
if (this.currentTab) {
|
|
this.updateTabContent(this.currentTab);
|
|
}
|
|
|
|
// Update quest system
|
|
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateUI();
|
|
}
|
|
|
|
console.log('[UI MANAGER] UI refresh completed');
|
|
}
|
|
}
|
|
|
|
// Handle UI update events from game engine
|
|
handleUIUpdate(data) {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.handleUIUpdate', data);
|
|
|
|
if (debugLogger) debugLogger.log('Handling UI update event:', data);
|
|
|
|
switch (data.type) {
|
|
case 'full':
|
|
this.updateAllUI();
|
|
break;
|
|
case 'economy':
|
|
this.updateResourceDisplay();
|
|
break;
|
|
case 'player':
|
|
this.updateResourceDisplay();
|
|
break;
|
|
case 'quests':
|
|
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateUI();
|
|
}
|
|
break;
|
|
case 'dailyCountdown':
|
|
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateDailyCountdown();
|
|
}
|
|
break;
|
|
case 'weeklyCountdown':
|
|
if (this.game && this.game.systems && this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateWeeklyCountdown();
|
|
}
|
|
break;
|
|
default:
|
|
if (debugLogger) debugLogger.log('Unknown update type:', data.type);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.handleUIUpdate', {
|
|
type: data.type,
|
|
handled: true
|
|
});
|
|
}
|
|
|
|
updateAllUI() {
|
|
if (!this.shouldUpdateUI()) {
|
|
return;
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.log('Updating all UI elements');
|
|
|
|
this.updateResourceDisplay();
|
|
|
|
// Update other UI components as needed
|
|
if (this.game && this.game.systems) {
|
|
// Update quest system
|
|
if (this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateUI();
|
|
}
|
|
|
|
// Update daily countdown
|
|
if (this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.updateDailyCountdown();
|
|
this.game.systems.questSystem.updateWeeklyCountdown();
|
|
}
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.log('All UI elements updated');
|
|
}
|
|
|
|
// Resource display
|
|
setupResourceDisplay() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.setupResourceDisplay');
|
|
|
|
// Resource display is handled in updateResourceDisplay method
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.setupResourceDisplay', {
|
|
setupCompleted: true
|
|
});
|
|
}
|
|
|
|
// Centralized UI update control - blocks all UI updates when not in multiplayer mode
|
|
shouldUpdateUI() {
|
|
const shouldUpdate = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
|
|
|
if (!shouldUpdate) {
|
|
console.log('[UI MANAGER] Blocking UI update - not in multiplayer mode');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Centralized update resource display - all calls should go through this
|
|
updateResourceDisplay() {
|
|
if (!this.shouldUpdateUI()) {
|
|
return;
|
|
}
|
|
|
|
// In multiplayer mode, ensure we're using server data
|
|
if (window.smartSaveManager?.isMultiplayer) {
|
|
// console.log('[UI MANAGER] Updating resource display in multiplayer mode - using server data');
|
|
}
|
|
|
|
// const debugLogger = window.debugLogger;
|
|
|
|
try {
|
|
// Safety checks - return early if systems aren't available
|
|
if (!this.game || !this.game.systems) {
|
|
// if (debugLogger) debugLogger.log('Game systems not available, skipping resource display update');
|
|
return;
|
|
}
|
|
|
|
if (!this.game.systems.player || !this.game.systems.economy) {
|
|
// if (debugLogger) debugLogger.log('Player or economy system not available, skipping resource display update');
|
|
return;
|
|
}
|
|
|
|
const player = this.game.systems.player;
|
|
const economy = this.game.systems.economy;
|
|
|
|
// Additional safety checks for player properties
|
|
if (!player.stats || !player.attributes || !player.ship) {
|
|
// if (debugLogger) debugLogger.log('Player properties not fully initialized, skipping resource display update');
|
|
return;
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.startStep('UIManager.updateResourceDisplay', {
|
|
// gameSystemsAvailable: !!(this.game && this.game.systems),
|
|
// playerSystemAvailable: !!(this.game && this.game.systems && this.game.systems.player),
|
|
// economySystemAvailable: !!(this.game && this.game.systems && this.game.systems.economy),
|
|
// playerStatsAvailable: !!player.stats,
|
|
// playerAttributesAvailable: !!player.attributes,
|
|
// playerShipAvailable: !!player.ship
|
|
// });
|
|
|
|
let elementsUpdated = 0;
|
|
let elementsNotFound = 0;
|
|
|
|
// Update player level with safety checks
|
|
const playerLevelElement = document.getElementById('playerLevel');
|
|
if (playerLevelElement) {
|
|
const oldLevel = playerLevelElement.textContent;
|
|
const playerLevel = player.stats.level || 1;
|
|
// console.log('[UI MANAGER] Updating player level:', { oldLevel, newLevel: playerLevel, playerStats: player.stats });
|
|
playerLevelElement.textContent = `Lv. ${playerLevel}`;
|
|
elementsUpdated++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Player level updated', {
|
|
oldLevel: oldLevel,
|
|
newLevel: playerLevelElement.textContent,
|
|
playerStatsLevel: player.stats.level
|
|
});
|
|
} else {
|
|
elementsNotFound++;
|
|
// if (debugLogger) debugLogger.log('Player level element not found');
|
|
}
|
|
|
|
// Update ship level with safety checks
|
|
const shipLevelElement = document.getElementById('currentShipLevel');
|
|
if (shipLevelElement) {
|
|
const oldShipLevel = shipLevelElement.textContent;
|
|
const shipLevel = player.ship.level || player.stats.level || 1;
|
|
shipLevelElement.textContent = shipLevel;
|
|
elementsUpdated++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Ship level updated', {
|
|
oldShipLevel: oldShipLevel,
|
|
newShipLevel: shipLevelElement.textContent,
|
|
playerShipLevel: player.ship.level,
|
|
playerStatsLevel: player.stats.level
|
|
});
|
|
} else {
|
|
elementsNotFound++;
|
|
if (debugLogger) debugLogger.log('Ship level element not found');
|
|
}
|
|
|
|
// Update credits with safety checks
|
|
const creditsElement = document.getElementById('credits');
|
|
if (creditsElement) {
|
|
const oldCredits = creditsElement.textContent;
|
|
const creditsAmount = economy.credits || 0;
|
|
// console.log('[UI MANAGER] Credits debug - economy.credits:', economy.credits, 'creditsAmount:', creditsAmount);
|
|
creditsElement.textContent = this.game.formatNumber(creditsAmount);
|
|
elementsUpdated++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Credits updated', {
|
|
oldCredits: oldCredits,
|
|
newCredits: creditsElement.textContent,
|
|
economyCredits: economy.credits,
|
|
formattedCredits: this.game.formatNumber(creditsAmount)
|
|
});
|
|
} else {
|
|
elementsNotFound++;
|
|
if (debugLogger) debugLogger.log('Credits element not found');
|
|
}
|
|
|
|
// Update gems with safety checks
|
|
const gemsElement = document.getElementById('gems');
|
|
if (gemsElement) {
|
|
const oldGems = gemsElement.textContent;
|
|
const gemsAmount = economy.gems || 0;
|
|
// console.log('[UI MANAGER] Gems debug - economy.gems:', economy.gems, 'gemsAmount:', gemsAmount);
|
|
gemsElement.textContent = this.game.formatNumber(gemsAmount);
|
|
elementsUpdated++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Gems updated', {
|
|
oldGems: oldGems,
|
|
newGems: gemsElement.textContent,
|
|
economyGems: economy.gems,
|
|
formattedGems: this.game.formatNumber(gemsAmount)
|
|
});
|
|
} else {
|
|
elementsNotFound++;
|
|
if (debugLogger) debugLogger.log('Gems element not found');
|
|
}
|
|
|
|
// Update energy with safety checks
|
|
const energyElement = document.getElementById('energy');
|
|
if (energyElement) {
|
|
const oldEnergy = energyElement.textContent;
|
|
const currentEnergy = player.attributes.currentEnergy || player.attributes.energy || 0;
|
|
const maxEnergy = player.attributes.maxEnergy || 100;
|
|
// console.log('[UI MANAGER] Energy debug - player.attributes.currentEnergy:', player.attributes.currentEnergy, 'player.attributes.maxEnergy:', player.attributes.maxEnergy);
|
|
energyElement.textContent = `${currentEnergy}/${maxEnergy}`;
|
|
elementsUpdated++;
|
|
|
|
if (debugLogger) debugLogger.logStep('Energy updated', {
|
|
oldEnergy: oldEnergy,
|
|
newEnergy: energyElement.textContent,
|
|
currentEnergy: currentEnergy,
|
|
maxEnergy: maxEnergy,
|
|
playerEnergy: player.attributes.energy,
|
|
playerMaxEnergy: player.attributes.maxEnergy
|
|
});
|
|
} else {
|
|
elementsNotFound++;
|
|
if (debugLogger) debugLogger.log('Energy element not found');
|
|
}
|
|
|
|
// Update play time (keep this here as it's part of the core resource display)
|
|
const playTimeElement = document.getElementById('playTime');
|
|
if (playTimeElement) {
|
|
const playTimeMs = player.stats.playTime || 0;
|
|
playTimeElement.textContent = this.formatPlayTime(playTimeMs);
|
|
elementsUpdated++;
|
|
}
|
|
|
|
// Update player stats panel
|
|
const playerLevelDisplayElement = document.getElementById('playerLevelDisplay');
|
|
if (playerLevelDisplayElement) {
|
|
playerLevelDisplayElement.textContent = player.stats.level || 1;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const playerXPElement = document.getElementById('playerXP');
|
|
if (playerXPElement) {
|
|
const currentXP = player.stats.experience || 0;
|
|
const xpToNext = player.stats.experienceToNext || 100;
|
|
playerXPElement.textContent = `${currentXP} / ${xpToNext}`;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const skillPointsElement = document.getElementById('skillPoints');
|
|
if (skillPointsElement) {
|
|
skillPointsElement.textContent = player.stats.skillPoints || 0;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const totalXPElement = document.getElementById('totalXP');
|
|
if (totalXPElement) {
|
|
totalXPElement.textContent = this.game.formatNumber(player.stats.totalXP || 0);
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const questsCompletedElement = document.getElementById('questsCompleted');
|
|
if (questsCompletedElement) {
|
|
// Use player stats from server first, then quest system stats as fallback
|
|
const questsCompleted = player.stats.questsCompleted ||
|
|
(this.game.systems.questSystem?.stats?.questsCompleted) || 0;
|
|
questsCompletedElement.textContent = questsCompleted;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const lastLoginElement = document.getElementById('lastLogin');
|
|
if (lastLoginElement) {
|
|
const lastLogin = player.stats.lastLogin;
|
|
if (lastLogin) {
|
|
const loginDate = new Date(lastLogin);
|
|
lastLoginElement.textContent = loginDate.toLocaleDateString() + ' ' + loginDate.toLocaleTimeString();
|
|
} else {
|
|
lastLoginElement.textContent = 'Never';
|
|
}
|
|
elementsUpdated++;
|
|
}
|
|
|
|
// Update all player stats
|
|
this.updatePlayerStats();
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.updateResourceDisplay', {
|
|
elementsUpdated: elementsUpdated,
|
|
elementsNotFound: elementsNotFound,
|
|
playerLevel: player.stats.level || 1,
|
|
shipLevel: player.ship.level || player.stats.level || 1,
|
|
credits: economy.credits || 0,
|
|
gems: economy.gems || 0,
|
|
currentEnergy: Math.floor(player.attributes.energy || 0),
|
|
maxEnergy: Math.floor(player.attributes.maxEnergy || 100)
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.log('Error in updateResourceDisplay', {
|
|
error: error.message,
|
|
stack: error.stack
|
|
});
|
|
}
|
|
}
|
|
|
|
formatPlayTime(milliseconds) {
|
|
// Format play time showing only the two most relevant units
|
|
const totalSeconds = Math.floor(milliseconds / 1000);
|
|
|
|
if (totalSeconds < 60) {
|
|
// Less than 1 minute: show seconds only
|
|
return `${totalSeconds}s`;
|
|
} else if (totalSeconds < 3600) {
|
|
// Less than 1 hour: show minutes and seconds
|
|
const minutes = Math.floor(totalSeconds / 60);
|
|
const seconds = totalSeconds % 60;
|
|
return `${minutes}m ${seconds}s`;
|
|
} else if (totalSeconds < 86400) {
|
|
// Less than 1 day: show hours and minutes
|
|
const hours = Math.floor(totalSeconds / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
return `${hours}h ${minutes}m`;
|
|
} else {
|
|
// 1 day or more: show days and hours
|
|
const days = Math.floor(totalSeconds / 86400);
|
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
|
return `${days}d ${hours}h`;
|
|
}
|
|
}
|
|
|
|
updatePlayerStats() {
|
|
// Update just the player stats panel (excluding those handled in updateResourceDisplay)
|
|
if (!this.game || !this.game.systems || !this.game.systems.player) {
|
|
return;
|
|
}
|
|
|
|
const player = this.game.systems.player;
|
|
let elementsUpdated = 0;
|
|
|
|
// Update player stats panel
|
|
const playerLevelDisplayElement = document.getElementById('playerLevelDisplay');
|
|
if (playerLevelDisplayElement) {
|
|
playerLevelDisplayElement.textContent = player.stats.level || 1;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const playerXPElement = document.getElementById('playerXP');
|
|
if (playerXPElement) {
|
|
const currentXP = player.stats.experience || 0;
|
|
const xpToNext = player.stats.experienceToNext || 100;
|
|
playerXPElement.textContent = `${currentXP} / ${xpToNext}`;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const skillPointsElement = document.getElementById('skillPoints');
|
|
if (skillPointsElement) {
|
|
skillPointsElement.textContent = player.stats.skillPoints || 0;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const totalXPElement = document.getElementById('totalXP');
|
|
if (totalXPElement) {
|
|
totalXPElement.textContent = this.game.formatNumber(player.stats.totalXP || 0);
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const questsCompletedElement = document.getElementById('questsCompleted');
|
|
if (questsCompletedElement) {
|
|
// Use player stats from server first, then quest system stats as fallback
|
|
const questsCompleted = player.stats.questsCompleted ||
|
|
(this.game.systems.questSystem?.stats?.questsCompleted) || 0;
|
|
questsCompletedElement.textContent = questsCompleted;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const lastLoginElement = document.getElementById('lastLogin');
|
|
if (lastLoginElement) {
|
|
const lastLogin = player.stats.lastLogin;
|
|
if (lastLogin) {
|
|
const loginDate = new Date(lastLogin);
|
|
lastLoginElement.textContent = loginDate.toLocaleDateString() + ' ' + loginDate.toLocaleTimeString();
|
|
} else {
|
|
lastLoginElement.textContent = 'Never';
|
|
}
|
|
elementsUpdated++;
|
|
}
|
|
|
|
// Update stats moved from Idle Progress card
|
|
const totalKillsElement = document.getElementById('totalKills');
|
|
if (totalKillsElement) {
|
|
totalKillsElement.textContent = this.game.formatNumber(player.stats.totalKills || 0);
|
|
elementsUpdated++;
|
|
}
|
|
|
|
const dungeonsClearedElement = document.getElementById('dungeonsCleared');
|
|
if (dungeonsClearedElement) {
|
|
dungeonsClearedElement.textContent = player.stats.dungeonsCleared || 0;
|
|
elementsUpdated++;
|
|
}
|
|
|
|
// DISABLED: Reduce console spam for quest debugging
|
|
// console.log(`[UI MANAGER] Player stats updated: ${elementsUpdated} elements`);
|
|
}
|
|
|
|
updateUI() {
|
|
// const debugLogger = window.debugLogger;
|
|
|
|
// if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
|
|
// currentTab: this.currentTab,
|
|
// modalOpen: this.modalOpen
|
|
// });
|
|
|
|
// Update resource display only if in multiplayer mode or game is actively running
|
|
if (this.shouldUpdateUI()) {
|
|
// if (debugLogger) debugLogger.logStep('Updating resource display');
|
|
this.updateResourceDisplay();
|
|
}
|
|
|
|
// Update tab content only if in multiplayer mode or game is actively running
|
|
if (this.shouldUpdateUI()) {
|
|
// if (debugLogger) debugLogger.logStep('Updating tab content', {
|
|
// currentTab: this.currentTab
|
|
// });
|
|
this.updateTabContent(this.currentTab);
|
|
}
|
|
|
|
// if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
|
|
// resourceDisplayUpdated: true,
|
|
// tabContentUpdated: true,
|
|
// currentTab: this.currentTab
|
|
// });
|
|
}
|
|
|
|
// Menus
|
|
showSettingsMenu() {
|
|
|
|
// Clear any existing modal content first
|
|
const modalBody = document.getElementById('modalBody');
|
|
if (modalBody) {
|
|
modalBody.innerHTML = '';
|
|
}
|
|
|
|
// Get current auto-save setting
|
|
const currentAutoSaveInterval = localStorage.getItem('autoSaveInterval') || '5';
|
|
|
|
let content = '<div class="settings-menu">';
|
|
content += '<h3>Game Settings</h3>';
|
|
content += '<div class="settings-section">';
|
|
content += '<h4>Auto-Save Settings</h4>';
|
|
content += '<p>Configure how often your game automatically saves:</p>';
|
|
|
|
content += '<div class="setting-group">';
|
|
content += '<label for="autoSaveInterval">Auto-Save Interval:</label>';
|
|
content += '<select id="autoSaveInterval" class="setting-select">';
|
|
content += '<option value="1" ' + (currentAutoSaveInterval === '1' ? 'selected' : '') + '>1 minute</option>';
|
|
content += '<option value="5" ' + (currentAutoSaveInterval === '5' ? 'selected' : '') + '>5 minutes</option>';
|
|
content += '<option value="10" ' + (currentAutoSaveInterval === '10' ? 'selected' : '') + '>10 minutes</option>';
|
|
content += '<option value="15" ' + (currentAutoSaveInterval === '15' ? 'selected' : '') + '>15 minutes</option>';
|
|
content += '<option value="30" ' + (currentAutoSaveInterval === '30' ? 'selected' : '') + '>30 minutes</option>';
|
|
content += '</select>';
|
|
content += '</div>';
|
|
|
|
content += '<div class="setting-actions">';
|
|
content += '<button class="btn btn-primary" onclick="if(window.game && window.game.systems) window.game.systems.ui.saveAutoSaveSettings()">Save Settings</button>';
|
|
content += '</div>';
|
|
content += '</div>';
|
|
|
|
content += '<div class="settings-section">';
|
|
content += '<h4>Reset Options</h4>';
|
|
content += '<div class="settings-description">';
|
|
content += '<p>Choose your reset option:</p>';
|
|
content += '</div>';
|
|
content += '<div class="reset-options">';
|
|
|
|
content += `
|
|
<div class="reset-option">
|
|
<h4>Reset Character</h4>
|
|
<p>Reset your character to level 1 and clear progress, but keep your inventory items.</p>
|
|
<ul>
|
|
<li>Character level and stats reset</li>
|
|
<li>Skills and abilities reset</li>
|
|
<li>Quest progress cleared</li>
|
|
<li>Economy reset to starting values</li>
|
|
<li>Inventory items preserved</li>
|
|
</ul>
|
|
<button class="btn btn-danger" onclick="if(window.game && window.game.systems) window.game.systems.ui.confirmResetCharacter()">Reset Character</button>
|
|
</div>
|
|
|
|
<div class="reset-option">
|
|
<h4>Hard Reset</h4>
|
|
<p>Completely clear ALL saved data including inventory, settings, and local storage.</p>
|
|
<ul>
|
|
<li>Character progress and stats</li>
|
|
<li>Inventory and items</li>
|
|
<li>Quest progress</li>
|
|
<li>Settings and preferences</li>
|
|
<li>All local application data</li>
|
|
</ul>
|
|
<button class="btn btn-warning" onclick="if(window.game && window.game.systems) window.game.systems.ui.confirmHardReset()">Hard Reset</button>
|
|
</div>
|
|
`;
|
|
|
|
content += '</div>';
|
|
content += '<div class="settings-actions">';
|
|
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems) window.game.systems.ui.closeModal()">Close</button>';
|
|
content += '</div>';
|
|
content += '</div>';
|
|
|
|
// Force modal update with timestamp to prevent caching
|
|
const timestamp = Date.now();
|
|
this.showModal('Settings', content + `<!-- Updated: ${timestamp} -->`);
|
|
}
|
|
|
|
saveAutoSaveSettings() {
|
|
const autoSaveInterval = document.getElementById('autoSaveInterval');
|
|
if (autoSaveInterval) {
|
|
const selectedInterval = autoSaveInterval.value;
|
|
localStorage.setItem('autoSaveInterval', selectedInterval);
|
|
|
|
// Update game engine auto-save if game is running
|
|
if (window.game && window.game.isRunning) {
|
|
window.game.updateAutoSaveInterval(parseInt(selectedInterval));
|
|
}
|
|
|
|
this.game.showNotification(`Auto-save interval set to ${selectedInterval} minute(s)`, 'success', 3000);
|
|
}
|
|
this.closeModal();
|
|
}
|
|
|
|
confirmResetCharacter() {
|
|
|
|
let content = '<div class="confirmation-dialog">';
|
|
content += '<h3>Reset Character</h3>';
|
|
content += '<p><strong>Warning:</strong> This will reset your character to level 1 and clear all progress, but will keep your settings and preferences.</p>';
|
|
content += '<ul>';
|
|
content += '<li>Character level and stats reset</li>';
|
|
content += '<li>Skills and abilities reset</li>';
|
|
content += '<li>Quest progress cleared</li>';
|
|
content += '<li>Economy reset to starting values</li>';
|
|
content += '<li>Inventory items preserved</li>';
|
|
content += '</ul>';
|
|
content += '<div class="confirmation-actions">';
|
|
content += '<button class="btn btn-danger" onclick="if(window.game && window.game.systems) window.game.systems.ui.resetCharacter()">Reset Character</button>';
|
|
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems) window.game.systems.ui.closeModal()">Cancel</button>';
|
|
content += '</div>';
|
|
content += '</div>';
|
|
|
|
this.showModal('Confirm Reset', content);
|
|
}
|
|
|
|
confirmHardReset() {
|
|
let content = '<div class="reset-confirmation">';
|
|
content += '<h3>Hard Reset - Clear All Data</h3>';
|
|
content += '<p><strong>Warning:</strong> This will completely clear ALL saved data including:</p>';
|
|
content += '<ul>';
|
|
content += '<li>Character progress and stats</li>';
|
|
content += '<li>Inventory and items</li>';
|
|
content += '<li>Quest progress</li>';
|
|
content += '<li>Settings and preferences</li>';
|
|
content += '<li>All local application data</li>';
|
|
content += '</ul>';
|
|
content += '<p>This will completely reset the application to its initial state. This action cannot be undone!</p>';
|
|
content += '<div class="confirmation-actions">';
|
|
content += '<button class="btn btn-danger" onclick="if(window.game && window.game.systems) window.game.systems.ui.hardReset()">Hard Reset</button>';
|
|
content += '<button class="btn btn-secondary" onclick="if(window.game && window.game.systems) window.game.systems.ui.closeModal()">Cancel</button>';
|
|
content += '</div>';
|
|
content += '</div>';
|
|
|
|
this.showModal('Confirm Hard Reset', content);
|
|
}
|
|
|
|
resetCharacter() {
|
|
|
|
// Reset character data only
|
|
if (this.game && this.game.systems) {
|
|
|
|
// Reset player to initial state
|
|
if (this.game.systems.player) {
|
|
this.game.systems.player.resetToLevel1();
|
|
} else {
|
|
}
|
|
|
|
// Reset economy - only reset if not in multiplayer mode
|
|
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
|
this.game.systems.economy.credits = 1000;
|
|
this.game.systems.economy.gems = 10;
|
|
}
|
|
|
|
// Keep inventory intact for soft reset (only reset max slots if needed)
|
|
if (this.game.systems.inventory) {
|
|
// Preserve items, only reset max slots to default
|
|
if (this.game.systems.inventory.maxSlots !== 20) {
|
|
this.game.systems.inventory.maxSlots = 20;
|
|
}
|
|
}
|
|
|
|
// Clear quest progress
|
|
if (this.game.systems.questSystem) {
|
|
this.game.systems.questSystem.mainQuests.forEach(quest => {
|
|
quest.status = quest.id === 'tutorial_complete' ? 'available' : 'locked';
|
|
quest.objectives.forEach(obj => obj.current = 0);
|
|
});
|
|
this.game.systems.questSystem.activeQuests = [];
|
|
this.game.systems.questSystem.completedQuests = [];
|
|
this.game.systems.questSystem.failedQuests = [];
|
|
}
|
|
|
|
// Clear dungeon progress
|
|
if (this.game.systems.dungeonSystem) {
|
|
this.game.systems.dungeonSystem.stats = {
|
|
dungeonsAttempted: 0,
|
|
dungeonsCompleted: 0,
|
|
totalEnemiesDefeated: 0,
|
|
bestTime: Infinity,
|
|
totalLootEarned: 0
|
|
};
|
|
this.game.systems.dungeonSystem.currentDungeon = null;
|
|
this.game.systems.dungeonSystem.currentRoom = null;
|
|
this.game.systems.dungeonSystem.isExploring = false;
|
|
}
|
|
|
|
// Reset skills
|
|
if (this.game.systems.skillSystem) {
|
|
this.game.systems.skillSystem.skills = {};
|
|
}
|
|
|
|
// Force UI update after reset
|
|
if (this.game.systems.player) {
|
|
this.game.systems.player.updateUI();
|
|
}
|
|
|
|
// Save the reset state
|
|
this.game.saveGame();
|
|
|
|
this.game.showNotification('Character reset successfully!', 'success', 5000);
|
|
this.closeModal();
|
|
|
|
// Clear any modal content to prevent old panel showing
|
|
const modalBody = document.getElementById('modalBody');
|
|
if (modalBody) {
|
|
modalBody.innerHTML = '';
|
|
}
|
|
|
|
// Force close any open modals
|
|
const modalOverlay = document.getElementById('modalOverlay');
|
|
if (modalOverlay) {
|
|
modalOverlay.classList.add('hidden');
|
|
}
|
|
|
|
// Reload the page to refresh UI
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
hardReset() {
|
|
|
|
// Force cache busting check
|
|
const version = Date.now();
|
|
|
|
// Clear in-memory game data first
|
|
if (this.game && this.game.systems) {
|
|
|
|
// Clear inventory data
|
|
if (this.game.systems.inventory) {
|
|
this.game.systems.inventory.items = [];
|
|
this.game.systems.inventory.equipment = {
|
|
weapon: null,
|
|
armor: null,
|
|
engine: null,
|
|
shield: null,
|
|
accessory: null
|
|
};
|
|
}
|
|
|
|
// Clear player data
|
|
if (this.game.systems.player) {
|
|
this.game.systems.player.stats = {
|
|
level: 1,
|
|
experience: 0,
|
|
experienceToNext: 100,
|
|
skillPoints: 0,
|
|
totalKills: 0,
|
|
dungeonsCleared: 0,
|
|
playTime: 0,
|
|
lastLogin: Date.now(),
|
|
tutorialDungeonCompleted: false
|
|
};
|
|
this.game.systems.player.attributes = {
|
|
health: 100,
|
|
maxHealth: 100,
|
|
energy: 100,
|
|
maxEnergy: 100,
|
|
attack: 10,
|
|
defense: 5,
|
|
speed: 10,
|
|
criticalChance: 0.05,
|
|
criticalDamage: 1.5
|
|
};
|
|
}
|
|
|
|
// Clear economy data - only reset if not in multiplayer mode
|
|
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
|
this.game.systems.economy.credits = 1000;
|
|
this.game.systems.economy.gems = 10;
|
|
}
|
|
|
|
// Clear quest progress including dailies
|
|
if (this.game.systems.questSystem) {
|
|
try {
|
|
// Reset main quests
|
|
if (this.game.systems.questSystem.mainQuests && Array.isArray(this.game.systems.questSystem.mainQuests)) {
|
|
this.game.systems.questSystem.mainQuests.forEach(quest => {
|
|
if (quest && quest.objectives) {
|
|
quest.status = quest.id === 'tutorial_complete' ? 'available' : 'locked';
|
|
quest.objectives.forEach(obj => obj.current = 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Reset daily quests - force all to available regardless of current status
|
|
if (this.game.systems.questSystem.dailyQuests && Array.isArray(this.game.systems.questSystem.dailyQuests)) {
|
|
this.game.systems.questSystem.dailyQuests.forEach(quest => {
|
|
if (quest && quest.objectives) {
|
|
quest.status = 'available';
|
|
quest.objectives.forEach(obj => obj.current = 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Reset procedural quests
|
|
if (this.game.systems.questSystem.proceduralQuests && Array.isArray(this.game.systems.questSystem.proceduralQuests)) {
|
|
this.game.systems.questSystem.proceduralQuests.forEach(quest => {
|
|
if (quest && quest.objectives) {
|
|
quest.status = 'available';
|
|
quest.objectives.forEach(obj => obj.current = 0);
|
|
}
|
|
});
|
|
}
|
|
} catch (error) {
|
|
// Continue with reset even if quest clearing fails
|
|
}
|
|
|
|
// Force clear all quest tracking arrays
|
|
this.game.systems.questSystem.activeQuests = [];
|
|
this.game.systems.questSystem.completedQuests = [];
|
|
this.game.systems.questSystem.failedQuests = [];
|
|
|
|
// Clear any quest timers or intervals
|
|
if (this.game.systems.questSystem.dailyCountdownInterval) {
|
|
clearInterval(this.game.systems.questSystem.dailyCountdownInterval);
|
|
this.game.systems.questSystem.dailyCountdownInterval = null;
|
|
}
|
|
|
|
if (this.game.systems.questSystem.weeklyCountdownInterval) {
|
|
clearInterval(this.game.systems.questSystem.weeklyCountdownInterval);
|
|
this.game.systems.questSystem.weeklyCountdownInterval = null;
|
|
}
|
|
|
|
// Reset quest statistics
|
|
this.game.systems.questSystem.stats = {
|
|
questsCompleted: 0,
|
|
dailyQuestsCompleted: 0,
|
|
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
|
|
lastDailyReset: Date.now()
|
|
};
|
|
|
|
// Force quest availability check to ensure clean state
|
|
this.game.systems.questSystem.checkQuestAvailability();
|
|
}
|
|
}
|
|
|
|
// Clear ALL browser storage data
|
|
localStorage.clear();
|
|
sessionStorage.clear();
|
|
|
|
// Clear any IndexedDB data if present
|
|
if (window.indexedDB) {
|
|
const databases = ['galaxy_strike_online', 'game_data', 'player_data'];
|
|
databases.forEach(dbName => {
|
|
indexedDB.deleteDatabase(dbName);
|
|
});
|
|
}
|
|
|
|
// Clear any cookies for this domain
|
|
document.cookie.split(";").forEach(function(c) {
|
|
document.cookie = c.replace(/^ +/, "").replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
|
|
});
|
|
|
|
// Clear service workers if present (with proper error handling)
|
|
if ('serviceWorker' in navigator) {
|
|
try {
|
|
navigator.serviceWorker.getRegistrations().then(function(registrations) {
|
|
registrations.forEach(function(registration) {
|
|
try {
|
|
registration.unregister();
|
|
} catch (error) {
|
|
}
|
|
});
|
|
}).catch(function(error) {
|
|
});
|
|
} catch (error) {
|
|
}
|
|
}
|
|
|
|
// Clear application cache if present (with fallback for older browsers)
|
|
if ('caches' in window) {
|
|
try {
|
|
caches.keys().then(function(cacheNames) {
|
|
return Promise.all(cacheNames.map(function(cacheName) {
|
|
return caches.delete(cacheName);
|
|
}));
|
|
}).then(function() {
|
|
}).catch(function(error) {
|
|
});
|
|
} catch (error) {
|
|
}
|
|
}
|
|
|
|
// Force garbage collection to clear RAM cache
|
|
if (window.gc) {
|
|
window.gc();
|
|
}
|
|
|
|
// Clear any global variables that might hold game data
|
|
if (window.game) {
|
|
window.game = null;
|
|
}
|
|
|
|
this.game.showNotification('All data cleared successfully! The page will reload...', 'success', 5000);
|
|
this.closeModal();
|
|
|
|
// Force complete page reload with aggressive cache busting
|
|
setTimeout(() => {
|
|
// Add multiple cache-busting parameters
|
|
const timestamp = Date.now();
|
|
const random = Math.random().toString(36).substring(7);
|
|
window.location.href = window.location.origin + window.location.pathname + '?t=' + timestamp + '&r=' + random + '&force=1';
|
|
}, 1000);
|
|
}
|
|
|
|
showDiscordIntegration() {
|
|
let content = '<div class="discord-integration">';
|
|
content += '<h3>Discord Integration</h3>';
|
|
content += '<p>Connect your game to Discord for real-time updates and notifications!</p>';
|
|
|
|
content += '<div class="discord-features">';
|
|
content += '<h4>Features:</h4>';
|
|
content += '<ul>';
|
|
content += '<li>Real-time achievement notifications</li>';
|
|
content += '<li>Dungeon completion alerts</li>';
|
|
content += '<li>Level up notifications</li>';
|
|
content += '<li>Daily quest reminders</li>';
|
|
content += '<li>Statistics tracking</li>';
|
|
content += '</ul>';
|
|
content += '</div>';
|
|
|
|
content += '<div class="discord-setup">';
|
|
content += '<h4>Setup Instructions:</h4>';
|
|
content += '<ol>';
|
|
content += '<li>Create a Discord server or use an existing one</li>';
|
|
content += '<li>Create a webhook URL in server settings</li>';
|
|
content += '<li>Enter the webhook URL below</li>';
|
|
content += '<li>Test the connection</li>';
|
|
content += '</ol>';
|
|
content += '</div>';
|
|
|
|
content += '<div class="discord-config">';
|
|
content += '<input type="url" placeholder="Enter Discord webhook URL..." id="discordWebhookUrl">';
|
|
content += '<button class="btn btn-primary" onclick="if(window.game && window.game.systems) window.game.systems.ui.testDiscordWebhook()">Test Connection</button>';
|
|
content += '<button class="btn btn-success" onclick="if(window.game && window.game.systems) window.game.systems.ui.saveDiscordWebhook()">Save Integration</button>';
|
|
content += '</div>';
|
|
|
|
content += '</div>';
|
|
|
|
this.showModal('Discord Integration', content);
|
|
}
|
|
|
|
testDiscordWebhook() {
|
|
const urlInput = document.getElementById('discordWebhookUrl');
|
|
const webhookUrl = urlInput?.value;
|
|
|
|
if (!webhookUrl) {
|
|
this.game.showNotification('Please enter a webhook URL', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
// Test webhook (would need actual webhook implementation)
|
|
this.game.showNotification('Testing Discord webhook...', 'info', 2000);
|
|
|
|
// Simulate webhook test
|
|
setTimeout(() => {
|
|
this.game.showNotification('Discord webhook test successful!', 'success', 3000);
|
|
}, 2000);
|
|
}
|
|
|
|
saveDiscordWebhook() {
|
|
const urlInput = document.getElementById('discordWebhookUrl');
|
|
const webhookUrl = urlInput?.value;
|
|
|
|
if (!webhookUrl) {
|
|
this.game.showNotification('Please enter a webhook URL', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
// Save webhook URL
|
|
localStorage.setItem('discordWebhookUrl', webhookUrl);
|
|
this.game.systems.player.settings.discordIntegration = true;
|
|
|
|
this.game.showNotification('Discord integration saved!', 'success', 3000);
|
|
this.closeModal();
|
|
}
|
|
|
|
// Notification display
|
|
showNotification(message, type = 'info', duration = 3000) {
|
|
const notification = document.createElement('div');
|
|
notification.className = `notification ${type}`;
|
|
notification.textContent = message;
|
|
|
|
// Position notification
|
|
notification.style.top = `${20 + (this.notifications.length * 70)}px`;
|
|
|
|
document.body.appendChild(notification);
|
|
this.notifications.push(notification);
|
|
|
|
// Auto remove
|
|
setTimeout(() => {
|
|
this.removeNotification(notification);
|
|
}, duration);
|
|
|
|
// Manual close on click
|
|
notification.addEventListener('click', () => {
|
|
this.removeNotification(notification);
|
|
});
|
|
}
|
|
|
|
removeNotification(notification) {
|
|
const index = this.notifications.indexOf(notification);
|
|
if (index > -1) {
|
|
this.notifications.splice(index, 1);
|
|
}
|
|
|
|
notification.style.opacity = '0';
|
|
notification.style.transform = 'translateX(100%)';
|
|
|
|
setTimeout(() => {
|
|
if (notification.parentNode) {
|
|
notification.parentNode.removeChild(notification);
|
|
}
|
|
|
|
// Reposition remaining notifications
|
|
this.repositionNotifications();
|
|
}, 300);
|
|
}
|
|
|
|
repositionNotifications() {
|
|
this.notifications.forEach((notification, index) => {
|
|
notification.style.top = `${20 + (index * 70)}px`;
|
|
});
|
|
}
|
|
|
|
// Loading states
|
|
showLoading(elementId, message = 'Loading...') {
|
|
const element = document.getElementById(elementId);
|
|
if (element) {
|
|
element.innerHTML = `
|
|
<div class="loading-state">
|
|
<div class="loading-spinner"></div>
|
|
<p>${message}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
hideLoading(elementId, content) {
|
|
const element = document.getElementById(elementId);
|
|
if (element) {
|
|
element.innerHTML = content || '';
|
|
}
|
|
}
|
|
|
|
checkAndStartTutorial() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
if (debugLogger) debugLogger.startStep('UIManager.checkAndStartTutorial');
|
|
|
|
try {
|
|
// Check if First Steps quest is active and tutorial dungeon hasn't been completed
|
|
const questSystem = this.game.systems.questSystem;
|
|
const player = this.game.systems.player;
|
|
|
|
if (!questSystem || !player) {
|
|
if (debugLogger) debugLogger.logStep('Quest system or player not available');
|
|
return;
|
|
}
|
|
|
|
const firstStepsQuest = questSystem.findQuest('tutorial_complete');
|
|
const tutorialCompleted = player.stats.tutorialDungeonCompleted;
|
|
|
|
if (debugLogger) debugLogger.logStep('Checking tutorial conditions', {
|
|
firstStepsQuestFound: !!firstStepsQuest,
|
|
questStatus: firstStepsQuest ? firstStepsQuest.status : 'not_found',
|
|
tutorialCompleted: tutorialCompleted
|
|
});
|
|
|
|
// Start tutorial dungeon if:
|
|
// 1. First Steps quest exists and is active
|
|
// 2. Tutorial dungeon hasn't been completed
|
|
if (firstStepsQuest &&
|
|
firstStepsQuest.status === 'active' &&
|
|
!tutorialCompleted) {
|
|
|
|
if (debugLogger) debugLogger.logStep('Auto-starting tutorial dungeon');
|
|
|
|
// Switch to dungeons tab
|
|
this.switchTab('dungeons');
|
|
|
|
// Start tutorial dungeon after a short delay to let UI update
|
|
setTimeout(() => {
|
|
if (this.game.systems.dungeonSystem) {
|
|
this.game.systems.dungeonSystem.startTutorialDungeon();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
if (debugLogger) debugLogger.endStep('UIManager.checkAndStartTutorial');
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent(error, 'UIManager.checkAndStartTutorial');
|
|
}
|
|
}
|
|
|
|
// Notification system
|
|
showNotification(message, type = 'info', duration = 3000) {
|
|
const notification = document.createElement('div');
|
|
notification.className = `notification notification-${type}`;
|
|
notification.textContent = message;
|
|
|
|
document.body.appendChild(notification);
|
|
this.notifications.push(notification);
|
|
|
|
// Auto-remove notification after duration
|
|
setTimeout(() => {
|
|
this.removeNotification(notification);
|
|
}, duration);
|
|
}
|
|
|
|
removeNotification(notification) {
|
|
const index = this.notifications.indexOf(notification);
|
|
if (index > -1) {
|
|
this.notifications.splice(index, 1);
|
|
}
|
|
|
|
if (notification.parentNode) {
|
|
notification.parentNode.removeChild(notification);
|
|
}
|
|
}
|
|
|
|
// Utility methods
|
|
formatNumber(num) {
|
|
return this.game.formatNumber(num);
|
|
}
|
|
|
|
formatTime(milliseconds) {
|
|
return this.game.formatTime(milliseconds);
|
|
}
|
|
|
|
createProgressBar(current, max, showText = true) {
|
|
const percent = Math.min(100, (current / max) * 100);
|
|
const text = showText ? `<span>${current}/${max}</span>` : '';
|
|
|
|
return `
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${percent}%"></div>
|
|
${text}
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
createButton(text, className = 'btn-primary', onClick = '', disabled = false) {
|
|
return `
|
|
<button class="btn ${className} ${disabled ? 'disabled' : ''}"
|
|
onclick="${onClick}"
|
|
${disabled ? 'disabled' : ''}>
|
|
${text}
|
|
</button>
|
|
`;
|
|
}
|
|
}
|
|
|
|
// Export UIManager to global scope
|
|
if (typeof window !== 'undefined') {
|
|
window.UIManager = UIManager;
|
|
} |