almost a full rework of the client with server data-driven calls

This commit is contained in:
Robert MacRae 2026-01-26 17:16:42 -04:00
parent 4aeb217e51
commit b793b85e25
21 changed files with 4156 additions and 5892 deletions

View File

@ -10,8 +10,6 @@
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
<script src="js/SimpleLocalServer.js"></script>
<script src="js/LocalServerManager.js"></script>
</head>
<body>
<!-- Custom Title Bar -->
@ -220,10 +218,16 @@
<div class="header-left">
<h1 class="logo">GSO</h1>
<div class="player-info">
<div>
<span class="player-name" id="playerName">Commander</span>
<span class="player-title" id="playerTitle">- Rookie Pilot</span>
</div>
<div>
<span class="player-username" id="playerUsername"></span>
<span class="player-level" id="playerLevel">Lv. 1</span>
</div>
</div>
</div>
<div class="header-center">
<div class="resources">
<div class="resource">
@ -261,35 +265,35 @@
<!-- Navigation -->
<nav class="main-nav">
<button class="nav-btn active" data-tab="dashboard">
<button class="nav-btn active" data-tab="dashboard" onclick="switchToTab('dashboard')">
<i class="fas fa-tachometer-alt"></i>
<span>Dashboard</span>
</button>
<button class="nav-btn" data-tab="dungeons">
<button class="nav-btn" data-tab="dungeons" onclick="switchToTab('dungeons')">
<i class="fas fa-dungeon"></i>
<span>Dungeons</span>
</button>
<button class="nav-btn" data-tab="skills">
<button class="nav-btn" data-tab="skills" onclick="switchToTab('skills')">
<i class="fas fa-graduation-cap"></i>
<span>Skills</span>
</button>
<button class="nav-btn" data-tab="base">
<button class="nav-btn" data-tab="base" onclick="switchToTab('base')">
<i class="fas fa-home"></i>
<span>Base</span>
</button>
<button class="nav-btn" data-tab="quests">
<button class="nav-btn" data-tab="quests" onclick="switchToTab('quests')">
<i class="fas fa-scroll"></i>
<span>Quests</span>
</button>
<button class="nav-btn" data-tab="inventory">
<button class="nav-btn" data-tab="inventory" onclick="switchToTab('inventory')">
<i class="fas fa-backpack"></i>
<span>Inventory</span>
</button>
<button class="nav-btn" data-tab="crafting">
<button class="nav-btn" data-tab="crafting" onclick="switchToTab('crafting')">
<i class="fas fa-hammer"></i>
<span>Crafting</span>
</button>
<button class="nav-btn" data-tab="shop">
<button class="nav-btn" data-tab="shop" onclick="switchToTab('shop')">
<i class="fas fa-store"></i>
<span>Shop</span>
</button>
@ -320,7 +324,35 @@
<p>Resources Gained: <span id="offlineResources">0</span></p>
<button class="btn btn-primary" id="claimOfflineBtn">Claim Rewards</button>
</div>
<div class="stats-grid">
</div>
<div class="card">
<h3>Player Stats</h3>
<div class="player-stats-grid">
<div class="stat">
<span class="stat-label">Level</span>
<span class="stat-value" id="playerLevelDisplay">1</span>
</div>
<div class="stat">
<span class="stat-label">Experience</span>
<span class="stat-value" id="playerXP">0 / 100</span>
</div>
<div class="stat">
<span class="stat-label">Skill Points</span>
<span class="stat-value" id="skillPoints">0</span>
</div>
<div class="stat">
<span class="stat-label">Total XP Earned</span>
<span class="stat-value" id="totalXP">0</span>
</div>
<div class="stat">
<span class="stat-label">Quests Completed</span>
<span class="stat-value" id="questsCompleted">0</span>
</div>
<div class="stat">
<span class="stat-label">Last Login</span>
<span class="stat-value" id="lastLogin">Never</span>
</div>
<div class="stat">
<span class="stat-label">Total Kills</span>
<span class="stat-value" id="totalKills">0</span>
@ -331,7 +363,7 @@
</div>
<div class="stat">
<span class="stat-label">Play Time</span>
<span class="stat-value" id="playTime">0h 0m</span>
<span class="stat-value" id="playTime">0m 0s</span>
</div>
</div>
</div>
@ -366,9 +398,9 @@
</div>
</div>
<div class="skill-categories">
<button class="skill-cat-btn active" data-category="combat">Combat</button>
<button class="skill-cat-btn" data-category="science">Science</button>
<button class="skill-cat-btn" data-category="crafting">Crafting</button>
<button class="skill-cat-btn active" data-category="combat" onclick="switchSkillCategory('combat')">Combat</button>
<button class="skill-cat-btn" data-category="science" onclick="switchSkillCategory('science')">Science</button>
<button class="skill-cat-btn" data-category="crafting" onclick="switchSkillCategory('crafting')">Crafting</button>
</div>
<div class="skills-grid" id="skillsGrid">
<!-- Skills will be generated here -->
@ -379,10 +411,10 @@
<!-- Base Tab -->
<div class="tab-content" id="base-tab">
<div class="base-navigation">
<button class="base-nav-btn active" data-view="overview">Base Overview</button>
<button class="base-nav-btn" data-view="visualization">Base Visualization</button>
<button class="base-nav-btn" data-view="ships">Ship Gallery</button>
<button class="base-nav-btn" data-view="starbases">Starbases</button>
<button class="base-nav-btn active" data-view="overview" onclick="switchBaseView('overview')">Base Overview</button>
<button class="base-nav-btn" data-view="visualization" onclick="switchBaseView('visualization')">Base Visualization</button>
<button class="base-nav-btn" data-view="ships" onclick="switchBaseView('ships')">Ship Gallery</button>
<button class="base-nav-btn" data-view="starbases" onclick="switchBaseView('starbases')">Starbases</button>
</div>
<!-- Base Overview -->
@ -515,11 +547,11 @@
<div class="tab-content" id="quests-tab">
<div class="quests-container">
<div class="quest-tabs">
<button class="quest-tab-btn active" data-type="main">Main Story</button>
<button class="quest-tab-btn" data-type="daily">Daily</button>
<button class="quest-tab-btn" data-type="weekly">Weekly</button>
<button class="quest-tab-btn" data-type="completed">Completed</button>
<button class="quest-tab-btn" data-type="failed">Failed Quests</button>
<button class="quest-tab-btn active" data-type="main" onclick="switchQuestCategory('main')">Main Story</button>
<button class="quest-tab-btn" data-type="daily" onclick="switchQuestCategory('daily')">Daily</button>
<button class="quest-tab-btn" data-type="weekly" onclick="switchQuestCategory('weekly')">Weekly</button>
<button class="quest-tab-btn" data-type="completed" onclick="switchQuestCategory('completed')">Completed</button>
<button class="quest-tab-btn" data-type="failed" onclick="switchQuestCategory('failed')">Failed Quests</button>
</div>
<div class="daily-countdown" id="dailyCountdown">Daily quests reset in: 00:00:00</div>
<div class="weekly-countdown" id="weeklyCountdown">Weekly quests reset in: 0d 00:00</div>
@ -600,10 +632,10 @@
</div>
</div>
<div class="crafting-categories">
<button class="crafting-cat-btn active" data-category="weapons">Weapons</button>
<button class="crafting-cat-btn" data-category="armor">Armor</button>
<button class="crafting-cat-btn" data-category="items">Items</button>
<button class="crafting-cat-btn" data-category="ships">Ships</button>
<button class="crafting-cat-btn active" data-category="weapons" onclick="switchCraftingCategory('weapons')">Weapons</button>
<button class="crafting-cat-btn" data-category="armor" onclick="switchCraftingCategory('armor')">Armor</button>
<button class="crafting-cat-btn" data-category="items" onclick="switchCraftingCategory('items')">Items</button>
<button class="crafting-cat-btn" data-category="ships" onclick="switchCraftingCategory('ships')">Ships</button>
</div>
<div class="crafting-grid" id="recipeList">
<!-- Recipes will be generated here -->
@ -616,13 +648,13 @@
<div class="shop-container">
<div class="shop-header">
<div class="shop-categories">
<button class="shop-cat-btn active" data-category="ships">Ships</button>
<button class="shop-cat-btn" data-category="weapons">Weapons</button>
<button class="shop-cat-btn" data-category="armors">Armors</button>
<button class="shop-cat-btn active" data-category="ships" onclick="switchShopCategory('ships')">Ships</button>
<button class="shop-cat-btn" data-category="weapons" onclick="switchShopCategory('weapons')">Weapons</button>
<button class="shop-cat-btn" data-category="armors" onclick="switchShopCategory('armors')">Armors</button>
<!-- <button class="shop-cat-btn" data-category="upgrades">Upgrades</button> -->
<button class="shop-cat-btn" data-category="cosmetics">Cosmetics</button>
<button class="shop-cat-btn" data-category="consumables">Consumables</button>
<button class="shop-cat-btn" data-category="materials">Materials</button>
<button class="shop-cat-btn" data-category="cosmetics" onclick="switchShopCategory('cosmetics')">Cosmetics</button>
<button class="shop-cat-btn" data-category="consumables" onclick="switchShopCategory('consumables')">Consumables</button>
<button class="shop-cat-btn" data-category="materials" onclick="switchShopCategory('materials')">Materials</button>
</div>
</div>
<div class="shop-content">
@ -672,13 +704,559 @@
<script src="js/systems/QuestSystem.js"></script>
<script src="js/systems/ShipSystem.js"></script>
<script src="js/systems/IdleSystem.js"></script>
<script src="js/systems/ItemSystem.js"></script>
<script src="js/systems/CraftingSystem.js"></script>
<script src="js/data/GameData.js"></script>
<script src="js/ui/UIManager.js"></script>
<script src="js/SmartSaveManager.js"></script>
<script src="js/SaveSystemIntegration.js"></script>
<script src="https://cdn.socket.io/4.7.4/socket.io.min.js"></script>
<script src="js/GameInitializer.js"></script>
<script src="js/ui/LiveMainMenu.js"></script>
<script src="js/main.js"></script>
<!-- Global Navigation Function -->
<script>
function switchToTab(tabName) {
console.log('[GLOBAL] switchToTab called with:', tabName);
// Try to use UIManager first
if (window.game && window.game.systems && window.game.systems.ui) {
console.log('[GLOBAL] Using UIManager to switch tab');
window.game.systems.ui.switchTab(tabName);
// Force update the specific tab content
console.log('[GLOBAL] Forcing update for tab:', tabName);
switch(tabName) {
case 'shop':
if (window.game.systems.economy) {
console.log('[GLOBAL] Forcing shop UI update');
window.game.systems.economy.updateShopUI();
}
break;
case 'quests':
console.log('[GLOBAL] Quest system check:', {
hasGame: !!window.game,
hasSystems: !!(window.game?.systems),
hasQuestSystem: !!(window.game?.systems?.questSystem),
questSystemType: typeof window.game?.systems?.questSystem
});
// REMOVED: QuestSystem should be server-driven only
console.log('[GLOBAL] Quests are server-driven - displaying server quest data');
// Display server quest data
const questListElement = document.getElementById('questList');
if (questListElement) {
// Get quest data from server playerData
const serverPlayerData = window.gameInitializer?.serverPlayerData;
if (serverPlayerData && serverPlayerData.quests) {
const quests = serverPlayerData.quests;
console.log('[GLOBAL] Displaying server quest data:', quests);
// Categorize quests on client since server sends old format
const activeQuests = quests.active || [];
const mainQuests = activeQuests.filter(quest => quest.type === 'main');
const dailyQuests = activeQuests.filter(quest => quest.type === 'daily');
const weeklyQuests = activeQuests.filter(quest => quest.type === 'weekly');
const tutorialQuests = activeQuests.filter(quest => quest.type === 'tutorial');
console.log('[GLOBAL] Client-side categorization:', {
mainQuests: mainQuests.length,
dailyQuests: dailyQuests.length,
weeklyQuests: weeklyQuests.length,
tutorialQuests: tutorialQuests.length
});
// Get the currently selected quest tab type
const activeQuestTab = document.querySelector('.quest-tab-btn.active')?.dataset.type || 'main';
console.log('[GLOBAL] Active quest tab:', activeQuestTab);
console.log('[GLOBAL] All quest tab buttons:', document.querySelectorAll('.quest-tab-btn'));
console.log('[GLOBAL] Active button found:', document.querySelector('.quest-tab-btn.active'));
// Force check for debugging
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
console.log('[GLOBAL] Quest tab button:', btn.dataset.type, 'active:', btn.classList.contains('active'));
});
// Create quest HTML
let questHTML = '<div class="quest-list-container">';
// Show quests based on selected tab
if (activeQuestTab === 'main' && mainQuests.length > 0) {
questHTML += '<h3>Main Story Quests</h3>';
mainQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'daily' && dailyQuests.length > 0) {
questHTML += '<h3>Daily Quests</h3>';
dailyQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item daily">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'weekly' && weeklyQuests.length > 0) {
questHTML += '<h3>Weekly Quests</h3>';
weeklyQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item weekly">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'completed') {
questHTML += '<h3>Completed Quests</h3>';
questHTML += '<p>No completed quests yet.</p>';
}
if (activeQuestTab === 'failed') {
questHTML += '<h3>Failed Quests</h3>';
questHTML += '<p>No failed quests yet.</p>';
}
// Show no quests message if category is empty
if ((activeQuestTab === 'main' && mainQuests.length === 0) ||
(activeQuestTab === 'daily' && dailyQuests.length === 0) ||
(activeQuestTab === 'weekly' && weeklyQuests.length === 0)) {
questHTML += '<p>No quests available in this category.</p>';
}
questHTML += '</div>';
questListElement.innerHTML = questHTML;
} else {
questListElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>No Quest Data Available</h3><p>Server quest data not found.</p></div>';
}
}
break;
case 'skills':
if (window.game.systems.skillSystem) {
console.log('[GLOBAL] Forcing skills UI update');
window.game.systems.skillSystem.updateUI();
}
break;
case 'crafting':
if (window.game.systems.crafting) {
console.log('[GLOBAL] Forcing crafting UI update');
window.game.systems.crafting.updateUI();
}
break;
}
return;
}
// Fallback: Manual tab switching
console.log('[GLOBAL] Using manual tab switching fallback');
// Hide all tabs
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
// Remove active class from all nav buttons
document.querySelectorAll('.nav-btn').forEach(btn => {
btn.classList.remove('active');
});
// Show selected tab
const targetTab = document.getElementById(tabName + '-tab');
if (targetTab) {
targetTab.classList.add('active');
}
// Add active class to clicked button
const targetButton = document.querySelector(`[data-tab="${tabName}"]`);
if (targetButton) {
targetButton.classList.add('active');
}
}
function switchShopCategory(category) {
console.log('[GLOBAL] switchShopCategory called with:', category);
console.log('[GLOBAL] switchShopCategory function starting');
try {
// Try to use UIManager first
if (window.game && window.game.systems && window.game.systems.ui) {
console.log('[GLOBAL] Using UIManager path for shop');
window.game.systems.ui.switchShopCategory(category);
console.log('[GLOBAL] switchShopCategory function completed (UIManager path)');
return;
}
// Fallback: Manual category switching
console.log('[GLOBAL] Using manual shop category switching');
document.querySelectorAll('.shop-cat-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-category="${category}"]`);
if (targetButton) {
targetButton.classList.add('active');
console.log('[GLOBAL] Set active shop button:', category);
}
// Force shop display update immediately
console.log('[GLOBAL] About to call updateShopDisplay');
updateShopDisplay();
console.log('[GLOBAL] Called updateShopDisplay');
console.log('[GLOBAL] switchShopCategory function completed (manual path)');
} catch (error) {
console.error('[GLOBAL] Error in switchShopCategory:', error);
}
}
function updateShopDisplay() {
try {
console.log('[GLOBAL] updateShopDisplay called');
console.log('[GLOBAL] window.game:', !!window.game);
console.log('[GLOBAL] game.systems.economy:', !!(window.game?.systems?.economy));
console.log('[GLOBAL] game.systems.itemSystem:', !!(window.game?.systems?.itemSystem));
if (window.game && window.game.systems && window.game.systems.economy) {
console.log('[GLOBAL] Calling economy.updateShopUI');
window.game.systems.economy.updateShopUI();
console.log('[GLOBAL] updateShopDisplay completed');
} else {
console.log('[GLOBAL] Economy system not available');
const shopItemsElement = document.getElementById('shopItems');
if (shopItemsElement) {
shopItemsElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>Shop Not Available</h3><p>Economy system not found.</p></div>';
}
}
} catch (error) {
console.error('[GLOBAL] Error in updateShopDisplay:', error);
}
}
function switchSkillCategory(category) {
console.log('[GLOBAL] switchSkillCategory called with:', category);
// Try to use UIManager first
if (window.game && window.game.systems && window.game.systems.ui) {
window.game.systems.ui.switchSkillCategory(category);
return;
}
// Fallback: Manual category switching
document.querySelectorAll('.skill-cat-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-category="${category}"]`);
if (targetButton) {
targetButton.classList.add('active');
}
}
function switchQuestCategory(category) {
console.log('[GLOBAL] switchQuestCategory called with:', category);
console.log('[GLOBAL] switchQuestCategory function starting');
try {
// Try to use UIManager first
if (window.game && window.game.systems && window.game.systems.ui) {
console.log('[GLOBAL] Using UIManager path');
// Try to call updateQuestTabs if it exists, otherwise use fallback
if (typeof window.game.systems.ui.updateQuestTabs === 'function') {
console.log('[GLOBAL] Calling UIManager updateQuestTabs');
window.game.systems.ui.updateQuestTabs(category);
} else {
console.log('[GLOBAL] updateQuestTabs not found, using fallback');
// Fallback: Manual category switching
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-type="${category}"]`);
if (targetButton) {
targetButton.classList.add('active');
}
// Force quest display update immediately
console.log('[GLOBAL] About to call updateQuestDisplay');
updateQuestDisplay();
console.log('[GLOBAL] Called updateQuestDisplay');
}
console.log('[GLOBAL] switchQuestCategory function completed (UIManager path)');
return;
}
// Fallback: Manual category switching
console.log('[GLOBAL] Using manual quest category switching');
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-type="${category}"]`);
if (targetButton) {
targetButton.classList.add('active');
console.log('[GLOBAL] Set active button:', category);
}
// Force quest display update immediately
console.log('[GLOBAL] About to call updateQuestDisplay');
updateQuestDisplay();
console.log('[GLOBAL] Called updateQuestDisplay');
console.log('[GLOBAL] switchQuestCategory function completed (manual path)');
} catch (error) {
console.error('[GLOBAL] Error in switchQuestCategory:', error);
}
}
function updateQuestDisplay() {
try {
console.log('[GLOBAL] updateQuestDisplay called');
console.log('[GLOBAL] window.gameInitializer:', !!window.gameInitializer);
console.log('[GLOBAL] serverPlayerData:', window.gameInitializer?.serverPlayerData);
// Get quest data from server playerData
const serverPlayerData = window.gameInitializer?.serverPlayerData;
if (serverPlayerData && serverPlayerData.quests) {
const quests = serverPlayerData.quests;
console.log('[GLOBAL] Updating quest display with data:', quests);
// Categorize quests on client since server sends old format
const activeQuests = quests.active || [];
const mainQuests = activeQuests.filter(quest => quest.type === 'main');
const dailyQuests = activeQuests.filter(quest => quest.type === 'daily');
const weeklyQuests = activeQuests.filter(quest => quest.type === 'weekly');
const tutorialQuests = activeQuests.filter(quest => quest.type === 'tutorial');
console.log('[GLOBAL] Quest categorization:', {
total: activeQuests.length,
main: mainQuests.length,
daily: dailyQuests.length,
weekly: weeklyQuests.length,
tutorial: tutorialQuests.length
});
// Get the currently selected quest tab type
const activeQuestTab = document.querySelector('.quest-tab-btn.active')?.dataset.type || 'main';
console.log('[GLOBAL] Active quest tab for update:', activeQuestTab);
const questListElement = document.getElementById('questList');
if (questListElement) {
// Create quest HTML
let questHTML = '<div class="quest-list-container">';
// Show quests based on selected tab
if (activeQuestTab === 'daily' && dailyQuests.length > 0) {
console.log('[GLOBAL] Showing daily quests:', dailyQuests.length);
questHTML += '<h3>Daily Quests</h3>';
dailyQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item daily">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'weekly' && weeklyQuests.length > 0) {
console.log('[GLOBAL] Showing weekly quests:', weeklyQuests.length);
questHTML += '<h3>Weekly Quests</h3>';
weeklyQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item weekly">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits, ' + (quest.rewards?.gems || 0) + ' gems</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'main' && mainQuests.length > 0) {
console.log('[GLOBAL] Showing main quests:', mainQuests.length);
questHTML += '<h3>Main Story Quests</h3>';
mainQuests.forEach(quest => {
const progress = quest.progress || 0;
const requirement = quest.requirements?.battlesWon || 1;
const progressPercent = (progress / requirement) * 100;
questHTML += '<div class="quest-item">';
questHTML += '<div class="quest-header">';
questHTML += '<h4>' + quest.name + '</h4>';
questHTML += '<span class="quest-status ' + (quest.status || 'active') + '">' + (quest.status || 'active') + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-description">' + quest.description + '</div>';
questHTML += '<div class="quest-progress">';
questHTML += '<div class="progress-bar">';
questHTML += '<div class="progress-fill" style="width: ' + progressPercent + '%"></div>';
questHTML += '</div>';
questHTML += '<span>' + progress + '/' + requirement + '</span>';
questHTML += '</div>';
questHTML += '<div class="quest-rewards">';
questHTML += '<span>Rewards: ' + (quest.rewards?.experience || 0) + ' XP, ' + (quest.rewards?.credits || 0) + ' credits</span>';
questHTML += '</div>';
questHTML += '</div>';
});
}
if (activeQuestTab === 'completed') {
questHTML += '<h3>Completed Quests</h3>';
questHTML += '<p>No completed quests yet.</p>';
}
if (activeQuestTab === 'failed') {
questHTML += '<h3>Failed Quests</h3>';
questHTML += '<p>No failed quests yet.</p>';
}
// Show no quests message if category is empty
if ((activeQuestTab === 'main' && mainQuests.length === 0) ||
(activeQuestTab === 'daily' && dailyQuests.length === 0) ||
(activeQuestTab === 'weekly' && weeklyQuests.length === 0)) {
questHTML += '<p>No quests available in this category.</p>';
}
questHTML += '</div>';
questListElement.innerHTML = questHTML;
console.log('[GLOBAL] Quest display updated for tab:', activeQuestTab);
}
} else {
console.log('[GLOBAL] No quest data available');
const questListElement = document.getElementById('questList');
if (questListElement) {
questListElement.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-secondary);"><h3>No Quest Data Available</h3><p>Server quest data not found.</p></div>';
}
}
} catch (error) {
console.error('[GLOBAL] Error in updateQuestDisplay:', error);
}
}
function switchCraftingCategory(category) {
console.log('[GLOBAL] switchCraftingCategory called with:', category);
// Try to use UIManager first
if (window.game && window.game.systems && window.game.systems.ui) {
window.game.systems.ui.switchCraftingCategory(category);
return;
}
// Fallback: Manual category switching
document.querySelectorAll('.crafting-cat-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-category="${category}"]`);
if (targetButton) {
targetButton.classList.add('active');
}
}
function switchBaseView(view) {
console.log('[GLOBAL] switchBaseView called with:', view);
// Try to use BaseSystem first
if (window.game && window.game.systems && window.game.systems.base) {
window.game.systems.base.switchBaseView(view);
return;
}
// Fallback: Manual view switching
document.querySelectorAll('.base-nav-btn').forEach(btn => {
btn.classList.remove('active');
});
const targetButton = document.querySelector(`[data-view="${view}"]`);
if (targetButton) {
targetButton.classList.add('active');
}
// Hide all base view contents
document.querySelectorAll('.base-view-content').forEach(content => {
content.style.display = 'none';
});
// Show selected view content
const targetContent = document.getElementById(`base-${view}`);
if (targetContent) {
targetContent.style.display = 'block';
}
}
</script>
<!-- Hidden Console Window -->
<div id="consoleWindow" class="console-window">
<div class="console-header">

View File

@ -15,12 +15,16 @@ class GameInitializer {
this.socket = null;
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server
this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server for Socket.IO (local dev server)
console.log('[GAME INITIALIZER] Constructor - gameServerUrl set to:', this.gameServerUrl);
}
updateServerUrls(apiUrl, gameUrl) {
console.log('[GAME INITIALIZER] Updating server URLs:', { apiUrl, gameUrl });
console.log('[GAME INITIALIZER] Updating server URLs:', { apiUrl: apiUrl, gameUrl: gameUrl });
console.log('[GAME INITIALIZER] Previous gameServerUrl:', this.gameServerUrl);
this.apiBaseUrl = apiUrl;
this.gameServerUrl = gameUrl;
console.log('[GAME INITIALIZER] New gameServerUrl:', this.gameServerUrl);
}
initializeMultiplayer(server, serverData, authToken, currentUser) {
@ -33,8 +37,10 @@ class GameInitializer {
// Initialize Socket.IO connection
this.initializeSocketConnection();
// Initialize game systems with multiplayer support
this.initializeGameSystems();
// Set SmartSaveManager to multiplayer mode
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(true, this);
}
// Update UI for multiplayer mode
this.updateUIForMultiplayerMode();
@ -49,6 +55,7 @@ class GameInitializer {
}
console.log('[GAME INITIALIZER] Initializing Socket.IO connection');
console.log('[GAME INITIALIZER] Using gameServerUrl:', this.gameServerUrl);
// Check if we're in local mode and should use mock socket
if (this.gameServerUrl.includes('localhost') && window.localServerManager && window.localServerManager.localServer) {
@ -63,14 +70,21 @@ class GameInitializer {
return;
}
// Connect to the game server (different from API server)
this.socket = io(this.gameServerUrl, {
// FORCE THE URL - Override any undefined issues
const FORCED_URL = 'https://dev.gameserver.galaxystrike.online';
console.log('[GAME INITIALIZER] FORCING URL to:', FORCED_URL);
console.log('[GAME INITIALIZER] Original this.gameServerUrl:', this.gameServerUrl);
// Connect to the game server with FORCED URL
this.socket = io(FORCED_URL, {
auth: {
token: this.authToken,
serverId: this.serverData.id
}
});
console.log('[GAME INITIALIZER] Socket.IO connection initiated to FORCED URL:', FORCED_URL);
// Socket event handlers
this.socket.on('connect', () => {
console.log('[GAME INITIALIZER] Connected to server');
@ -111,9 +125,69 @@ class GameInitializer {
console.log('[GAME INITIALIZER] Chat message:', data);
this.onChatMessage(data);
});
// Server data events
this.socket.on('authenticated', (data) => {
console.log('[GAME INITIALIZER] Authentication response:', data);
this.onAuthenticated(data);
});
this.socket.on('gameDataLoaded', (data) => {
console.log('[GAME INITIALIZER] Game data loaded:', data);
this.onGameDataLoaded(data);
});
this.socket.on('updatePlayerStats', (data) => {
console.log('[GAME INITIALIZER] Player stats updated on server:', data);
this.onGameDataSaved(data);
});
this.socket.on('gameDataSaved', (data) => {
console.log('[GAME INITIALIZER] Game data saved:', data);
this.onGameDataSaved(data);
});
// Idle rewards events
this.socket.on('offlineRewardsClaimed', (data) => {
console.log('[GAME INITIALIZER] Offline rewards claimed:', data);
this.onOfflineRewardsClaimed(data);
});
this.socket.on('onlineIdleRewards', (data) => {
console.log('[GAME INITIALIZER] Online idle rewards received:', data);
this.onOnlineIdleRewards(data);
});
// PlayTime events
this.socket.on('playTimeUpdated', (data) => {
console.log('[GAME INITIALIZER] PlayTime updated from server:', data);
this.onPlayTimeUpdated(data);
});
// Shop purchase events
this.socket.on('purchaseCompleted', (data) => {
console.log('[GAME INITIALIZER] Purchase completed:', data);
this.onPurchaseCompleted(data);
});
// Item system events
this.socket.on('shopItemsReceived', (data) => {
console.log('[GAME INITIALIZER] Shop items received:', data);
this.onShopItemsReceived(data);
});
this.socket.on('itemDetailsReceived', (data) => {
console.log('[GAME INITIALIZER] Item details received:', data);
this.onItemDetailsReceived(data);
});
}
onSocketConnected() {
// Expose socket globally for systems that need it
if (window.game) {
window.game.socket = this.socket;
}
// Join the server room
this.socket.emit('joinServer', {
serverId: this.serverData.id,
@ -121,13 +195,48 @@ class GameInitializer {
username: this.currentUser.username
});
// Authenticate with server to get player data
this.authenticateWithServer();
// Show connected status
this.showConnectionStatus('Connected', 'success');
}
onSocketDisconnected() {
console.log('[GAME INITIALIZER] Socket disconnected - switching to singleplayer mode');
// Show disconnected status
this.showConnectionStatus('Disconnected', 'error');
// Switch SmartSaveManager back to singleplayer mode
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(false);
console.log('[GAME INITIALIZER] SmartSaveManager set to singleplayer mode');
}
// Clear socket reference
this.socket = null;
console.log('[GAME INITIALIZER] Socket reference cleared');
}
// Force disconnect from multiplayer server
forceDisconnect() {
console.log('[GAME INITIALIZER] Force disconnect called');
if (this.socket) {
console.log('[GAME INITIALIZER] Disconnecting socket...');
this.socket.disconnect();
this.socket = null;
}
// Switch to singleplayer mode
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(false);
console.log('[GAME INITIALIZER] Force switched to singleplayer mode');
}
this.showConnectionStatus('Disconnected', 'error');
console.log('[GAME INITIALIZER] Force disconnect completed');
}
onPlayerJoined(data) {
@ -156,6 +265,147 @@ class GameInitializer {
}
}
onAuthenticated(data) {
console.log('[GAME INITIALIZER] Authentication successful:', data);
if (data.success && data.playerData) {
// Store server player data from authentication (this is our primary source)
this.serverPlayerData = data.playerData;
this.currentUser = data.user;
// CRITICAL: Force multiplayer mode and prevent fallback
if (window.smartSaveManager) {
console.log('[GAME INITIALIZER] FORCING multiplayer mode after authentication');
window.smartSaveManager.setMultiplayerMode(true, this);
}
// ItemSystem is now initialized by GameEngine - no need to initialize here
console.log('[GAME INITIALIZER] ItemSystem initialization handled by GameEngine');
console.log('[GAME INITIALIZER] Using authentication data as primary source:', this.serverPlayerData);
// NOW create GameEngine AFTER authentication is successful
if (!window.game) {
console.log('[GAME INITIALIZER] Creating GameEngine after successful authentication');
this.createGameEngineForMultiplayer();
}
// Set SmartSaveManager to multiplayer mode
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(true, this);
console.log('[GAME INITIALIZER] SmartSaveManager set to multiplayer mode');
// Apply authentication data immediately (this will be stored for later)
window.smartSaveManager.applyServerDataToGame(data.playerData);
}
// NOTE: Don't apply to GameEngine here - it doesn't exist yet!
// The data will be applied in createGameEngineForMultiplayer() after the game is created.
this.showNotification(`Welcome back! Level ${data.playerData.stats?.level || 1}`, 'success');
} else {
this.showNotification(data.error || 'Authentication failed', 'error');
}
}
createGameEngineForMultiplayer() {
console.log('[GAME INITIALIZER] Creating GameEngine for multiplayer mode');
console.log('[GAME INITIALIZER] Server player data available:', !!this.serverPlayerData);
try {
// Create GameEngine instance
window.game = new GameEngine();
// CRITICAL: Set multiplayer mode BEFORE initializing systems
console.log('[GAME INITIALIZER] Setting multiplayer mode BEFORE initialization');
window.game.setMultiplayerMode(true, this.socket, this.serverData, this.currentUser);
// NOTE: Don't apply server data immediately - wait for full initialization
console.log('[GAME INITIALIZER] Server data ready, will apply after GameEngine initialization');
console.log('[GAME INITIALIZER] - this.serverPlayerData:', !!this.serverPlayerData);
console.log('[GAME INITIALIZER] - window.game:', !!window.game);
console.log('[GAME INITIALIZER] - window.game.loadServerPlayerData:', !!window.game?.loadServerPlayerData);
// Initialize the game engine
console.log('[GAME INITIALIZER] About to call window.game.init()');
const initPromise = window.game.init();
console.log('[GAME INITIALIZER] GameEngine.init() returned:', typeof initPromise, initPromise);
// Apply server data and refresh UI after initialization is complete
initPromise.then(() => {
console.log('[GAME INITIALIZER] GameEngine initialized successfully for multiplayer');
// Apply server data immediately after initialization
if (this.serverPlayerData && window.game.loadServerPlayerData) {
console.log('[GAME INITIALIZER] Applying server player data to GameEngine:', this.serverPlayerData);
window.game.loadServerPlayerData(this.serverPlayerData);
console.log('[GAME INITIALIZER] Server player data applied to GameEngine');
// Force UI refresh
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
console.log('[GAME INITIALIZER] Forcing UI refresh after data application');
window.game.systems.ui.forceRefreshAllUI();
} else {
console.warn('[GAME INITIALIZER] UI refresh not available - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
}
} else {
console.warn('[GAME INITIALIZER] No server player data or loadServerPlayerData method available');
console.log('[GAME INITIALIZER] - this.serverPlayerData:', !!this.serverPlayerData);
console.log('[GAME INITIALIZER] - window.game.loadServerPlayerData:', !!window.game?.loadServerPlayerData);
}
// Start the game
if (window.game.start) {
window.game.start();
}
}).catch((error) => {
console.error('[GAME INITIALIZER] GameEngine init failed:', error);
console.error('[GAME INITIALIZER] Error details:', error.stack);
this.showNotification('Failed to initialize game engine', 'error');
});
} catch (error) {
console.error('[GAME INITIALIZER] Error creating GameEngine:', error);
this.showNotification('Error creating game engine', 'error');
}
}
onGameDataLoaded(data) {
console.log('[GAME INITIALIZER] Server game data loaded:', data);
console.log('[GAME INITIALIZER] Data success:', data.success);
console.log('[GAME INITIALIZER] Data content:', data.data);
console.log('[GAME INITIALIZER] Data keys:', data.data ? Object.keys(data.data) : 'No data object');
// Only process if we don't already have good data from authentication
if (data.success && data.data && Object.keys(data.data).length > 0 && !this.serverPlayerData) {
console.log('[GAME INITIALIZER] Using gameDataLoaded as primary source (no auth data available)');
this.serverPlayerData = data.data;
// Apply server data to game if game is running
if (window.game && window.game.loadServerPlayerData) {
window.game.loadServerPlayerData(data.data);
// Force UI refresh when server data is applied
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
window.game.systems.ui.forceRefreshAllUI();
}
}
} else {
console.log('[GAME INITIALIZER] Ignoring gameDataLoaded - already have data from authentication or data is empty');
}
}
onGameDataSaved(data) {
console.log('[GAME INITIALIZER] Server game data saved:', data);
if (data.success) {
this.showNotification('Game saved to server!', 'success');
} else {
this.showNotification(data.error || 'Failed to save to server', 'error');
}
}
onForceDisconnect(data) {
// Handle forced disconnection from server
console.warn('[GAME INITIALIZER] Force disconnected by server:', data);
@ -211,7 +461,56 @@ class GameInitializer {
// Configure game for multiplayer mode
console.log('[GAME INITIALIZER] Configuring for multiplayer mode');
window.game.setMultiplayerMode(true, this.socket, this.serverData, this.currentUser);
// Note: setMultiplayerMode already called in createGameEngineForMultiplayer() before initialization
window.game.gameInitializer = this; // Store reference for server polling
// DISABLE game logic in multiplayer - server is authoritative
if (window.game) {
console.log('[GAME INITIALIZER] Disabling client game logic - server is authoritative');
// Override game logic methods to do nothing in multiplayer
const originalUpdateGameLogic = window.game.updateGameLogic;
window.game.updateGameLogic = function() {
// In multiplayer mode, client does NO game logic
// Server is authoritative for ALL game data including credits
// Client is display-only
};
const originalStart = window.game.start;
window.game.start = function() {
console.log('[GAME ENGINE] Multiplayer mode - client does not run game logic, server is authoritative');
console.log('[GAME ENGINE] GameInitializer reference:', !!this.gameInitializer);
console.log('[GAME ENGINE] Socket reference:', !!(this.gameInitializer && this.gameInitializer.socket));
console.log('[GAME ENGINE] Game mode:', this.gameInitializer ? this.gameInitializer.gameMode : 'no gameInitializer');
this.isRunning = true;
// NO game logic timer - client is display-only
// Server handles all game logic including credit generation
// Start server data polling for UI updates
if (this.gameInitializer && this.gameInitializer.socket) {
console.log('[GAME ENGINE] Starting server data polling for UI updates');
this.serverPollTimer = setInterval(() => {
console.log('[GAME ENGINE] Polling server for data...');
this.gameInitializer.loadGameDataFromServer();
}, 5000); // Request updates every 5 seconds
} else {
console.warn('[GAME ENGINE] Cannot start server polling - no gameInitializer or socket');
}
// Only start UI updates that use server data (every second)
if (this.systems.ui) {
console.log('[GAME ENGINE] Starting multiplayer UI updates');
this.uiUpdateTimer = setInterval(() => {
if (this.systems && this.systems.ui && this.systems.ui.updateUI) {
console.log('[GAME ENGINE] Updating multiplayer UI with server data');
this.systems.ui.updateUI();
}
}, 1000);
}
};
}
// Game is already set up with save data, just start the game loop
if (window.game.start) {
@ -230,8 +529,24 @@ class GameInitializer {
updateUIForMultiplayerMode() {
// Update UI elements to show multiplayer mode
const playerName = document.getElementById('playerName');
if (playerName && this.currentUser) {
playerName.textContent = this.currentUser.username;
const playerTitle = document.getElementById('playerTitle');
const playerUsername = document.getElementById('playerUsername');
if (this.currentUser) {
// Set the player name (rank/title)
if (playerName) {
playerName.textContent = 'Commander';
}
// Set the player title
if (playerTitle) {
playerTitle.textContent = '- Rookie Pilot';
}
// Set the username next to the level
if (playerUsername) {
playerUsername.textContent = this.currentUser.username + ' ';
}
}
// Show multiplayer-specific UI elements
@ -340,10 +655,211 @@ class GameInitializer {
}
}
// Method to save game data to server (SECURE: only send specific updates)
saveGameDataToServer(gameData) {
if (this.socket && this.gameMode === 'multiplayer') {
console.log('[GAME INITIALIZER] Sending secure game updates to server');
// Only send specific, validated updates - not entire game state
const secureUpdates = {
playerStats: {
credits: gameData.player?.credits || 0,
level: gameData.player?.level || 1,
experience: gameData.player?.experience || 0,
playTime: gameData.player?.playTime || 0
},
timestamp: Date.now()
};
// Send only the specific updates for server validation
this.socket.emit('updatePlayerStats', secureUpdates);
}
}
// Method to load game data from server
loadGameDataFromServer() {
if (this.socket && this.gameMode === 'multiplayer') {
console.log('[GAME INITIALIZER] Loading game data from server');
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
console.log('[GAME INITIALIZER] Current user:', this.currentUser);
console.log('[GAME INITIALIZER] Emitting loadGameData event with username');
// Get username from current user or fallback to stored user
let username = 'anonymous'; // default fallback
if (this.currentUser?.username) {
username = this.currentUser.username;
} else {
// Try to get from localStorage as fallback
const storedUser = localStorage.getItem('currentUser');
if (storedUser) {
try {
const user = JSON.parse(storedUser);
username = user.username || 'anonymous';
} catch (e) {
console.warn('[GAME INITIALIZER] Failed to parse stored user, using default');
}
}
}
console.log('[GAME INITIALIZER] Using username for data load:', username);
// Send the username to load the correct player data
this.socket.emit('loadGameData', {
username: username
});
} else {
console.log('[GAME INITIALIZER] Cannot load game data - socket or multiplayer mode not available');
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
}
}
// Method to authenticate with server
authenticateWithServer() {
console.log('[GAME INITIALIZER] authenticateWithServer called');
console.log('[GAME INITIALIZER] Socket available:', !!this.socket);
console.log('[GAME INITIALIZER] Game mode:', this.gameMode);
console.log('[GAME INITIALIZER] Current user:', this.currentUser);
if (this.socket && this.currentUser) {
console.log('[GAME INITIALIZER] Sending authentication to server');
this.socket.emit('authenticate', {
userId: this.currentUser.userId,
username: this.currentUser.username
});
} else {
console.warn('[GAME INITIALIZER] Cannot authenticate - missing socket or user data');
if (!this.socket) {
console.warn('[GAME INITIALIZER] Socket is null/undefined');
}
if (!this.currentUser) {
console.warn('[GAME INITIALIZER] Current user is null/undefined');
}
}
}
onOfflineRewardsClaimed(data) {
if (data.success) {
if (data.rewards.credits > 0 || data.rewards.experience > 0) {
// Apply rewards to player
if (window.game && window.game.systems) {
if (data.rewards.credits > 0) {
window.game.systems.economy.addCredits(data.rewards.credits, 'offline');
}
if (data.rewards.experience > 0) {
window.game.systems.player.addExperience(data.rewards.experience);
}
// Show success message
let message = 'Offline rewards claimed!\n';
if (data.rewards.credits > 0) message += `+${data.rewards.credits} credits\n`;
if (data.rewards.experience > 0) message += `+${data.rewards.experience} experience\n`;
window.game.showNotification(message, 'success', 5000);
}
} else {
window.game.showNotification('No offline rewards available', 'info', 3000);
}
} else {
window.game.showNotification(`Failed to claim offline rewards: ${data.error}`, 'error', 5000);
}
}
onOnlineIdleRewards(data) {
if (window.game && window.game.systems) {
// Update player balance with online idle rewards
if (data.credits > 0) {
// The server already updated the balance, just show notification
window.game.showNotification(`+${data.credits} credits (online idle)`, 'success', 2000);
}
}
}
onPlayTimeUpdated(data) {
console.log('[GAME INITIALIZER] PlayTime updated from server:', data);
if (window.game && window.game.systems && window.game.systems.player) {
const player = window.game.systems.player;
// Update playTime from server
player.stats.playTime = data.playTime;
console.log('[GAME INITIALIZER] Updated local playTime to:', data.playTime, 'ms');
console.log('[GAME INITIALIZER] PlayTime in hours:', data.playTime / (1000 * 60 * 60), 'hours');
// Update UI
player.updateUI();
}
}
onPurchaseCompleted(data) {
if (data.success) {
// Update local player data with server response
if (window.game && window.game.systems && window.game.systems.economy) {
const economy = window.game.systems.economy;
// Update currency balance
if (data.currency === 'credits') {
economy.credits = data.newBalance;
} else if (data.currency === 'gems') {
economy.gems = data.newBalance;
}
// Request fresh economy data from server to ensure sync
if (economy.requestEconomyData) {
setTimeout(() => {
economy.requestEconomyData();
}, 500);
}
// Update UI
economy.updateUI();
// Show success message
window.game.showNotification(`Purchased ${data.item.name}!`, 'success', 3000);
}
} else {
// Show error message
window.game.showNotification(`Purchase failed: ${data.error}`, 'error', 5000);
}
}
onShopItemsReceived(data) {
if (data.success && window.game && window.game.systems && window.game.systems.itemSystem) {
// Update ItemSystem with server data
window.game.systems.itemSystem.processServerItems(data.items);
console.log('[GAME INITIALIZER] ItemSystem updated with server shop items');
// Update Economy shop UI
if (window.game.systems.economy) {
window.game.systems.economy.updateShopUI();
console.log('[GAME INITIALIZER] Economy shop UI updated');
}
} else {
console.warn('[GAME INITIALIZER] Failed to receive shop items:', data);
}
}
onItemDetailsReceived(data) {
// This is handled by the ItemSystem directly
// Just log for debugging
if (data.success) {
console.log('[GAME INITIALIZER] Item details received for:', data.item.name);
} else {
console.warn('[GAME INITIALIZER] Failed to receive item details:', data);
}
}
// Cleanup method
cleanup() {
console.log('[GAME INITIALIZER] Cleaning up');
// Reset SmartSaveManager to singleplayer mode
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(false);
}
if (this.socket) {
this.socket.disconnect();
this.socket = null;
@ -353,12 +869,26 @@ class GameInitializer {
this.serverData = null;
this.authToken = null;
this.currentUser = null;
this.serverPlayerData = null;
}
}
// Create global instance
window.gameInitializer = new GameInitializer();
// Make force disconnect available globally for testing
window.forceDisconnectMultiplayer = function() {
if (window.gameInitializer && window.gameInitializer.forceDisconnect) {
window.gameInitializer.forceDisconnect();
} else {
console.log('[GAME INITIALIZER] GameInitializer not available for force disconnect');
}
};
// Debug: Log the global instance immediately
console.log('[GAME INITIALIZER] Global instance created:', window.gameInitializer);
console.log('[GAME INITIALIZER] Global instance gameServerUrl:', window.gameInitializer.gameServerUrl);
// Export for use in other scripts
if (typeof module !== 'undefined' && module.exports) {
module.exports = GameInitializer;

View File

@ -0,0 +1,325 @@
/**
* Save System Integration
* Integrates SmartSaveManager with existing game systems
*/
console.log('[SAVE INTEGRATION] Save system integration loading');
// Override the game's save method to use SmartSaveManager
function integrateWithGameEngine() {
if (window.game && window.game.save) {
// Store original save method
const originalSave = window.game.save;
// Override game save method
window.game.save = async function() {
// console.log('[SAVE INTEGRATION] Game save called');
if (window.smartSaveManager) {
await window.smartSaveManager.save();
} else {
// Fallback to original save if SmartSaveManager not available
return await originalSave.call(this);
}
};
console.log('[SAVE INTEGRATION] Game save method overridden');
}
}
// Override the game's load method to use SmartSaveManager
function integrateLoadSystem() {
if (window.game && window.game.load) {
// Store original load method
const originalLoad = window.game.load;
// Override load method
window.game.load = async function(saveData = null) {
console.log('[SAVE INTEGRATION] Game load called, using SmartSaveManager');
try {
let dataToLoad = saveData;
// If no data provided, use SmartSaveManager
if (!dataToLoad && window.smartSaveManager) {
dataToLoad = await window.smartSaveManager.loadPlayerData();
}
// Load the data
if (dataToLoad) {
if (this.loadPlayerData) {
this.loadPlayerData(dataToLoad);
} else {
// Fallback to original load
return await originalLoad.call(this, dataToLoad);
}
console.log('[SAVE INTEGRATION] Game data loaded successfully');
return true;
} else {
console.log('[SAVE INTEGRATION] No save data found, starting fresh');
return false;
}
} catch (error) {
console.error('[SAVE INTEGRATION] Load error:', error);
return false;
}
};
console.log('[SAVE INTEGRATION] Game load method overridden');
}
}
// Add server data loading method to game
function addServerDataSupport() {
if (window.game) {
// Store pending server data for later application
window.game.pendingServerData = null;
window.game.loadServerPlayerData = function(serverData) {
console.log('[SAVE INTEGRATION] Loading server player data into game');
console.log('[SAVE INTEGRATION] Server data received:', serverData);
console.log('[SAVE INTEGRATION] Server data type:', typeof serverData);
console.log('[SAVE INTEGRATION] Server data keys:', serverData ? Object.keys(serverData) : 'No data');
console.log('[SAVE INTEGRATION] Game systems available:', this.systems ? Object.keys(this.systems) : 'No systems');
// Store server data for later if systems aren't ready
if (!this.systems || Object.keys(this.systems).length === 0) {
console.log('[SAVE INTEGRATION] Game systems not ready, storing data for later');
this.pendingServerData = serverData;
return;
}
console.log('[SAVE INTEGRATION] Game systems ready, applying server data now');
try {
// Apply player stats
if (serverData.stats && this.systems && this.systems.player) {
console.log('[SAVE INTEGRATION] Applying player stats:', serverData.stats);
console.log('[SAVE INTEGRATION] Player system methods:', Object.getOwnPropertyNames(Object.getPrototypeOf(this.systems.player)));
// Check if load method exists
if (typeof this.systems.player.load === 'function') {
this.systems.player.load(serverData.stats);
console.log('[SAVE INTEGRATION] Player stats applied successfully');
console.log('[SAVE INTEGRATION] Updated player stats:', this.systems.player.stats);
} else {
console.warn('[SAVE INTEGRATION] Player system has no load method, trying direct assignment');
// Direct assignment as fallback
if (this.systems.player.stats) {
Object.assign(this.systems.player.stats, serverData.stats);
console.log('[SAVE INTEGRATION] Player stats assigned directly:', this.systems.player.stats);
}
}
} else {
console.warn('[SAVE INTEGRATION] No player system or stats in server data');
console.log('[SAVE INTEGRATION] Has serverData.stats:', !!serverData?.stats);
console.log('[SAVE INTEGRATION] Has systems.player:', !!(this.systems?.player));
}
// Apply inventory
if (serverData.inventory && this.systems && this.systems.inventory) {
console.log('[SAVE INTEGRATION] Applying player inventory:', serverData.inventory);
if (typeof this.systems.inventory.load === 'function') {
this.systems.inventory.load(serverData.inventory);
} else {
console.warn('[SAVE INTEGRATION] Inventory system has no load method');
}
}
// Apply ship data
if (serverData.ship && this.systems && this.systems.ship) {
console.log('[SAVE INTEGRATION] Applying player ship:', serverData.ship);
if (typeof this.systems.ship.load === 'function') {
this.systems.ship.load(serverData.ship);
} else {
console.warn('[SAVE INTEGRATION] Ship system has no load method');
}
}
// Apply base data
if (serverData.base && this.systems && this.systems.base) {
console.log('[SAVE INTEGRATION] Applying player base:', serverData.base);
if (typeof this.systems.base.load === 'function') {
this.systems.base.load(serverData.base);
} else {
console.warn('[SAVE INTEGRATION] Base system has no load method');
}
}
// Show notification
if (this.showNotification) {
this.showNotification(`Welcome back! Level ${serverData.stats?.level || 1}`, 'success', 3000);
}
console.log('[SAVE INTEGRATION] Server player data application completed');
// Force UI update
if (this.systems && this.systems.ui && this.systems.ui.updateUI) {
this.systems.ui.updateUI();
console.log('[SAVE INTEGRATION] Server player data application completed');
}
// Apply pending server data if any exists
if (this.pendingServerData) {
console.log('[SAVE INTEGRATION] Applying pending server data');
this.loadServerPlayerData(this.pendingServerData);
this.pendingServerData = null;
}
} catch (error) {
console.error('[SAVE INTEGRATION] Error applying server player data:', error);
if (this.showNotification) {
this.showNotification('Failed to load server data!', 'error', 3000);
}
}
};
// Method to check and apply pending server data
window.game.checkAndApplyPendingServerData = function() {
if (this.pendingServerData && this.systems && Object.keys(this.systems).length > 0) {
console.log('[SAVE INTEGRATION] Systems ready, applying pending server data');
this.loadServerPlayerData(this.pendingServerData);
this.pendingServerData = null;
}
};
// Fallback loadPlayerData method if GameEngine doesn't have it
if (!window.game.loadPlayerData) {
window.game.loadPlayerData = window.game.loadServerPlayerData;
}
console.log('[SAVE INTEGRATION] Server data support added to game');
}
}
// Add save mode switching to UI
function addSaveModeUI() {
// Add save mode indicator to UI
const createSaveModeIndicator = () => {
const indicator = document.createElement('div');
indicator.id = 'save-mode-indicator';
indicator.style.cssText = `
position: fixed;
bottom: 10px;
right: 10px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 8px 12px;
border-radius: 4px;
font-size: 12px;
z-index: 10000;
display: none;
`;
document.body.appendChild(indicator);
return indicator;
};
const updateSaveModeIndicator = () => {
const indicator = document.getElementById('save-mode-indicator') || createSaveModeIndicator();
if (window.smartSaveManager) {
const info = window.smartSaveManager.getSaveInfo();
indicator.textContent = `Save: ${info.saveLocation}`;
indicator.style.display = 'block';
// Color code based on mode
indicator.style.background = info.isMultiplayer ? 'rgba(0, 100, 200, 0.8)' : 'rgba(0, 150, 0, 0.8)';
}
};
// Update indicator when mode changes
if (window.smartSaveManager) {
const originalSetMultiplayerMode = window.smartSaveManager.setMultiplayerMode;
window.smartSaveManager.setMultiplayerMode = function(...args) {
originalSetMultiplayerMode.apply(this, args);
updateSaveModeIndicator();
};
}
// Initial update
setTimeout(updateSaveModeIndicator, 1000);
}
// Debug function to check data flow
function debugDataFlow() {
console.log('[DEBUG] === DATA FLOW DEBUG ===');
// Check GameInitializer
if (window.gameInitializer) {
console.log('[DEBUG] GameInitializer exists:', !!window.gameInitializer);
console.log('[DEBUG] GameInitializer serverPlayerData:', window.gameInitializer.serverPlayerData);
console.log('[DEBUG] GameInitializer gameMode:', window.gameInitializer.gameMode);
} else {
console.log('[DEBUG] GameInitializer NOT found');
}
// Check game systems
if (window.game) {
console.log('[DEBUG] Game exists:', !!window.game);
console.log('[DEBUG] Game systems:', window.game.systems ? Object.keys(window.game.systems) : 'No systems');
if (window.game.systems && window.game.systems.player) {
console.log('[DEBUG] Player system exists:', !!window.game.systems.player);
console.log('[DEBUG] Player stats:', window.game.systems.player.stats);
console.log('[DEBUG] Player credits:', window.game.systems.player.stats?.credits);
}
} else {
console.log('[DEBUG] Game NOT found');
}
// Check SmartSaveManager
if (window.smartSaveManager) {
console.log('[DEBUG] SmartSaveManager exists:', !!window.smartSaveManager);
console.log('[DEBUG] SmartSaveManager mode:', window.smartSaveManager.isMultiplayer ? 'multiplayer' : 'singleplayer');
} else {
console.log('[DEBUG] SmartSaveManager NOT found');
}
console.log('[DEBUG] === END DEBUG ===');
}
// Debug function available for manual testing
window.debugDataFlow = debugDataFlow;
// Enhanced debug function for connection testing
window.debugConnectionState = function() {
console.log('=== CONNECTION STATE DEBUG ===');
console.log('GameInitializer exists:', !!window.gameInitializer);
console.log('GameInitializer socket connected:', !!window.gameInitializer?.socket?.connected);
console.log('GameInitializer gameMode:', window.gameInitializer?.gameMode);
console.log('GameInitializer serverPlayerData:', !!window.gameInitializer?.serverPlayerData);
console.log('SmartSaveManager exists:', !!window.smartSaveManager);
console.log('SmartSaveManager mode:', window.smartSaveManager?.isMultiplayer ? 'multiplayer' : 'singleplayer');
console.log('Game exists:', !!window.game);
console.log('Game isRunning:', window.game?.isRunning);
console.log('=== END CONNECTION DEBUG ===');
};
// Initialize integration when DOM is ready
function initializeIntegration() {
console.log('[SAVE INTEGRATION] Initializing save system integration');
// Wait for game to be ready
const checkGameReady = () => {
if (window.game) {
integrateWithGameEngine();
integrateLoadSystem();
addServerDataSupport();
addSaveModeUI();
console.log('[SAVE INTEGRATION] Integration complete');
} else {
setTimeout(checkGameReady, 500);
}
};
checkGameReady();
}
// Auto-initialize
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeIntegration);
} else {
initializeIntegration();
}
console.log('[SAVE INTEGRATION] Save system integration loaded');

View File

@ -0,0 +1,228 @@
/**
* Smart Save Manager
* Intelligently handles save data for both singleplayer and multiplayer modes
*/
class SmartSaveManager {
constructor() {
this.isMultiplayer = false;
this.serverPlayerData = null;
this.localSaveData = null;
this.gameInitializer = null;
console.log('[SMART SAVE] SmartSaveManager initialized');
}
setMultiplayerMode(isMultiplayer, gameInitializer = null) {
const oldMode = this.isMultiplayer;
this.isMultiplayer = isMultiplayer;
this.gameInitializer = gameInitializer;
console.log(`[SMART SAVE] Mode change: ${oldMode ? 'multiplayer' : 'singleplayer'} -> ${isMultiplayer ? 'multiplayer' : 'singleplayer'}`);
console.log(`[SMART SAVE] Set to ${isMultiplayer ? 'multiplayer' : 'singleplayer'} mode`);
if (isMultiplayer && gameInitializer) {
// Load server data when switching to multiplayer
this.loadServerData();
}
}
// Load player data (intelligently chooses source)
async loadPlayerData() {
if (this.isMultiplayer) {
return await this.loadServerData();
} else {
return await this.loadLocalData();
}
}
// Save player data (intelligently chooses destination)
async savePlayerData(gameData) {
if (this.isMultiplayer) {
return await this.saveServerData(gameData);
} else {
return await this.saveLocalData(gameData);
}
}
// Load server data
async loadServerData() {
try {
if (!this.gameInitializer || !this.gameInitializer.socket) {
// Don't warn during initialization - this is expected before socket is ready
// console.warn('[SMART SAVE] No multiplayer connection available');
return null;
}
console.log('[SMART SAVE] Loading server player data');
// Request data from server
this.gameInitializer.loadGameDataFromServer();
// Return cached server data if available
return this.serverPlayerData;
} catch (error) {
console.error('[SMART SAVE] Error loading server data:', error);
return null;
}
}
// Save server data (DISABLED - client should not send data to server)
async saveServerData(gameData) {
console.warn('[SMART SAVE] Client save disabled - server is authoritative');
return true; // Pretend it worked to avoid client errors
}
// Load local data
async loadLocalData() {
try {
console.log('[SMART SAVE] Loading local save data');
// Use existing local save system
if (window.mainMenu && window.mainMenu.loadGame) {
const saveData = await window.mainMenu.loadGame(1); // Load slot 1
this.localSaveData = saveData;
return saveData;
}
// Fallback to localStorage
const saveKey = 'gso_save_slot_1';
const saveData = localStorage.getItem(saveKey);
if (saveData) {
const parsed = JSON.parse(saveData);
this.localSaveData = parsed;
return parsed;
}
return null;
} catch (error) {
console.error('[SMART SAVE] Error loading local data:', error);
return null;
}
}
// Save local data
async saveLocalData(gameData) {
try {
// Don't save locally when in multiplayer mode
if (this.isMultiplayer) {
console.log('[SMART SAVE] Skipping local save - in multiplayer mode');
return true;
}
console.log('[SMART SAVE] Saving locally');
// Use existing local save system
if (window.mainMenu && window.mainMenu.saveGame) {
await window.mainMenu.saveGame(1, gameData); // Save to slot 1
this.localSaveData = gameData;
return true;
}
// Fallback to localStorage
const saveKey = 'gso_save_slot_1';
localStorage.setItem(saveKey, JSON.stringify(gameData));
this.localSaveData = gameData;
return true;
} catch (error) {
console.error('[SMART SAVE] Error saving local data:', error);
return false;
}
}
// Apply server data to game
applyServerDataToGame(serverData) {
console.log('[SMART SAVE] Applying server data to game');
this.serverPlayerData = serverData;
// Apply to game if game is running (try both methods)
if (window.game) {
console.log('[SMART SAVE] Game is available, checking for data loading methods');
console.log('[SMART SAVE] - loadPlayerData:', !!window.game.loadPlayerData);
console.log('[SMART SAVE] - loadServerPlayerData:', !!window.game.loadServerPlayerData);
if (window.game.loadServerPlayerData) {
console.log('[SMART SAVE] Using loadServerPlayerData method');
window.game.loadServerPlayerData(serverData);
console.log('[SMART SAVE] Server data applied to game, forcing UI refresh');
// Force UI refresh after applying server data
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
console.log('[SMART SAVE] Forcing UI refresh after server data application');
window.game.systems.ui.forceRefreshAllUI();
} else {
console.warn('[SMART SAVE] UI refresh not available after server data application - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
}
} else if (window.game.loadPlayerData) {
console.log('[SMART SAVE] Using loadPlayerData method');
window.game.loadPlayerData(serverData);
console.log('[SMART SAVE] Server data applied to game, forcing UI refresh');
// Force UI refresh after applying server data
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
console.log('[SMART SAVE] Forcing UI refresh after server data application');
window.game.systems.ui.forceRefreshAllUI();
} else {
console.warn('[SMART SAVE] UI refresh not available after server data application - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
// Try delayed UI refresh since UIManager might not be ready yet
console.log('[SMART SAVE] Attempting delayed UI refresh...');
setTimeout(() => {
if (window.game.systems && window.game.systems.ui && window.game.systems.ui.forceRefreshAllUI) {
console.log('[SMART SAVE] Delayed UI refresh successful');
window.game.systems.ui.forceRefreshAllUI();
} else {
console.warn('[SMART SAVE] Delayed UI refresh also failed - systems:', !!window.game.systems, 'ui:', !!window.game.systems?.ui, 'forceRefreshAllUI:', !!window.game.systems?.ui?.forceRefreshAllUI);
}
}, 2000); // Wait 2 seconds for systems to initialize
}
} else {
console.warn('[SMART SAVE] No data loading method available on game object');
}
} else {
console.warn('[SMART SAVE] Game not available for data application');
}
// Store for game engine
if (window.gameInitializer) {
window.gameInitializer.serverPlayerData = serverData;
}
}
// Get current save source info
getSaveInfo() {
return {
isMultiplayer: this.isMultiplayer,
hasServerData: !!this.serverPlayerData,
hasLocalData: !!this.localSaveData,
saveLocation: this.isMultiplayer ? 'Server Database' : 'Local Storage'
};
}
// Sync data between local and server (for migration)
async syncData(direction = 'toServer') {
if (direction === 'toServer') {
// Upload local data to server
const localData = await this.loadLocalData();
if (localData) {
await this.saveServerData(localData);
console.log('[SMART SAVE] Synced local data to server');
}
} else {
// Download server data to local
const serverData = await this.loadServerData();
if (serverData) {
await this.saveLocalData(serverData);
console.log('[SMART SAVE] Synced server data to local');
}
}
}
}
// Create global instance
window.smartSaveManager = new SmartSaveManager();
console.log('[SMART SAVE] SmartSaveManager loaded and available globally');

View File

@ -5,7 +5,9 @@
class DebugLogger {
constructor() {
this.debugEnabled = true; // Always enabled
// Completely disable debug logging to prevent console flooding
this.debugEnabled = false;
this.startTime = performance.now();
this.stepTimers = new Map();
this.debugLogs = []; // Store logs in memory
@ -15,10 +17,15 @@ class DebugLogger {
this.logger = window.logger || null;
// Log initialization
if (this.debugEnabled) {
this.log('=== DEBUG SESSION STARTED ===');
}
}
async log(message, data = null) {
// Skip logging if debug is disabled
if (!this.debugEnabled) return;
const timestamp = new Date().toISOString();
const stackTrace = new Error().stack;
@ -55,13 +62,13 @@ class DebugLogger {
this.debugLogs.shift();
}
// Always log to console
console.log(`[DEBUG] ${message}`, data || '');
// Skip console logging to prevent flooding
// console.log(`[DEBUG] ${message}`, data || '');
// Log performance data to console
if (performanceData.memory) {
console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
}
// Skip performance logging to prevent flooding
// if (performanceData.memory) {
// console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
// }
// Use existing logger if available
if (this.logger) {
@ -79,6 +86,9 @@ class DebugLogger {
}
async startStep(stepName) {
// Skip logging if debug is disabled
if (!this.debugEnabled) return;
this.stepTimers.set(stepName, performance.now());
await this.log(`STEP START: ${stepName}`, {
type: 'step_start',
@ -88,6 +98,9 @@ class DebugLogger {
}
async endStep(stepName, data = null) {
// Skip logging if debug is disabled
if (!this.debugEnabled) return;
const startTime = this.stepTimers.get(stepName);
const duration = startTime ? (performance.now() - startTime).toFixed(2) : 'N/A';
@ -101,6 +114,9 @@ class DebugLogger {
}
async logStep(stepName, data = null) {
// Skip logging if debug is disabled
if (!this.debugEnabled) return;
await this.log(`STEP: ${stepName}`, {
type: 'step',
step: stepName,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -95,72 +95,24 @@ class Inventory {
maxSlots: this.maxSlots
});
const startingItems = [
{
id: 'starter_blaster_common',
name: 'Common Blaster',
type: 'weapon',
rarity: 'common',
quantity: 1,
stats: { attack: 5, criticalChance: 0.02 },
description: 'A reliable basic blaster for new pilots',
equipable: true,
slot: 'weapon'
},
{
id: 'basic_armor_common',
name: 'Basic Armor',
type: 'armor',
rarity: 'common',
quantity: 1,
stats: { defense: 3 },
description: 'Light armor providing basic protection',
equipable: true,
slot: 'armor'
}
];
if (debugLogger) debugLogger.logStep('Adding starting items', {
startingItemCount: startingItems.length,
startingItems: startingItems.map(item => ({
id: item.id,
name: item.name,
type: item.type,
quantity: item.quantity
}))
// In multiplayer mode, starting items should come from server
if (window.smartSaveManager?.isMultiplayer) {
console.log('[INVENTORY] Multiplayer mode - starting items will be provided by server');
if (debugLogger) debugLogger.logStep('Skipping starting items in multiplayer mode');
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
finalItemCount: this.items.length,
itemsAdded: 0
});
startingItems.forEach(item => {
console.log(`[DEBUG] Adding starting item: ${item.name}`);
const result = this.addItem(item);
console.log(`[DEBUG] Starting item add result: ${result}, inventory size: ${this.items.length}`);
});
// Equip starter items
console.log('[INVENTORY] Equipping starter items');
if (debugLogger) debugLogger.logStep('Equipping starter items');
// Equip starter blaster
const blasterItem = this.items.find(item => item.id === 'starter_blaster');
if (blasterItem) {
console.log('[INVENTORY] Equipping starter blaster');
this.equipItem(blasterItem.id);
return;
}
// Equip basic armor
const armorItem = this.items.find(item => item.id === 'basic_armor');
if (armorItem) {
console.log('[INVENTORY] Equipping basic armor');
this.equipItem(armorItem.id);
}
// Auto-stack starting items
if (debugLogger) debugLogger.logStep('Auto-stacking starting items');
this.autoStackItems();
// Singleplayer mode - no hardcoded starting items available
console.log('[INVENTORY] Singleplayer mode - no hardcoded starting items available');
if (debugLogger) debugLogger.logStep('No starting items available in singleplayer mode');
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
finalItemCount: this.items.length,
itemsAdded: startingItems.length
itemsAdded: 0
});
}

View File

@ -213,12 +213,10 @@ class Logger {
async info(message, data = null) {
await this.log('info', message, data);
console.info(`[INFO] ${message}`, data || '');
}
async debug(message, data = null) {
await this.log('debug', message, data);
console.debug(`[DEBUG] ${message}`, data || '');
}
async gameEvent(eventType, details) {

View File

@ -537,9 +537,9 @@ class Player {
upgrades: []
};
console.log('=== DEBUG: Character Reset ===');
console.log('Player health reset to:', this.attributes.health, '/', this.attributes.maxHealth);
console.log('Ship health reset to:', this.ship.health, '/', this.ship.maxHealth);
// console.log('=== DEBUG: Character Reset ===');
// console.log('Player health reset to:', this.attributes.health, '/', this.attributes.maxHealth);
// console.log('Ship health reset to:', this.ship.health, '/', this.ship.maxHealth);
// Reset skills
this.skills = {};
@ -692,16 +692,43 @@ class Player {
}
updatePlayTime(deltaTime) {
// DISABLED: Reduce console spam for quest debugging
/*
console.log('[PLAYER] updatePlayTime called with deltaTime:', deltaTime, 'ms');
console.log('[PLAYER] Game state check:', {
hasGame: !!this.game,
isRunning: this.game?.isRunning,
isPaused: this.game?.state?.paused,
isHidden: document.hidden
});
*/
// Only update playtime when game is actively running and not paused
if (!this.game || !this.game.isRunning || this.game.state.paused) {
// console.log('[PLAYER] Skipping playtime update - game not running or paused');
return;
}
// Also check if tab is visible (don't count time when tab is in background)
if (document.hidden) {
// console.log('[PLAYER] Skipping playtime update - tab hidden');
return;
}
// DISABLED: Reduce console spam for quest debugging
/*
console.log('[PLAYER] Before update - playTime:', this.stats.playTime, 'ms');
*/
// Use real computer time delta
this.stats.playTime += deltaTime;
// DISABLED: Reduce console spam for quest debugging
/*
console.log('[PLAYER] After update - playTime:', this.stats.playTime, 'ms');
console.log('[PLAYER] PlayTime in seconds:', this.stats.playTime / 1000, 'seconds');
console.log('[PLAYER] PlayTime in minutes:', this.stats.playTime / 60000, 'minutes');
console.log('[PLAYER] PlayTime in hours:', this.stats.playTime / 3600000, 'hours');
*/
}
// UI updates
@ -717,18 +744,25 @@ class Player {
// Update player info
const playerNameElement = document.getElementById('playerName');
const playerTitleElement = document.getElementById('playerTitle');
const playerLevelElement = document.getElementById('playerLevel');
if (playerNameElement) {
playerNameElement.textContent = `${this.info.name} - ${this.info.title}`;
playerNameElement.textContent = this.info.name;
}
if (playerTitleElement) {
playerTitleElement.textContent = ` - ${this.info.title}`;
}
if (playerLevelElement) {
playerLevelElement.textContent = `Lv. ${this.stats.level}`;
}
// Update health and energy
if (this.game && this.game.systems && this.game.systems.ui) {
// Update health and energy only if in multiplayer mode or game is actively running
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldUpdateUI && this.game && this.game.systems && this.game.systems.ui) {
this.game.systems.ui.updateResourceDisplay();
}
@ -765,6 +799,7 @@ class Player {
if (debugLogger) debugLogger.logStep('Player UI update completed', {
elementsUpdated: {
playerName: !!playerNameElement,
playerTitle: !!playerTitleElement,
playerLevel: !!playerLevelElement,
totalKills: !!totalKillsElement,
dungeonsCleared: !!dungeonsClearedElement,
@ -817,9 +852,29 @@ class Player {
try {
if (data.stats) {
console.log('[PLAYER] Loading stats:', data.stats);
console.log('[PLAYER] Current playTime before load:', this.stats.playTime);
console.log('[PLAYER] Server playTime:', data.stats.playTime);
const oldStats = { ...this.stats };
this.stats = { ...this.stats, ...data.stats };
// Preserve playTime if server doesn't provide it or provides 0
const existingPlayTime = this.stats.playTime || 0;
const serverPlayTime = data.stats.playTime || 0;
// Use server playTime if it's greater than existing, otherwise preserve existing
const preservedPlayTime = serverPlayTime > existingPlayTime ? serverPlayTime : existingPlayTime;
console.log('[PLAYER] Preserving playTime:', preservedPlayTime, '(existing:', existingPlayTime, ', server:', serverPlayTime, ')');
// Merge stats but preserve playTime
this.stats = {
...this.stats,
...data.stats,
playTime: preservedPlayTime // Force preserve playTime
};
console.log('[PLAYER] Level after stats load:', this.stats.level);
console.log('[PLAYER] PlayTime after stats load:', this.stats.playTime);
if (debugLogger) debugLogger.logStep('Player stats loaded', {
oldLevel: oldStats.level,

View File

@ -54,8 +54,9 @@ document.addEventListener('DOMContentLoaded', async () => {
window.debugLogger.startStep('domLoad');
window.debugLogger.logStep('DOM loaded, starting initialization');
// Auto-start local server for singleplayer mode
console.log('[MAIN] Checking local server status...');
// Auto-start local server for singleplayer mode (DISABLED to prevent auto-start after multiplayer disconnect)
console.log('[MAIN] Skipping local server auto-start to prevent conflicts with multiplayer mode');
/*
if (window.localServerManager) {
try {
const serverResult = await window.localServerManager.autoStartIfSingleplayer();
@ -78,6 +79,7 @@ document.addEventListener('DOMContentLoaded', async () => {
} else {
console.warn('[MAIN] LocalServerManager not available');
}
*/
// Title bar is already initialized, just log it
console.log('[MAIN] DOM loaded - title bar should already be working');
@ -368,7 +370,7 @@ if (window.performance && window.performance.memory) {
setInterval(() => {
if (window.game && window.game.isRunning) {
const stats = window.game.getPerformanceStats();
if (stats.memory && stats.memory.used / stats.memory.total > 0.9) {
if (stats.memory && stats.memory.used / stats.memory.limit > 0.8) {
console.warn('High memory usage detected:', stats.memory);
}
}

View File

@ -1309,7 +1309,11 @@ class BaseSystem {
});
}
// Only update player UI if in multiplayer mode or game is actively running
if (this.game.shouldUpdateGUI()) {
player.updateUI();
}
this.updateShipGallery();
// Also update ShipSystem display
@ -1592,10 +1596,12 @@ class BaseSystem {
// Apply benefits
this.applyStarbaseBenefits(newStarbase);
// Update UI
// Only update UI if in multiplayer mode or game is actively running
if (this.game.shouldUpdateGUI()) {
economy.updateUI();
this.updateStarbaseList();
this.updateStarbasePurchaseList();
}
this.game.showNotification(`Purchased ${starbaseTemplate.name}!`, 'success', 4000);
}
@ -1650,11 +1656,18 @@ class BaseSystem {
}
startMiningProduction(starbase) {
// Only start mining if in multiplayer mode or game is actively running
const shouldStartMining = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldStartMining && !this.miningInterval) {
// Set up passive credit generation
if (!this.miningInterval) {
this.miningInterval = setInterval(() => {
this.game.systems.economy.addCredits(500, 'mining_outpost');
}, 3600000); // 1 hour
console.log('[BASE SYSTEM] Mining production started');
} else if (!shouldStartMining) {
console.log('[BASE SYSTEM] Skipping mining production - not in multiplayer mode');
}
}
@ -2057,7 +2070,8 @@ showRoomBuildMenu(x, y) {
console.log('[DEBUG] Player ship updated:', player.ship);
console.log('[DEBUG] Player attributes updated:', player.attributes);
// Update UI displays
// Only update UI displays if in multiplayer mode or game is actively running
if (this.game.shouldUpdateGUI()) {
player.updateUI();
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
this.game.systems.ship.updateCurrentShipDisplay();
@ -2065,6 +2079,7 @@ showRoomBuildMenu(x, y) {
}
}
}
}
// Update base stats after loading
if (debugLogger) debugLogger.logStep('Updating base stats after load');

View File

@ -641,8 +641,14 @@ class CraftingSystem extends BaseSystem {
switchCategory(category) {
this.currentCategory = category;
this.selectedRecipe = null;
// Update UI only if in multiplayer mode or game is actively running
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldUpdateUI) {
this.updateUI();
}
}
}
// Export for use in GameEngine

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,18 @@ class IdleSystem {
this.lastActiveTime = Date.now();
this.accumulatedTime = 0; // Track time for resource generation
// Idle production rates
// Idle production rates (online rates)
this.productionRates = {
credits: 10, // credits per second (increased for better gameplay)
experience: 1, // experience per second (increased for better progression)
energy: 0.5 // energy regeneration per second
credits: 0.1, // 1 credit every 10 seconds (0.1 per second)
experience: 0, // no auto experience - only from dungeons
energy: 1/300 // 1 energy every 5 minutes (1/300 per second)
};
// Offline rates (different from online rates)
this.offlineProductionRates = {
credits: 1/60, // 1 credit every 1 minute (1/60 per second)
experience: 0, // no experience offline - only from dungeons
energy: 1/300 // 1 energy every 5 minutes (same as online)
};
// Offline rewards
@ -144,6 +151,20 @@ class IdleSystem {
}
claimOfflineRewards() {
// In multiplayer mode, use server communication
if (window.smartSaveManager?.isMultiplayer) {
this.game.showNotification('Claiming offline rewards from server...', 'info', 2000);
// Send request to server
if (window.game && window.game.socket) {
window.game.socket.emit('claimOfflineRewards', {});
} else {
this.game.showNotification('Not connected to server', 'error', 3000);
}
return;
}
// Singleplayer mode - use local logic
if (this.offlineRewards.credits === 0 &&
this.offlineRewards.experience === 0 &&
this.offlineRewards.items.length === 0) {

View File

@ -0,0 +1,383 @@
/**
* Galaxy Strike Online - Client Item System
* Dynamically loads and manages items from the GameServer
*/
class ItemSystem {
constructor(gameEngine) {
this.game = gameEngine;
// Item storage
this.itemCatalog = new Map(); // itemId -> item data
this.shopItems = []; // Array of shop items
this.lastUpdated = null;
// Loading state
this.isLoading = false;
this.loadPromise = null;
// Event listeners
this.eventListeners = new Map();
}
/**
* Initialize the item system and load data from server
*/
async initialize() {
console.log('[ITEM SYSTEM] Initializing client item system');
if (this.loadPromise) {
return this.loadPromise;
}
this.loadPromise = this.loadFromServer();
return this.loadPromise;
}
/**
* Load all items from the GameServer
*/
async loadFromServer() {
if (this.isLoading) {
console.log('[ITEM SYSTEM] Already loading items from server');
return this.loadPromise;
}
this.isLoading = true;
try {
console.log('[ITEM SYSTEM] Loading items from GameServer - Multiplayer Mode');
console.log('[ITEM SYSTEM] Socket connection status:', !!window.game?.socket);
if (!window.game || !window.game.socket) {
throw new Error('Not connected to server - multiplayer mode requires server connection');
}
// Load shop items from server
const shopItems = await this.fetchShopItems();
console.log('[ITEM SYSTEM] Received', shopItems.length, 'items from server');
// Process and store items
this.processServerItems(shopItems);
this.lastUpdated = Date.now();
console.log(`[ITEM SYSTEM] Successfully loaded ${this.itemCatalog.size} items from server`);
console.log('[ITEM SYSTEM] Item categories loaded:', Object.keys(this.itemCatalog).length);
// Emit loaded event
this.emit('itemsLoaded', {
itemCount: this.itemCatalog.size,
shopItemCount: this.shopItems.length,
timestamp: this.lastUpdated
});
return true;
} catch (error) {
console.error('[ITEM SYSTEM] Failed to load items from server:', error);
console.error('[ITEM SYSTEM] Error details:', {
message: error.message,
stack: error.stack,
socketConnected: !!window.game?.socket,
socketId: window.game?.socket?.id
});
// No fallback - emit error event
this.emit('itemsLoadError', error);
return false;
} finally {
this.isLoading = false;
}
}
/**
* Fetch shop items from the GameServer
*/
async fetchShopItems() {
console.log('[ITEM SYSTEM] Starting fetchShopItems');
if (!window.game || !window.game.socket) {
console.error('[ITEM SYSTEM] No socket connection available');
throw new Error('Not connected to server');
}
console.log('[ITEM SYSTEM] Socket ID:', window.game.socket.id);
console.log('[ITEM SYSTEM] Socket connected:', window.game.socket.connected);
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
console.error('[ITEM SYSTEM] Server request timeout after 10 seconds');
window.game.socket.off('shopItemsReceived', handleResponse);
reject(new Error('Server request timeout'));
}, 10000);
// Request shop items from server
console.log('[ITEM SYSTEM] Emitting getShopItems request');
window.game.socket.emit('getShopItems', {});
// Listen for response
const handleResponse = (data) => {
console.log('[ITEM SYSTEM] Received shopItemsReceived response:', data);
clearTimeout(timeout);
window.game.socket.off('shopItemsReceived', handleResponse);
if (data.success) {
console.log('[ITEM SYSTEM] Successfully received', data.items?.length || 0, 'items');
console.log('[ITEM SYSTEM] Response timestamp:', data.timestamp);
resolve(data.items || []);
} else {
console.error('[ITEM SYSTEM] Server returned error:', data.error);
reject(new Error(data.error || 'Failed to load shop items'));
}
};
console.log('[ITEM SYSTEM] Setting up shopItemsReceived listener');
window.game.socket.on('shopItemsReceived', handleResponse);
});
}
/**
* Fetch specific item details from server
*/
async fetchItemDetails(itemId) {
if (!window.game || !window.game.socket) {
throw new Error('Not connected to server');
}
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('Server request timeout'));
}, 5000);
// Request item details from server
window.game.socket.emit('getItemDetails', { itemId });
// Listen for response
const handleResponse = (data) => {
clearTimeout(timeout);
window.game.socket.off('itemDetailsReceived', handleResponse);
if (data.success) {
// Cache the item
this.itemCatalog.set(itemId, data.item);
resolve(data.item);
} else {
reject(new Error(data.error || 'Item not found'));
}
};
window.game.socket.on('itemDetailsReceived', handleResponse);
});
}
/**
* Process items received from server
*/
processServerItems(items) {
console.log('[ITEM SYSTEM] Processing', items.length, 'items from server');
console.log('[ITEM SYSTEM] Sample items:', items.slice(0, 3));
this.itemCatalog.clear();
this.shopItems = [];
for (const item of items) {
// Store in catalog
this.itemCatalog.set(item.id, item);
// Add to shop items if available for shop
if (item.categories && item.categories.includes('shop')) {
this.shopItems.push(item);
}
console.log('[ITEM SYSTEM] Added item:', {
id: item.id,
name: item.name,
type: item.type,
rarity: item.rarity,
price: item.price,
categories: item.categories
});
}
console.log('[ITEM SYSTEM] Processing complete - Catalog:', this.itemCatalog.size, 'Shop items:', this.shopItems.length);
console.log('[ITEM SYSTEM] Shop items by type:', this.shopItems.reduce((acc, item) => {
acc[item.type] = (acc[item.type] || 0) + 1;
return acc;
}, {}));
}
/**
* Get item by ID
*/
getItem(itemId) {
// Return from cache if available
if (this.itemCatalog.has(itemId)) {
return this.itemCatalog.get(itemId);
}
// Try to fetch from server if not cached
if (window.game && window.game.socket) {
this.fetchItemDetails(itemId).catch(error => {
console.warn(`[ITEM SYSTEM] Failed to fetch item ${itemId}:`, error);
});
}
return null;
}
/**
* Get all shop items
*/
getShopItems() {
return [...this.shopItems];
}
/**
* Get items by category
*/
getItemsByCategory(category) {
return Array.from(this.itemCatalog.values()).filter(item =>
item.type === category || (item.categories && item.categories.includes(category))
);
}
/**
* Get items by type
*/
getItemsByType(type) {
return Array.from(this.itemCatalog.values()).filter(item => item.type === type);
}
/**
* Get items by rarity
*/
getItemsByRarity(rarity) {
return Array.from(this.itemCatalog.values()).filter(item => item.rarity === rarity);
}
/**
* Check if player can use item based on requirements
*/
canPlayerUseItem(item, playerLevel = null) {
if (!item.requirements) return true;
// Get player level if not provided
if (playerLevel === null && window.game && window.game.systems && window.game.systems.player) {
playerLevel = window.game.systems.player.level;
}
// Check level requirement
if (item.requirements.level && playerLevel < item.requirements.level) {
return false;
}
// Add other requirement checks here
return true;
}
/**
* Get filtered shop items for current player
*/
getAvailableShopItems() {
return this.shopItems.filter(item => this.canPlayerUseItem(item));
}
/**
* Format item price for display
*/
formatPrice(item) {
if (!item.price) return 'Free';
const currency = item.currency || 'credits';
const price = this.game.formatNumber(item.price);
return `${price} ${currency}`;
}
/**
* Get item rarity color
*/
getRarityColor(rarity) {
const colors = {
common: '#888888',
uncommon: '#00ff00',
rare: '#0088ff',
legendary: '#ff8800',
epic: '#ff00ff'
};
return colors[rarity] || '#ffffff';
}
/**
* Refresh items from server
*/
async refresh() {
console.log('[ITEM SYSTEM] Refreshing items from server');
return this.loadFromServer();
}
/**
* Event system
*/
on(event, callback) {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, []);
}
this.eventListeners.get(event).push(callback);
}
off(event, callback) {
if (this.eventListeners.has(event)) {
const listeners = this.eventListeners.get(event);
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
}
}
}
emit(event, data) {
if (this.eventListeners.has(event)) {
for (const callback of this.eventListeners.get(event)) {
try {
callback(data);
} catch (error) {
console.error(`[ITEM SYSTEM] Error in event listener for ${event}:`, error);
}
}
}
}
/**
* Get system statistics
*/
getStats() {
const stats = {
totalItems: this.itemCatalog.size,
shopItems: this.shopItems.length,
lastUpdated: this.lastUpdated,
isLoading: this.isLoading,
socketConnected: !!(window.game?.socket),
socketId: window.game?.socket?.id
};
// Add category breakdown
stats.categories = {};
for (const item of this.itemCatalog.values()) {
stats.categories[item.type] = (stats.categories[item.type] || 0) + 1;
}
return stats;
}
}
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = ItemSystem;
} else {
window.ItemSystem = ItemSystem;
}

View File

@ -13,6 +13,10 @@ class QuestSystem {
this.game = gameEngine;
// Server time synchronization
this.serverTimeOffset = 0; // Difference between server and client time
this.lastServerTimeSync = 0;
// Quest types
this.questTypes = {
main: 'Main Story',
@ -788,14 +792,15 @@ class QuestSystem {
this.maxProceduralQuests = 3;
this.proceduralQuestRefresh = 30 * 60 * 1000; // 30 minutes
// Statistics
// Initialize stats
this.stats = {
questsCompleted: 0,
questsFailed: 0,
dailyQuestsCompleted: 0,
weeklyQuestsCompleted: 0,
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
lastDailyReset: Date.now(),
lastWeeklyReset: Date.now()
lastDailyReset: this.getServerTime(),
lastWeeklyReset: this.getServerTime()
};
// Initialize daily quests
@ -816,6 +821,43 @@ class QuestSystem {
});
}
// Server time synchronization methods
getServerTime() {
// In multiplayer mode, use UTC time as server time
if (window.smartSaveManager?.isMultiplayer) {
// Get current UTC timestamp
const utcTime = Date.now();
console.log('[QUEST SYSTEM] Using UTC time as server time:', utcTime);
console.log('[QUEST SYSTEM] Local time:', Date.now());
return utcTime;
}
// Fallback to client time in singleplayer
return Date.now();
}
getServerDate() {
// Create a date that displays in UTC
const timestamp = this.getServerTime();
const utcDate = new Date(timestamp);
// Force UTC display by using UTC methods
return {
getTime: () => timestamp,
getDay: () => utcDate.getUTCDay(),
getHours: () => utcDate.getUTCHours(),
getMinutes: () => utcDate.getUTCMinutes(),
getSeconds: () => utcDate.getUTCSeconds(),
getDate: () => utcDate.getUTCDate(),
getFullYear: () => utcDate.getUTCFullYear(),
getMonth: () => utcDate.getUTCMonth(),
toString: () => utcDate.toUTCString(),
valueOf: () => timestamp
};
}
async initialize() {
const debugLogger = window.debugLogger;
@ -1119,7 +1161,7 @@ class QuestSystem {
// Complete quest
quest.status = 'completed';
quest.completedAt = Date.now();
quest.completedAt = this.getServerTime();
this.completedQuests.push(quest);
if (debugLogger) debugLogger.logStep('Quest marked as completed', {
@ -1131,7 +1173,7 @@ class QuestSystem {
// Save completed daily quests to history
if (quest.type === 'daily') {
const questCopy = { ...quest, completedAt: Date.now() };
const questCopy = { ...quest, completedAt: this.getServerTime() };
this.completedDailyQuests.push(questCopy);
if (debugLogger) debugLogger.logStep('Daily quest added to history', {
@ -1143,7 +1185,7 @@ class QuestSystem {
// Save completed weekly quests to history
if (quest.type === 'weekly') {
const questCopy = { ...quest, completedAt: Date.now() };
const questCopy = { ...quest, completedAt: this.getServerTime() };
this.completedWeeklyQuests.push(questCopy);
if (debugLogger) debugLogger.logStep('Weekly quest added to history', {
@ -1218,22 +1260,6 @@ class QuestSystem {
giveQuestRewards(quest) {
const debugLogger = window.debugLogger;
if (debugLogger) debugLogger.startStep('QuestSystem.giveQuestRewards', {
questId: quest.id,
questName: quest.name,
questType: quest.type,
rewards: quest.rewards
});
const oldPlayerStats = {
credits: this.game.systems.economy.credits,
gems: this.game.systems.economy.gems,
experience: this.game.systems.player.stats.experience,
level: this.game.systems.player.stats.level
};
const rewardsGiven = {};
if (quest.rewards.credits) {
this.game.systems.economy.addCredits(quest.rewards.credits, 'quest');
this.stats.totalRewardsEarned.credits += quest.rewards.credits;
@ -1558,7 +1584,7 @@ class QuestSystem {
this.completedQuests = [];
this.dailyQuests = [];
this.selectedDailyQuests = [];
this.lastDailyReset = Date.now();
this.lastDailyReset = this.getServerTime();
// Reset main quest statuses
this.mainQuests.forEach(quest => {
@ -1591,7 +1617,7 @@ class QuestSystem {
checkDailyReset() {
const debugLogger = window.debugLogger;
const now = Date.now();
const now = this.getServerTime();
const lastReset = this.lastDailyReset;
const daysSinceReset = Math.floor((now - lastReset) / (24 * 60 * 60 * 1000));
@ -1645,20 +1671,27 @@ class QuestSystem {
// Update countdown immediately
this.updateDailyCountdown();
// Only start timer if in multiplayer mode or game is actively running
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldStartTimer) {
// Update every second
this.dailyCountdownInterval = setInterval(() => {
this.updateDailyCountdown();
}, 1000);
console.log('[QUEST SYSTEM] Daily countdown timer started with interval:', this.dailyCountdownInterval);
} else {
console.log('[QUEST SYSTEM] Skipping daily countdown timer - not in multiplayer mode');
}
}
updateDailyCountdown() {
// Always update countdown so it's ready when user switches to daily tab
const now = new Date();
const tomorrow = new Date(now);
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(0, 0, 0, 0); // Set to midnight
const now = this.getServerDate();
const tomorrow = new Date();
tomorrow.setUTCDate(now.getDate() + 1);
tomorrow.setUTCHours(0, 0, 0, 0); // Set to midnight UTC
const timeUntilReset = tomorrow - now;
const hours = Math.floor(timeUntilReset / (1000 * 60 * 60));
@ -1723,11 +1756,11 @@ class QuestSystem {
checkWeeklyReset() {
const debugLogger = window.debugLogger;
const now = Date.now();
const now = this.getServerTime();
const lastReset = this.lastWeeklyReset || 0;
// Calculate if we need to reset based on Saturday midnight
const currentDateTime = new Date();
// Calculate if we need to reset based on Saturday midnight (server time)
const currentDateTime = this.getServerDate();
const dayOfWeek = currentDateTime.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
const currentHour = currentDateTime.getHours();
const currentMinute = currentDateTime.getMinutes();
@ -1805,18 +1838,25 @@ class QuestSystem {
// Update countdown immediately
this.updateWeeklyCountdown();
// Only start timer if in multiplayer mode or game is actively running
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldStartTimer) {
// Update every minute (weekly changes less frequently)
this.weeklyCountdownInterval = setInterval(() => {
this.updateWeeklyCountdown();
// Check for weekly reset every minute
this.checkWeeklyReset();
}, 60000); // Update every minute
}, 60000); // 1 minute
console.log('[QUEST SYSTEM] Weekly countdown timer started with interval:', this.weeklyCountdownInterval);
} else {
console.log('[QUEST SYSTEM] Skipping weekly countdown timer - not in multiplayer mode');
}
}
updateWeeklyCountdown() {
const now = new Date();
const now = this.getServerDate();
const dayOfWeek = now.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
const currentHour = now.getHours();
const currentMinute = now.getMinutes();
@ -1850,19 +1890,19 @@ class QuestSystem {
console.log('[QUEST SYSTEM] Days until Saturday:', daysUntilSaturday);
// Create the target reset time (Saturday midnight)
const nextSaturday = new Date(now);
nextSaturday.setDate(now.getDate() + daysUntilSaturday);
nextSaturday.setHours(0, 0, 0, 0); // Set to midnight
// Create the target reset time (Saturday midnight UTC)
const nextSaturday = new Date();
nextSaturday.setUTCDate(now.getDate() + daysUntilSaturday);
nextSaturday.setUTCHours(0, 0, 0, 0); // Set to midnight UTC
console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toString());
console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toUTCString());
let timeUntilReset = nextSaturday.getTime() - now.getTime();
// Ensure timeUntilReset is positive (handle edge cases)
if (timeUntilReset <= 0) {
console.log('[QUEST SYSTEM] Time until reset is negative or zero, adding 7 days');
nextSaturday.setDate(nextSaturday.getDate() + 7);
nextSaturday.setUTCDate(nextSaturday.getDate() + 7);
timeUntilReset = nextSaturday.getTime() - now.getTime();
}
@ -2067,8 +2107,58 @@ class QuestSystem {
return completed.sort((a, b) => (b.completedAt || 0) - (a.completedAt || 0));
}
// Load quests from server data
loadServerQuests(serverQuestData) {
console.log('[QUEST SYSTEM] Loading server quest data:', serverQuestData);
if (!serverQuestData) {
console.log('[QUEST SYSTEM] No server quest data provided');
return;
}
// Clear existing quests
this.mainQuests = [];
this.dailyQuests = [];
this.weeklyQuests = [];
this.activeQuests = [];
this.completedQuests = [];
// Load quests from server data
if (serverQuestData.mainQuests && Array.isArray(serverQuestData.mainQuests)) {
this.mainQuests = serverQuestData.mainQuests;
console.log('[QUEST SYSTEM] Loaded', this.mainQuests.length, 'main quests');
}
if (serverQuestData.dailyQuests && Array.isArray(serverQuestData.dailyQuests)) {
this.dailyQuests = serverQuestData.dailyQuests;
console.log('[QUEST SYSTEM] Loaded', this.dailyQuests.length, 'daily quests');
}
if (serverQuestData.activeQuests && Array.isArray(serverQuestData.activeQuests)) {
this.activeQuests = serverQuestData.activeQuests;
console.log('[QUEST SYSTEM] Loaded', this.activeQuests.length, 'active quests');
}
if (serverQuestData.completedQuests && Array.isArray(serverQuestData.completedQuests)) {
this.completedQuests = serverQuestData.completedQuests;
console.log('[QUEST SYSTEM] Loaded', this.completedQuests.length, 'completed quests');
}
console.log('[QUEST SYSTEM] Server quest data loaded successfully');
console.log('[QUEST SYSTEM] Total quests loaded:', {
main: this.mainQuests.length,
daily: this.dailyQuests.length,
active: this.activeQuests.length,
completed: this.completedQuests.length
});
}
// UI updates
updateUI() {
console.log('[QUEST SYSTEM] updateUI called');
console.log('[QUEST SYSTEM] Game available:', !!this.game);
console.log('[QUEST SYSTEM] Multiplayer mode:', window.smartSaveManager?.isMultiplayer);
this.updateQuestList();
this.updateQuestStats();
}
@ -2086,6 +2176,7 @@ class QuestSystem {
const quests = this.getQuestsByType(activeType);
console.log(`[QUEST SYSTEM] Getting quests for type: ${activeType}, found: ${quests.length} quests`);
console.log('[QUEST SYSTEM] First few quests:', quests.slice(0, 3));
questListElement.innerHTML = '';
@ -2273,8 +2364,11 @@ class QuestSystem {
break;
}
// Only update player UI if in multiplayer mode or game is actively running
if (this.game.shouldUpdateGUI()) {
player.updateUI();
}
}
// Retry failed quest
retryQuest(questId) {

View File

@ -304,8 +304,12 @@ return true;
player.stats.skillPoints--;
this.levelUpSkill(category, skillId);
// Update UI to refresh skill points display
// Update UI to refresh skill points display only if in multiplayer mode or game is actively running
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldUpdateUI) {
this.updateUI();
}
return true;
}
@ -341,8 +345,12 @@ return true;
this.applySkillEffects();
// Update UI to refresh skill points display
// Update UI to refresh skill points display only if in multiplayer mode or game is actively running
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
if (shouldUpdateUI) {
this.updateUI();
}
this.game.showNotification(`${skill.name} unlocked!`, 'success', 4000);
return true;

View File

@ -37,8 +37,16 @@ class LiveMainMenu {
// Check for existing auth token
this.checkExistingAuth();
// Check for local server and update URLs if needed
this.checkForLocalServer();
// DISABLE local server check - always use remote multiplayer server
// this.checkForLocalServer();
console.log('[LIVE MAIN MENU] Local server check disabled - using remote multiplayer server only');
console.log('[LIVE MAIN MENU] Using remote API:', this.apiBaseUrl);
console.log('[LIVE MAIN MENU] Using remote game server:', this.gameServerUrl);
// Initialize SmartSaveManager to singleplayer mode by default
if (window.smartSaveManager) {
window.smartSaveManager.setMultiplayerMode(false);
}
console.log('[LIVE MAIN MENU] Constructor completed');
}
@ -435,6 +443,9 @@ class LiveMainMenu {
}
async refreshServerList() {
// Build server list with local server, dev server, and API servers
const servers = [];
if (!this.authToken) {
console.error('[LIVE MAIN MENU] No auth token for server list');
return;
@ -447,9 +458,6 @@ class LiveMainMenu {
try {
let response;
// Build server list with local server, dev server, and API servers
const servers = [];
// Add local server if available
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for local server');
@ -459,32 +467,8 @@ class LiveMainMenu {
}
}
// Add dev game server
try {
const devServerResponse = await fetch('http://localhost:3002/health');
if (devServerResponse.ok) {
const devServerInfo = await devServerResponse.json();
servers.push({
id: 'dev-game-server',
name: 'Dev Game Server',
description: 'Development game server for testing',
type: 'development',
region: 'local',
maxPlayers: 8,
currentPlayers: 0,
owner: 'Developer',
address: 'localhost',
port: 3002,
status: 'online',
createdAt: new Date().toISOString(),
ping: 0,
isLocal: true,
isDev: true
});
}
} catch (error) {
console.log('[LIVE MAIN MENU] Dev game server not available:', error.message);
}
// Skip local dev server check to avoid blocking
console.log('[LIVE MAIN MENU] Skipping local dev server check to avoid blocking');
// Add API servers
console.log('[LIVE MAIN MENU] Fetching server list from:', `${this.apiBaseUrl}/servers`);
@ -495,37 +479,35 @@ class LiveMainMenu {
'Content-Type': 'application/json'
}
});
if (apiResponse.ok) {
const apiData = await apiResponse.json();
if (apiData.success && apiData.servers) {
servers.push(...apiData.servers);
console.log(`[LIVE MAIN MENU] Server list loaded: ${servers.length} servers found`);
// Debug: Log server list data
console.log('[LIVE MAIN MENU] Server list loaded:', servers);
if (servers.length > 0) {
console.log('[LIVE MAIN MENU] First server details:', servers[0]);
}
}
}
this.servers = servers;
console.log('[LIVE MAIN MENU] Server list loaded:', servers.length, 'servers found');
// Display servers
this.renderServerList();
} catch (error) {
console.error('[LIVE MAIN MENU] Server list error:', error);
this.servers = [];
this.renderServerList();
// Show error message to user
this.showLoginNotice(`Network error: ${error.message}`, 'error');
console.error('[LIVE MAIN MENU] Error fetching server list:', error);
this.showLoginNotice('Connection error. Please try again.', 'error');
} finally {
// Hide loading state
if (this.serverLoading) this.serverLoading.classList.add('hidden');
}
// Store servers
this.servers = servers;
// Render server list
this.renderServerList();
}
renderServerList() {
if (!this.servers) return;
const filteredServers = this.getFilteredServers();
// Handle empty state
@ -553,6 +535,22 @@ class LiveMainMenu {
this.updateServerItemsSmoothly(currentItems, newItems);
}
removeServerItemsSmoothly() {
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
if (existingItems.length === 0) return;
// Add fade-out transition
existingItems.forEach(item => {
item.style.transition = 'opacity 0.2s ease-out';
item.style.opacity = '0';
});
// Remove items after fade out
setTimeout(() => {
existingItems.forEach(item => item.remove());
}, 200);
}
removeServerItemsSmoothly() {
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
@ -1026,6 +1024,13 @@ Status: ${this.selectedServer.status}
launchMultiplayerGame(server, serverData) {
console.log('[LIVE MAIN MENU] Launching multiplayer game on server:', server.name);
// Set SmartSaveManager to multiplayer mode
if (window.smartSaveManager && window.gameInitializer) {
window.smartSaveManager.setMultiplayerMode(true, window.gameInitializer);
console.log('[LIVE MAIN MENU] SmartSaveManager set to multiplayer mode');
}
// Hide main menu and start game in multiplayer mode
this.hideLoadingScreenAndShowGame();
this.initializeMultiplayerGame(server, serverData);
@ -1051,37 +1056,21 @@ Status: ${this.selectedServer.status}
initializeMultiplayerGame(server, serverData) {
console.log('[LIVE MAIN MENU] Initializing multiplayer game');
// Check if GameEngine is available, if not create a basic fallback
if (typeof GameEngine === 'undefined') {
console.warn('[LIVE MAIN MENU] GameEngine class not available, creating fallback');
// Create a basic fallback GameEngine class
window.GameEngine = class GameEngine extends EventTarget {
constructor() {
super();
this.systems = {};
this.gameTime = 0;
this.isRunning = false;
this.isFallback = true; // Mark as fallback for UIManager
console.log('[LIVE MAIN MENU] Fallback GameEngine created');
// DELAY GameEngine creation until after multiplayer connection is ready
// First, set up GameInitializer and socket connection
if (!window.gameInitializer) {
console.log('[LIVE MAIN MENU] Creating new GameInitializer for multiplayer');
window.gameInitializer = new GameInitializer();
}
async init() {
console.log('[LIVE MAIN MENU] Fallback GameEngine init() called');
return true;
}
// Set up server URLs and connection first
window.gameInitializer.updateServerUrls(
'https://api.korvarix.com/api',
server.url || 'https://dev.gameserver.galaxystrike.online'
);
setMultiplayerMode(isMultiplayer, socket, serverData, currentUser) {
console.log('[LIVE MAIN MENU] Fallback GameEngine setMultiplayerMode called');
this.isMultiplayer = isMultiplayer;
this.socket = socket;
this.serverData = serverData;
this.currentUser = currentUser;
}
startGame(continueGame) {
console.log('[LIVE MAIN MENU] Fallback GameEngine startGame called, continueGame:', continueGame);
this.isRunning = true;
// Initialize multiplayer mode (this will handle GameEngine creation after authentication)
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
// Add simple return to menu functionality
window.returnToMainMenu = () => {
@ -1092,237 +1081,63 @@ Status: ${this.selectedServer.status}
};
}
getPerformanceStats() {
console.log('[LIVE MAIN MENU] Fallback GameEngine getPerformanceStats called');
return {
gameTime: this.gameTime,
isRunning: this.isRunning,
fps: 60,
memory: 'N/A (fallback mode)'
};
checkForLocalServer() {
console.log('[LIVE MAIN MENU] Checking for local server...');
// Check if local server manager is available and running
if (window.localServerManager) {
const serverStatus = window.localServerManager.getStatus();
if (serverStatus.isRunning) {
console.log('[LIVE MAIN MENU] Local server detected, switching to local mode');
this.isLocalMode = true;
this.apiBaseUrl = `http://localhost:${serverStatus.port}/api`;
this.gameServerUrl = `http://localhost:${serverStatus.port}`;
console.log(`[LIVE MAIN MENU] Updated API URL to: ${this.apiBaseUrl}`);
// Update button to show local mode
if (this.createServerBtn) {
this.createServerBtn.innerHTML = '<i class="fas fa-check"></i> Local Server Running';
this.createServerBtn.classList.remove('btn-primary');
this.createServerBtn.classList.add('btn-success');
}
showNotification(message, type = 'info', duration = 3000) {
console.log(`[LIVE MAIN MENU] Fallback notification: ${message} (${type})`);
// Simple console notification for fallback mode
if (typeof console !== 'undefined') {
console.log(`📢 ${type.toUpperCase()}: ${message}`);
}
}
// Auto-login for local mode
this.autoLoginLocalMode();
save() {
console.log('[LIVE MAIN MENU] Fallback GameEngine save called');
// Save will be handled by the main save logic when it detects local mode
return Promise.resolve({ success: true });
}
};
}
// Create GameEngine if it doesn't exist
if (!window.game) {
console.log('[LIVE MAIN MENU] Creating new GameEngine instance for multiplayer');
try {
window.game = new GameEngine();
// Initialize the game engine
window.game.init().then(() => {
console.log('[LIVE MAIN MENU] GameEngine initialized successfully for multiplayer');
// Apply pending save data if available (after GameEngine is ready)
if (window.liveMainMenu && window.liveMainMenu.pendingSaveData) {
console.log('[LIVE MAIN MENU] Applying pending save data after GameEngine init...');
try {
const saveData = window.liveMainMenu.pendingSaveData;
console.log('[LIVE MAIN MENU] Save data structure:', {
hasPlayer: !!saveData.player,
hasInventory: !!saveData.inventory,
hasEconomy: !!saveData.economy,
hasIdleSystem: !!saveData.idleSystem,
hasDungeonSystem: !!saveData.dungeonSystem,
hasSkillSystem: !!saveData.skillSystem,
hasBaseSystem: !!saveData.baseSystem,
hasQuestSystem: !!saveData.questSystem,
gameTime: saveData.gameTime,
playerLevel: saveData.player?.stats?.level
});
console.log('[LIVE MAIN MENU] Game systems available:', {
hasGame: !!window.game,
hasSystems: !!window.game?.systems,
hasPlayer: !!window.game?.systems?.player,
hasInventory: !!window.game?.systems?.inventory,
hasEconomy: !!window.game?.systems?.economy,
hasIdleSystem: !!window.game?.systems?.idleSystem,
hasDungeonSystem: !!window.game?.systems?.dungeonSystem,
hasSkillSystem: !!window.game?.systems?.skillSystem,
hasBaseSystem: !!window.game?.systems?.baseSystem,
hasQuestSystem: !!window.game?.systems?.questSystem
});
let appliedCount = 0;
// Apply save data to game systems
if (saveData.player && window.game.systems.player) {
window.game.systems.player.load(saveData.player);
console.log('[LIVE MAIN MENU] ✅ Player data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Player data NOT loaded - saveData.player:', !!saveData.player, 'window.game.systems.player:', !!window.game?.systems?.player);
}
if (saveData.inventory && window.game.systems.inventory) {
window.game.systems.inventory.load(saveData.inventory);
console.log('[LIVE MAIN MENU] ✅ Inventory data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Inventory data NOT loaded - saveData.inventory:', !!saveData.inventory, 'window.game.systems.inventory:', !!window.game?.systems?.inventory);
}
if (saveData.economy && window.game.systems.economy) {
window.game.systems.economy.load(saveData.economy);
console.log('[LIVE MAIN MENU] ✅ Economy data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Economy data NOT loaded - saveData.economy:', !!saveData.economy, 'window.game.systems.economy:', !!window.game?.systems?.economy);
}
if (saveData.idleSystem && window.game.systems.idleSystem) {
window.game.systems.idleSystem.load(saveData.idleSystem);
console.log('[LIVE MAIN MENU] ✅ Idle system data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Idle system data NOT loaded - saveData.idleSystem:', !!saveData.idleSystem, 'window.game.systems.idleSystem:', !!window.game?.systems?.idleSystem);
}
if (saveData.dungeonSystem && window.game.systems.dungeonSystem) {
window.game.systems.dungeonSystem.load(saveData.dungeonSystem);
console.log('[LIVE MAIN MENU] ✅ Dungeon system data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Dungeon system data NOT loaded - saveData.dungeonSystem:', !!saveData.dungeonSystem, 'window.game.systems.dungeonSystem:', !!window.game?.systems?.dungeonSystem);
}
if (saveData.skillSystem && window.game.systems.skillSystem) {
window.game.systems.skillSystem.load(saveData.skillSystem);
console.log('[LIVE MAIN MENU] ✅ Skill system data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Skill system data NOT loaded - saveData.skillSystem:', !!saveData.skillSystem, 'window.game.systems.skillSystem:', !!window.game?.systems?.skillSystem);
}
if (saveData.baseSystem && window.game.systems.baseSystem) {
window.game.systems.baseSystem.load(saveData.baseSystem);
console.log('[LIVE MAIN MENU] ✅ Base system data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Base system data NOT loaded - saveData.baseSystem:', !!saveData.baseSystem, 'window.game.systems.baseSystem:', !!window.game?.systems?.baseSystem);
}
if (saveData.questSystem && window.game.systems.questSystem) {
window.game.systems.questSystem.load(saveData.questSystem);
console.log('[LIVE MAIN MENU] ✅ Quest system data loaded from pending save');
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Quest system data NOT loaded - saveData.questSystem:', !!saveData.questSystem, 'window.game.systems.questSystem:', !!window.game?.systems?.questSystem);
}
if (saveData.gameTime && window.game) {
window.game.gameTime = saveData.gameTime;
console.log('[LIVE MAIN MENU] ✅ Game time loaded from pending save:', saveData.gameTime);
appliedCount++;
} else {
console.log('[LIVE MAIN MENU] ❌ Game time NOT loaded - saveData.gameTime:', !!saveData.gameTime, 'window.game:', !!window.game);
}
console.log(`[LIVE MAIN MENU] Save data application complete: ${appliedCount}/9 systems loaded`);
if (appliedCount === 0) {
console.warn('[LIVE MAIN MENU] ⚠️ NO save data was applied! This is why the UI shows fresh game state.');
console.warn('[LIVE MAIN MENU] ⚠️ The fallback GameEngine does not have the required game systems.');
}
console.log('[LIVE MAIN MENU] Pending save data applied successfully');
// Clear pending save data
window.liveMainMenu.pendingSaveData = null;
} catch (error) {
console.error('[LIVE MAIN MENU] Error applying pending save data:', error);
console.log('[LIVE MAIN MENU] No local server running');
}
} else {
console.log('[LIVE MAIN MENU] No pending save data to apply');
}
// Now initialize multiplayer mode through GameInitializer
if (window.gameInitializer) {
// Determine the correct game server URL based on server type
let gameServerUrl = this.gameServerUrl; // Default to dev server
if (server.isLocal) {
gameServerUrl = this.localGameServerUrl;
} else if (server.isDev) {
gameServerUrl = this.gameServerUrl;
} else {
// Use server address and port for remote servers
gameServerUrl = `http://${server.address}:${server.port}`;
}
console.log('[LIVE MAIN MENU] Using game server URL:', gameServerUrl);
window.gameInitializer.updateServerUrls(this.apiBaseUrl, gameServerUrl);
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
}
}).catch(error => {
console.error('[LIVE MAIN MENU] Failed to initialize GameEngine for multiplayer:', error);
this.showLoginNotice('Failed to initialize game: ' + error.message, 'error');
});
} catch (error) {
console.error('[LIVE MAIN MENU] Error creating GameEngine:', error);
this.showLoginNotice('Failed to create game engine: ' + error.message, 'error');
}
} else {
console.log('[LIVE MAIN MENU] GameEngine already exists, initializing multiplayer mode');
// Initialize multiplayer mode through GameInitializer
if (window.gameInitializer) {
// Determine the correct game server URL based on server type
let gameServerUrl = this.gameServerUrl; // Default to dev server
if (server.isLocal) {
gameServerUrl = this.localGameServerUrl;
} else if (server.isDev) {
gameServerUrl = this.gameServerUrl;
} else {
// Use server address and port for remote servers
gameServerUrl = `http://${server.address}:${server.port}`;
}
console.log('[LIVE MAIN MENU] Using game server URL:', gameServerUrl);
window.gameInitializer.updateServerUrls(this.apiBaseUrl, gameServerUrl);
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
}
console.log('[LIVE MAIN MENU] Local server manager not available');
}
}
async startLocalServer() {
console.log('[LIVE MAIN MENU] Starting local server...');
// Disable button to prevent multiple clicks
if (this.createServerBtn) {
this.createServerBtn.disabled = true;
this.createServerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Starting...';
}
try {
// Check if LocalServerManager is available
if (!window.localServerManager) {
console.error('[LIVE MAIN MENU] LocalServerManager not available');
this.showLoginNotice('Local server manager not available', 'error');
// Reset button
if (this.createServerBtn) {
this.createServerBtn.disabled = false;
this.createServerBtn.innerHTML = '<i class="fas fa-server"></i> Start Local Server';
}
return;
}
// Update button to show loading state
if (this.createServerBtn) {
this.createServerBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Starting...';
this.createServerBtn.disabled = true;
}
// Show loading message
this.showLoginNotice('Starting local server...', 'info');
// Start the local server
const result = await window.localServerManager.startServer();
if (result.success) {
@ -1370,117 +1185,16 @@ Status: ${this.selectedServer.status}
}
}
}
checkForLocalServer() {
console.log('[LIVE MAIN MENU] Checking for local server...');
// Check if local server manager is available and running
if (window.localServerManager) {
const serverStatus = window.localServerManager.getStatus();
if (serverStatus.isRunning) {
console.log('[LIVE MAIN MENU] Local server detected, switching to local mode');
this.isLocalMode = true;
this.apiBaseUrl = `http://localhost:${serverStatus.port}/api`;
this.gameServerUrl = `http://localhost:${serverStatus.port}`;
console.log(`[LIVE MAIN MENU] Updated API URL to: ${this.apiBaseUrl}`);
console.log(`[LIVE MAIN MENU] Updated Game Server URL to: ${this.gameServerUrl}`);
// Update login notice to show local mode
this.showLoginNotice('Local server active - Singleplayer mode available', 'info');
// Auto-login for local mode
this.autoLoginLocalMode();
} else {
console.log('[LIVE MAIN MENU] Local server not running, using remote servers');
}
} else {
console.log('[LIVE MAIN MENU] LocalServerManager not available');
}
}
async autoLoginLocalMode() {
console.log('[LIVE MAIN MENU] Auto-logging in to local mode...');
try {
let response;
// Use SimpleLocalServer mock API if available
if (window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API');
response = await window.localServerManager.localServer.mockRequest('POST', '/api/auth/login', {
email: 'local@player.com',
password: 'local'
});
} else {
// Fallback to real fetch
console.log('[LIVE MAIN MENU] Using real fetch for local login');
response = await fetch(`${this.apiBaseUrl}/auth/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: 'local@player.com',
password: 'local'
})
});
}
const data = await response.json();
if (data.success) {
console.log('[LIVE MAIN MENU] Local mode login successful');
this.authToken = data.token;
this.currentUser = data.user;
// Update UI
this.hideLoginNotice();
this.showServerSection(false, false); // Show section without refreshing or animating
// Load servers (will show local server)
this.refreshServerList();
} else {
console.error('[LIVE MAIN MENU] Local mode login failed:', data);
}
} catch (error) {
console.error('[LIVE MAIN MENU] Error in local mode auto-login:', error);
}
}
}
// Initialize the live main menu when DOM is ready
function initializeLiveMainMenu() {
console.log('[LIVE MAIN MENU] Initializing LiveMainMenu...');
// End of LiveMainMenu class
// Wait a bit for DOM to be fully ready
setTimeout(() => {
if (!window.liveMainMenu) {
console.log('[LIVE MAIN MENU] Creating new LiveMainMenu instance');
window.liveMainMenu = new LiveMainMenu();
} else {
console.log('[LIVE MAIN MENU] LiveMainMenu already exists');
}
}, 100);
}
// Try multiple initialization methods
if (document.readyState === 'loading') {
// DOM is still loading, wait for DOMContentLoaded
document.addEventListener('DOMContentLoaded', initializeLiveMainMenu);
} else {
// DOM is already ready, initialize immediately
initializeLiveMainMenu();
}
// Also try initialization as a fallback
setTimeout(() => {
if (!window.liveMainMenu) {
console.warn('[LIVE MAIN MENU] Fallback initialization triggered');
// Initialize LiveMainMenu when DOM is ready
document.addEventListener('DOMContentLoaded', () => {
if (typeof window !== 'undefined') {
window.liveMainMenu = new LiveMainMenu();
}
}, 1000);
});
// Export for use in other scripts
if (typeof module !== 'undefined' && module.exports) {

View File

@ -43,16 +43,19 @@ class UIManager {
const gameInterface = document.getElementById('gameInterface');
const navButtons = document.querySelectorAll('.nav-btn');
if (debugLogger) debugLogger.logStep('DOM Check', {
console.log('[UI MANAGER] DOM Check:', {
gameInterfaceExists: !!gameInterface,
gameInterfaceHidden: gameInterface?.classList.contains('hidden'),
navButtonsFound: navButtons.length,
documentReady: document.readyState
});
if (gameInterface && !gameInterface.classList.contains('hidden') && navButtons.length > 0) {
// 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);
}
};
@ -117,10 +120,6 @@ class UIManager {
});
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
navButtonsSetup: navButtons.length,
skillCatButtonsSetup: skillCatButtons.length,
shopCatButtonsSetup: shopCatButtons.length,
questTabButtonsSetup: questTabButtons.length,
craftingCatButtonsSetup: craftingCatButtons.length
});
}
@ -140,10 +139,11 @@ class UIManager {
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);
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`);
@ -151,16 +151,30 @@ class UIManager {
}
btn.addEventListener('click', (e) => {
console.log(`[UIManager] Navigation button clicked: ${btn.dataset.tab}`);
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 button as having a listener
// Mark as having listener
btn.setAttribute('data-has-listener', 'true');
console.log(`[UIManager] Button ${btn.dataset.tab} setup complete`);
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
@ -284,7 +298,7 @@ class UIManager {
// if (debugLogger) debugLogger.logStep('Setting up return to menu button');
returnToMenuBtn.addEventListener('click', () => {
if (debugLogger) debugLogger.log('Return to menu button clicked');
this.returnToMainMenu();
this.showReturnToMainMenuModal();
});
// Mark as having listener
@ -712,28 +726,77 @@ class UIManager {
} 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
});
}
}
confirmReturnToMainMenu() {
async confirmReturnToMainMenu() {
try {
const debugLogger = window.debugLogger;
if (debugLogger) debugLogger.startStep('UIManager.confirmReturnToMainMenu', {
gameRunning: this.game ? this.game.isRunning : false
// 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
});
// Stop the game engine and save
if (this.game && typeof this.game.isRunning === 'boolean') {
// if (debugLogger) debugLogger.logStep('Stopping game engine and saving');
// Handle async stop properly
} else {
// Handle async stop properly for singleplayer mode
this.game.stop().then(() => {
try {
@ -747,6 +810,25 @@ class UIManager {
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 {
@ -765,26 +847,36 @@ class UIManager {
saveError: true,
mainMenuShown: true
});
} catch (fallbackError) {
} 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;
@ -1005,8 +1097,10 @@ class UIManager {
gameStateUpdated: true
});
// Update specific tab content
// 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,
@ -1019,6 +1113,10 @@ class UIManager {
}
updateTabContent(tabName) {
if (!this.shouldUpdateUI()) {
return;
}
if (debugLogger) debugLogger.startStep('UIManager.updateTabContent', {
tabName: tabName,
currentTab: this.currentTab
@ -1208,8 +1306,14 @@ class UIManager {
});
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,
@ -1229,13 +1333,7 @@ class UIManager {
}
}
switchQuestType(type) {
const debugLogger = window.debugLogger;
if (debugLogger) debugLogger.startStep('UIManager.switchQuestType', {
type: type
});
updateQuestTabs(type) {
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
let buttonsUpdated = 0;
@ -1255,7 +1353,13 @@ class UIManager {
});
try {
this.game.systems.questSystem.updateUI();
// 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,
@ -1403,7 +1507,29 @@ class UIManager {
});
}
// Handle UI update events from GameEngine
// 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;
@ -1447,6 +1573,10 @@ class UIManager {
}
updateAllUI() {
if (!this.shouldUpdateUI()) {
return;
}
// if (debugLogger) debugLogger.log('Updating all UI elements');
this.updateResourceDisplay();
@ -1481,18 +1611,40 @@ class UIManager {
});
}
// 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() {
const debugLogger = window.debugLogger;
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');
// 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');
// if (debugLogger) debugLogger.log('Player or economy system not available, skipping resource display update');
return;
}
@ -1501,18 +1653,18 @@ class UIManager {
// 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');
// 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
});
// 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;
@ -1522,6 +1674,7 @@ class UIManager {
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++;
@ -1532,7 +1685,7 @@ class UIManager {
});
} else {
elementsNotFound++;
if (debugLogger) debugLogger.log('Player level element not found');
// if (debugLogger) debugLogger.log('Player level element not found');
}
// Update ship level with safety checks
@ -1559,6 +1712,7 @@ class UIManager {
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++;
@ -1578,6 +1732,7 @@ class UIManager {
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++;
@ -1596,9 +1751,9 @@ class UIManager {
const energyElement = document.getElementById('energy');
if (energyElement) {
const oldEnergy = energyElement.textContent;
// Ensure we're using the correct energy values, not credits
const currentEnergy = Math.floor(player.attributes.energy || 0);
const maxEnergy = Math.floor(player.attributes.maxEnergy || 100);
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++;
@ -1615,6 +1770,65 @@ class UIManager {
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,
@ -1633,29 +1847,132 @@ class UIManager {
}
}
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;
// const debugLogger = window.debugLogger;
if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
currentTab: this.currentTab,
modalOpen: this.modalOpen
});
// if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
// currentTab: this.currentTab,
// modalOpen: this.modalOpen
// });
// Update resource display
if (debugLogger) debugLogger.logStep('Updating resource display');
// 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
if (debugLogger) debugLogger.logStep('Updating tab content', {
currentTab: this.currentTab
});
// 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
});
// if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
// resourceDisplayUpdated: true,
// tabContentUpdated: true,
// currentTab: this.currentTab
// });
}
// Menus
@ -1807,8 +2124,8 @@ class UIManager {
} else {
}
// Reset economy
if (this.game.systems.economy) {
// 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;
}
@ -1927,8 +2244,8 @@ class UIManager {
};
}
// Clear economy data
if (this.game.systems.economy) {
// 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;
}

View File

@ -1196,6 +1196,13 @@ body {
.player-info {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.player-info > div {
display: flex;
align-items: center;
gap: 0.3rem;
}
.player-name {
@ -1203,6 +1210,18 @@ body {
color: var(--text-primary);
}
.player-title {
font-weight: 500;
color: var(--text-secondary);
font-size: 0.9rem;
}
.player-username {
font-weight: 600;
color: var(--accent-color);
font-size: 0.85rem;
}
.player-level {
font-size: 0.8rem;
color: var(--primary-color);
@ -1381,6 +1400,20 @@ body {
gap: 0.5rem;
}
.player-stats-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 0.5rem;
max-height: 400px;
overflow-y: auto;
}
@media (max-width: 768px) {
.player-stats-grid {
grid-template-columns: 1fr;
}
}
.stat {
display: flex;
justify-content: space-between;