almost a full rework of the client with server data-driven calls
This commit is contained in:
parent
4aeb217e51
commit
b793b85e25
@ -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://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">
|
<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="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>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!-- Custom Title Bar -->
|
<!-- Custom Title Bar -->
|
||||||
@ -220,8 +218,14 @@
|
|||||||
<div class="header-left">
|
<div class="header-left">
|
||||||
<h1 class="logo">GSO</h1>
|
<h1 class="logo">GSO</h1>
|
||||||
<div class="player-info">
|
<div class="player-info">
|
||||||
<span class="player-name" id="playerName">Commander</span>
|
<div>
|
||||||
<span class="player-level" id="playerLevel">Lv. 1</span>
|
<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>
|
</div>
|
||||||
<div class="header-center">
|
<div class="header-center">
|
||||||
@ -261,35 +265,35 @@
|
|||||||
|
|
||||||
<!-- Navigation -->
|
<!-- Navigation -->
|
||||||
<nav class="main-nav">
|
<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>
|
<i class="fas fa-tachometer-alt"></i>
|
||||||
<span>Dashboard</span>
|
<span>Dashboard</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="dungeons">
|
<button class="nav-btn" data-tab="dungeons" onclick="switchToTab('dungeons')">
|
||||||
<i class="fas fa-dungeon"></i>
|
<i class="fas fa-dungeon"></i>
|
||||||
<span>Dungeons</span>
|
<span>Dungeons</span>
|
||||||
</button>
|
</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>
|
<i class="fas fa-graduation-cap"></i>
|
||||||
<span>Skills</span>
|
<span>Skills</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="base">
|
<button class="nav-btn" data-tab="base" onclick="switchToTab('base')">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-home"></i>
|
||||||
<span>Base</span>
|
<span>Base</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="quests">
|
<button class="nav-btn" data-tab="quests" onclick="switchToTab('quests')">
|
||||||
<i class="fas fa-scroll"></i>
|
<i class="fas fa-scroll"></i>
|
||||||
<span>Quests</span>
|
<span>Quests</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="inventory">
|
<button class="nav-btn" data-tab="inventory" onclick="switchToTab('inventory')">
|
||||||
<i class="fas fa-backpack"></i>
|
<i class="fas fa-backpack"></i>
|
||||||
<span>Inventory</span>
|
<span>Inventory</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="crafting">
|
<button class="nav-btn" data-tab="crafting" onclick="switchToTab('crafting')">
|
||||||
<i class="fas fa-hammer"></i>
|
<i class="fas fa-hammer"></i>
|
||||||
<span>Crafting</span>
|
<span>Crafting</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="nav-btn" data-tab="shop">
|
<button class="nav-btn" data-tab="shop" onclick="switchToTab('shop')">
|
||||||
<i class="fas fa-store"></i>
|
<i class="fas fa-store"></i>
|
||||||
<span>Shop</span>
|
<span>Shop</span>
|
||||||
</button>
|
</button>
|
||||||
@ -320,7 +324,35 @@
|
|||||||
<p>Resources Gained: <span id="offlineResources">0</span></p>
|
<p>Resources Gained: <span id="offlineResources">0</span></p>
|
||||||
<button class="btn btn-primary" id="claimOfflineBtn">Claim Rewards</button>
|
<button class="btn btn-primary" id="claimOfflineBtn">Claim Rewards</button>
|
||||||
</div>
|
</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">
|
<div class="stat">
|
||||||
<span class="stat-label">Total Kills</span>
|
<span class="stat-label">Total Kills</span>
|
||||||
<span class="stat-value" id="totalKills">0</span>
|
<span class="stat-value" id="totalKills">0</span>
|
||||||
@ -331,7 +363,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="stat">
|
<div class="stat">
|
||||||
<span class="stat-label">Play Time</span>
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -366,9 +398,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="skill-categories">
|
<div class="skill-categories">
|
||||||
<button class="skill-cat-btn active" data-category="combat">Combat</button>
|
<button class="skill-cat-btn active" data-category="combat" onclick="switchSkillCategory('combat')">Combat</button>
|
||||||
<button class="skill-cat-btn" data-category="science">Science</button>
|
<button class="skill-cat-btn" data-category="science" onclick="switchSkillCategory('science')">Science</button>
|
||||||
<button class="skill-cat-btn" data-category="crafting">Crafting</button>
|
<button class="skill-cat-btn" data-category="crafting" onclick="switchSkillCategory('crafting')">Crafting</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="skills-grid" id="skillsGrid">
|
<div class="skills-grid" id="skillsGrid">
|
||||||
<!-- Skills will be generated here -->
|
<!-- Skills will be generated here -->
|
||||||
@ -379,10 +411,10 @@
|
|||||||
<!-- Base Tab -->
|
<!-- Base Tab -->
|
||||||
<div class="tab-content" id="base-tab">
|
<div class="tab-content" id="base-tab">
|
||||||
<div class="base-navigation">
|
<div class="base-navigation">
|
||||||
<button class="base-nav-btn active" data-view="overview">Base Overview</button>
|
<button class="base-nav-btn active" data-view="overview" onclick="switchBaseView('overview')">Base Overview</button>
|
||||||
<button class="base-nav-btn" data-view="visualization">Base Visualization</button>
|
<button class="base-nav-btn" data-view="visualization" onclick="switchBaseView('visualization')">Base Visualization</button>
|
||||||
<button class="base-nav-btn" data-view="ships">Ship Gallery</button>
|
<button class="base-nav-btn" data-view="ships" onclick="switchBaseView('ships')">Ship Gallery</button>
|
||||||
<button class="base-nav-btn" data-view="starbases">Starbases</button>
|
<button class="base-nav-btn" data-view="starbases" onclick="switchBaseView('starbases')">Starbases</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Base Overview -->
|
<!-- Base Overview -->
|
||||||
@ -515,11 +547,11 @@
|
|||||||
<div class="tab-content" id="quests-tab">
|
<div class="tab-content" id="quests-tab">
|
||||||
<div class="quests-container">
|
<div class="quests-container">
|
||||||
<div class="quest-tabs">
|
<div class="quest-tabs">
|
||||||
<button class="quest-tab-btn active" data-type="main">Main Story</button>
|
<button class="quest-tab-btn active" data-type="main" onclick="switchQuestCategory('main')">Main Story</button>
|
||||||
<button class="quest-tab-btn" data-type="daily">Daily</button>
|
<button class="quest-tab-btn" data-type="daily" onclick="switchQuestCategory('daily')">Daily</button>
|
||||||
<button class="quest-tab-btn" data-type="weekly">Weekly</button>
|
<button class="quest-tab-btn" data-type="weekly" onclick="switchQuestCategory('weekly')">Weekly</button>
|
||||||
<button class="quest-tab-btn" data-type="completed">Completed</button>
|
<button class="quest-tab-btn" data-type="completed" onclick="switchQuestCategory('completed')">Completed</button>
|
||||||
<button class="quest-tab-btn" data-type="failed">Failed Quests</button>
|
<button class="quest-tab-btn" data-type="failed" onclick="switchQuestCategory('failed')">Failed Quests</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="daily-countdown" id="dailyCountdown">Daily quests reset in: 00:00:00</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>
|
<div class="weekly-countdown" id="weeklyCountdown">Weekly quests reset in: 0d 00:00</div>
|
||||||
@ -600,10 +632,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="crafting-categories">
|
<div class="crafting-categories">
|
||||||
<button class="crafting-cat-btn active" data-category="weapons">Weapons</button>
|
<button class="crafting-cat-btn active" data-category="weapons" onclick="switchCraftingCategory('weapons')">Weapons</button>
|
||||||
<button class="crafting-cat-btn" data-category="armor">Armor</button>
|
<button class="crafting-cat-btn" data-category="armor" onclick="switchCraftingCategory('armor')">Armor</button>
|
||||||
<button class="crafting-cat-btn" data-category="items">Items</button>
|
<button class="crafting-cat-btn" data-category="items" onclick="switchCraftingCategory('items')">Items</button>
|
||||||
<button class="crafting-cat-btn" data-category="ships">Ships</button>
|
<button class="crafting-cat-btn" data-category="ships" onclick="switchCraftingCategory('ships')">Ships</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="crafting-grid" id="recipeList">
|
<div class="crafting-grid" id="recipeList">
|
||||||
<!-- Recipes will be generated here -->
|
<!-- Recipes will be generated here -->
|
||||||
@ -616,13 +648,13 @@
|
|||||||
<div class="shop-container">
|
<div class="shop-container">
|
||||||
<div class="shop-header">
|
<div class="shop-header">
|
||||||
<div class="shop-categories">
|
<div class="shop-categories">
|
||||||
<button class="shop-cat-btn active" data-category="ships">Ships</button>
|
<button class="shop-cat-btn active" data-category="ships" onclick="switchShopCategory('ships')">Ships</button>
|
||||||
<button class="shop-cat-btn" data-category="weapons">Weapons</button>
|
<button class="shop-cat-btn" data-category="weapons" onclick="switchShopCategory('weapons')">Weapons</button>
|
||||||
<button class="shop-cat-btn" data-category="armors">Armors</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="upgrades">Upgrades</button> -->
|
||||||
<button class="shop-cat-btn" data-category="cosmetics">Cosmetics</button>
|
<button class="shop-cat-btn" data-category="cosmetics" onclick="switchShopCategory('cosmetics')">Cosmetics</button>
|
||||||
<button class="shop-cat-btn" data-category="consumables">Consumables</button>
|
<button class="shop-cat-btn" data-category="consumables" onclick="switchShopCategory('consumables')">Consumables</button>
|
||||||
<button class="shop-cat-btn" data-category="materials">Materials</button>
|
<button class="shop-cat-btn" data-category="materials" onclick="switchShopCategory('materials')">Materials</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="shop-content">
|
<div class="shop-content">
|
||||||
@ -672,12 +704,558 @@
|
|||||||
<script src="js/systems/QuestSystem.js"></script>
|
<script src="js/systems/QuestSystem.js"></script>
|
||||||
<script src="js/systems/ShipSystem.js"></script>
|
<script src="js/systems/ShipSystem.js"></script>
|
||||||
<script src="js/systems/IdleSystem.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/systems/CraftingSystem.js"></script>
|
||||||
<script src="js/data/GameData.js"></script>
|
<script src="js/data/GameData.js"></script>
|
||||||
<script src="js/ui/UIManager.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/GameInitializer.js"></script>
|
||||||
<script src="js/ui/LiveMainMenu.js"></script>
|
<script src="js/ui/LiveMainMenu.js"></script>
|
||||||
<script src="js/main.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 -->
|
<!-- Hidden Console Window -->
|
||||||
<div id="consoleWindow" class="console-window">
|
<div id="consoleWindow" class="console-window">
|
||||||
|
|||||||
@ -15,12 +15,16 @@ class GameInitializer {
|
|||||||
this.socket = null;
|
this.socket = null;
|
||||||
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server
|
this.apiBaseUrl = 'https://api.korvarix.com/api'; // API Server
|
||||||
this.gameServerUrl = 'https://dev.gameserver.galaxystrike.online'; // Game Server for Socket.IO (local dev 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) {
|
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.apiBaseUrl = apiUrl;
|
||||||
this.gameServerUrl = gameUrl;
|
this.gameServerUrl = gameUrl;
|
||||||
|
console.log('[GAME INITIALIZER] New gameServerUrl:', this.gameServerUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeMultiplayer(server, serverData, authToken, currentUser) {
|
initializeMultiplayer(server, serverData, authToken, currentUser) {
|
||||||
@ -33,8 +37,10 @@ class GameInitializer {
|
|||||||
// Initialize Socket.IO connection
|
// Initialize Socket.IO connection
|
||||||
this.initializeSocketConnection();
|
this.initializeSocketConnection();
|
||||||
|
|
||||||
// Initialize game systems with multiplayer support
|
// Set SmartSaveManager to multiplayer mode
|
||||||
this.initializeGameSystems();
|
if (window.smartSaveManager) {
|
||||||
|
window.smartSaveManager.setMultiplayerMode(true, this);
|
||||||
|
}
|
||||||
|
|
||||||
// Update UI for multiplayer mode
|
// Update UI for multiplayer mode
|
||||||
this.updateUIForMultiplayerMode();
|
this.updateUIForMultiplayerMode();
|
||||||
@ -49,6 +55,7 @@ class GameInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('[GAME INITIALIZER] Initializing Socket.IO connection');
|
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
|
// Check if we're in local mode and should use mock socket
|
||||||
if (this.gameServerUrl.includes('localhost') && window.localServerManager && window.localServerManager.localServer) {
|
if (this.gameServerUrl.includes('localhost') && window.localServerManager && window.localServerManager.localServer) {
|
||||||
@ -63,14 +70,21 @@ class GameInitializer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to the game server (different from API server)
|
// FORCE THE URL - Override any undefined issues
|
||||||
this.socket = io(this.gameServerUrl, {
|
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: {
|
auth: {
|
||||||
token: this.authToken,
|
token: this.authToken,
|
||||||
serverId: this.serverData.id
|
serverId: this.serverData.id
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('[GAME INITIALIZER] Socket.IO connection initiated to FORCED URL:', FORCED_URL);
|
||||||
|
|
||||||
// Socket event handlers
|
// Socket event handlers
|
||||||
this.socket.on('connect', () => {
|
this.socket.on('connect', () => {
|
||||||
console.log('[GAME INITIALIZER] Connected to server');
|
console.log('[GAME INITIALIZER] Connected to server');
|
||||||
@ -111,9 +125,69 @@ class GameInitializer {
|
|||||||
console.log('[GAME INITIALIZER] Chat message:', data);
|
console.log('[GAME INITIALIZER] Chat message:', data);
|
||||||
this.onChatMessage(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() {
|
onSocketConnected() {
|
||||||
|
// Expose socket globally for systems that need it
|
||||||
|
if (window.game) {
|
||||||
|
window.game.socket = this.socket;
|
||||||
|
}
|
||||||
|
|
||||||
// Join the server room
|
// Join the server room
|
||||||
this.socket.emit('joinServer', {
|
this.socket.emit('joinServer', {
|
||||||
serverId: this.serverData.id,
|
serverId: this.serverData.id,
|
||||||
@ -121,13 +195,48 @@ class GameInitializer {
|
|||||||
username: this.currentUser.username
|
username: this.currentUser.username
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Authenticate with server to get player data
|
||||||
|
this.authenticateWithServer();
|
||||||
|
|
||||||
// Show connected status
|
// Show connected status
|
||||||
this.showConnectionStatus('Connected', 'success');
|
this.showConnectionStatus('Connected', 'success');
|
||||||
}
|
}
|
||||||
|
|
||||||
onSocketDisconnected() {
|
onSocketDisconnected() {
|
||||||
|
console.log('[GAME INITIALIZER] Socket disconnected - switching to singleplayer mode');
|
||||||
|
|
||||||
// Show disconnected status
|
// Show disconnected status
|
||||||
this.showConnectionStatus('Disconnected', 'error');
|
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) {
|
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) {
|
onForceDisconnect(data) {
|
||||||
// Handle forced disconnection from server
|
// Handle forced disconnection from server
|
||||||
console.warn('[GAME INITIALIZER] Force disconnected by server:', data);
|
console.warn('[GAME INITIALIZER] Force disconnected by server:', data);
|
||||||
@ -211,7 +461,56 @@ class GameInitializer {
|
|||||||
|
|
||||||
// Configure game for multiplayer mode
|
// Configure game for multiplayer mode
|
||||||
console.log('[GAME INITIALIZER] Configuring 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
|
// Game is already set up with save data, just start the game loop
|
||||||
if (window.game.start) {
|
if (window.game.start) {
|
||||||
@ -230,8 +529,24 @@ class GameInitializer {
|
|||||||
updateUIForMultiplayerMode() {
|
updateUIForMultiplayerMode() {
|
||||||
// Update UI elements to show multiplayer mode
|
// Update UI elements to show multiplayer mode
|
||||||
const playerName = document.getElementById('playerName');
|
const playerName = document.getElementById('playerName');
|
||||||
if (playerName && this.currentUser) {
|
const playerTitle = document.getElementById('playerTitle');
|
||||||
playerName.textContent = this.currentUser.username;
|
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
|
// 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 method
|
||||||
cleanup() {
|
cleanup() {
|
||||||
console.log('[GAME INITIALIZER] Cleaning up');
|
console.log('[GAME INITIALIZER] Cleaning up');
|
||||||
|
|
||||||
|
// Reset SmartSaveManager to singleplayer mode
|
||||||
|
if (window.smartSaveManager) {
|
||||||
|
window.smartSaveManager.setMultiplayerMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (this.socket) {
|
if (this.socket) {
|
||||||
this.socket.disconnect();
|
this.socket.disconnect();
|
||||||
this.socket = null;
|
this.socket = null;
|
||||||
@ -353,12 +869,26 @@ class GameInitializer {
|
|||||||
this.serverData = null;
|
this.serverData = null;
|
||||||
this.authToken = null;
|
this.authToken = null;
|
||||||
this.currentUser = null;
|
this.currentUser = null;
|
||||||
|
this.serverPlayerData = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create global instance
|
// Create global instance
|
||||||
window.gameInitializer = new GameInitializer();
|
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
|
// Export for use in other scripts
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
module.exports = GameInitializer;
|
module.exports = GameInitializer;
|
||||||
|
|||||||
325
Client/js/SaveSystemIntegration.js
Normal file
325
Client/js/SaveSystemIntegration.js
Normal 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');
|
||||||
228
Client/js/SmartSaveManager.js
Normal file
228
Client/js/SmartSaveManager.js
Normal 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');
|
||||||
@ -5,7 +5,9 @@
|
|||||||
|
|
||||||
class DebugLogger {
|
class DebugLogger {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.debugEnabled = true; // Always enabled
|
// Completely disable debug logging to prevent console flooding
|
||||||
|
this.debugEnabled = false;
|
||||||
|
|
||||||
this.startTime = performance.now();
|
this.startTime = performance.now();
|
||||||
this.stepTimers = new Map();
|
this.stepTimers = new Map();
|
||||||
this.debugLogs = []; // Store logs in memory
|
this.debugLogs = []; // Store logs in memory
|
||||||
@ -15,10 +17,15 @@ class DebugLogger {
|
|||||||
this.logger = window.logger || null;
|
this.logger = window.logger || null;
|
||||||
|
|
||||||
// Log initialization
|
// Log initialization
|
||||||
this.log('=== DEBUG SESSION STARTED ===');
|
if (this.debugEnabled) {
|
||||||
|
this.log('=== DEBUG SESSION STARTED ===');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async log(message, data = null) {
|
async log(message, data = null) {
|
||||||
|
// Skip logging if debug is disabled
|
||||||
|
if (!this.debugEnabled) return;
|
||||||
|
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
const stackTrace = new Error().stack;
|
const stackTrace = new Error().stack;
|
||||||
|
|
||||||
@ -55,13 +62,13 @@ class DebugLogger {
|
|||||||
this.debugLogs.shift();
|
this.debugLogs.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always log to console
|
// Skip console logging to prevent flooding
|
||||||
console.log(`[DEBUG] ${message}`, data || '');
|
// console.log(`[DEBUG] ${message}`, data || '');
|
||||||
|
|
||||||
// Log performance data to console
|
// Skip performance logging to prevent flooding
|
||||||
if (performanceData.memory) {
|
// if (performanceData.memory) {
|
||||||
console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
|
// console.log(`[PERF] ${performanceData.elapsed} | Memory: ${performanceData.memory.used}/${performanceData.memory.total}`);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Use existing logger if available
|
// Use existing logger if available
|
||||||
if (this.logger) {
|
if (this.logger) {
|
||||||
@ -79,6 +86,9 @@ class DebugLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async startStep(stepName) {
|
async startStep(stepName) {
|
||||||
|
// Skip logging if debug is disabled
|
||||||
|
if (!this.debugEnabled) return;
|
||||||
|
|
||||||
this.stepTimers.set(stepName, performance.now());
|
this.stepTimers.set(stepName, performance.now());
|
||||||
await this.log(`STEP START: ${stepName}`, {
|
await this.log(`STEP START: ${stepName}`, {
|
||||||
type: 'step_start',
|
type: 'step_start',
|
||||||
@ -88,6 +98,9 @@ class DebugLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async endStep(stepName, data = null) {
|
async endStep(stepName, data = null) {
|
||||||
|
// Skip logging if debug is disabled
|
||||||
|
if (!this.debugEnabled) return;
|
||||||
|
|
||||||
const startTime = this.stepTimers.get(stepName);
|
const startTime = this.stepTimers.get(stepName);
|
||||||
const duration = startTime ? (performance.now() - startTime).toFixed(2) : 'N/A';
|
const duration = startTime ? (performance.now() - startTime).toFixed(2) : 'N/A';
|
||||||
|
|
||||||
@ -101,6 +114,9 @@ class DebugLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async logStep(stepName, data = null) {
|
async logStep(stepName, data = null) {
|
||||||
|
// Skip logging if debug is disabled
|
||||||
|
if (!this.debugEnabled) return;
|
||||||
|
|
||||||
await this.log(`STEP: ${stepName}`, {
|
await this.log(`STEP: ${stepName}`, {
|
||||||
type: 'step',
|
type: 'step',
|
||||||
step: stepName,
|
step: stepName,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -95,72 +95,24 @@ class Inventory {
|
|||||||
maxSlots: this.maxSlots
|
maxSlots: this.maxSlots
|
||||||
});
|
});
|
||||||
|
|
||||||
const startingItems = [
|
// In multiplayer mode, starting items should come from server
|
||||||
{
|
if (window.smartSaveManager?.isMultiplayer) {
|
||||||
id: 'starter_blaster_common',
|
console.log('[INVENTORY] Multiplayer mode - starting items will be provided by server');
|
||||||
name: 'Common Blaster',
|
if (debugLogger) debugLogger.logStep('Skipping starting items in multiplayer mode');
|
||||||
type: 'weapon',
|
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
|
||||||
rarity: 'common',
|
finalItemCount: this.items.length,
|
||||||
quantity: 1,
|
itemsAdded: 0
|
||||||
stats: { attack: 5, criticalChance: 0.02 },
|
});
|
||||||
description: 'A reliable basic blaster for new pilots',
|
return;
|
||||||
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
|
|
||||||
}))
|
|
||||||
});
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Equip basic armor
|
// Singleplayer mode - no hardcoded starting items available
|
||||||
const armorItem = this.items.find(item => item.id === 'basic_armor');
|
console.log('[INVENTORY] Singleplayer mode - no hardcoded starting items available');
|
||||||
if (armorItem) {
|
if (debugLogger) debugLogger.logStep('No starting items available in singleplayer mode');
|
||||||
console.log('[INVENTORY] Equipping basic armor');
|
|
||||||
this.equipItem(armorItem.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-stack starting items
|
|
||||||
if (debugLogger) debugLogger.logStep('Auto-stacking starting items');
|
|
||||||
this.autoStackItems();
|
|
||||||
|
|
||||||
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
|
if (debugLogger) debugLogger.endStep('Inventory.addStartingItems', {
|
||||||
finalItemCount: this.items.length,
|
finalItemCount: this.items.length,
|
||||||
itemsAdded: startingItems.length
|
itemsAdded: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -213,12 +213,10 @@ class Logger {
|
|||||||
|
|
||||||
async info(message, data = null) {
|
async info(message, data = null) {
|
||||||
await this.log('info', message, data);
|
await this.log('info', message, data);
|
||||||
console.info(`[INFO] ${message}`, data || '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async debug(message, data = null) {
|
async debug(message, data = null) {
|
||||||
await this.log('debug', message, data);
|
await this.log('debug', message, data);
|
||||||
console.debug(`[DEBUG] ${message}`, data || '');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async gameEvent(eventType, details) {
|
async gameEvent(eventType, details) {
|
||||||
|
|||||||
@ -537,9 +537,9 @@ class Player {
|
|||||||
upgrades: []
|
upgrades: []
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('=== DEBUG: Character Reset ===');
|
// console.log('=== DEBUG: Character Reset ===');
|
||||||
console.log('Player health reset to:', this.attributes.health, '/', this.attributes.maxHealth);
|
// 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('Ship health reset to:', this.ship.health, '/', this.ship.maxHealth);
|
||||||
|
|
||||||
// Reset skills
|
// Reset skills
|
||||||
this.skills = {};
|
this.skills = {};
|
||||||
@ -692,16 +692,43 @@ class Player {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updatePlayTime(deltaTime) {
|
updatePlayTime(deltaTime) {
|
||||||
|
// DISABLED: Reduce console spam for quest debugging
|
||||||
|
/*
|
||||||
console.log('[PLAYER] updatePlayTime called with deltaTime:', deltaTime, 'ms');
|
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');
|
console.log('[PLAYER] Before update - playTime:', this.stats.playTime, 'ms');
|
||||||
|
*/
|
||||||
|
|
||||||
// Use real computer time delta
|
// Use real computer time delta
|
||||||
this.stats.playTime += deltaTime;
|
this.stats.playTime += deltaTime;
|
||||||
|
|
||||||
|
// DISABLED: Reduce console spam for quest debugging
|
||||||
|
/*
|
||||||
console.log('[PLAYER] After update - playTime:', this.stats.playTime, 'ms');
|
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 seconds:', this.stats.playTime / 1000, 'seconds');
|
||||||
console.log('[PLAYER] PlayTime in minutes:', this.stats.playTime / 60000, 'minutes');
|
console.log('[PLAYER] PlayTime in minutes:', this.stats.playTime / 60000, 'minutes');
|
||||||
console.log('[PLAYER] PlayTime in hours:', this.stats.playTime / 3600000, 'hours');
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI updates
|
// UI updates
|
||||||
@ -717,18 +744,25 @@ class Player {
|
|||||||
|
|
||||||
// Update player info
|
// Update player info
|
||||||
const playerNameElement = document.getElementById('playerName');
|
const playerNameElement = document.getElementById('playerName');
|
||||||
|
const playerTitleElement = document.getElementById('playerTitle');
|
||||||
const playerLevelElement = document.getElementById('playerLevel');
|
const playerLevelElement = document.getElementById('playerLevel');
|
||||||
|
|
||||||
if (playerNameElement) {
|
if (playerNameElement) {
|
||||||
playerNameElement.textContent = `${this.info.name} - ${this.info.title}`;
|
playerNameElement.textContent = this.info.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerTitleElement) {
|
||||||
|
playerTitleElement.textContent = ` - ${this.info.title}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerLevelElement) {
|
if (playerLevelElement) {
|
||||||
playerLevelElement.textContent = `Lv. ${this.stats.level}`;
|
playerLevelElement.textContent = `Lv. ${this.stats.level}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update health and energy
|
// Update health and energy only if in multiplayer mode or game is actively running
|
||||||
if (this.game && this.game.systems && this.game.systems.ui) {
|
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
|
|
||||||
|
if (shouldUpdateUI && this.game && this.game.systems && this.game.systems.ui) {
|
||||||
this.game.systems.ui.updateResourceDisplay();
|
this.game.systems.ui.updateResourceDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -765,6 +799,7 @@ class Player {
|
|||||||
if (debugLogger) debugLogger.logStep('Player UI update completed', {
|
if (debugLogger) debugLogger.logStep('Player UI update completed', {
|
||||||
elementsUpdated: {
|
elementsUpdated: {
|
||||||
playerName: !!playerNameElement,
|
playerName: !!playerNameElement,
|
||||||
|
playerTitle: !!playerTitleElement,
|
||||||
playerLevel: !!playerLevelElement,
|
playerLevel: !!playerLevelElement,
|
||||||
totalKills: !!totalKillsElement,
|
totalKills: !!totalKillsElement,
|
||||||
dungeonsCleared: !!dungeonsClearedElement,
|
dungeonsCleared: !!dungeonsClearedElement,
|
||||||
@ -817,9 +852,29 @@ class Player {
|
|||||||
try {
|
try {
|
||||||
if (data.stats) {
|
if (data.stats) {
|
||||||
console.log('[PLAYER] Loading stats:', 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 };
|
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] Level after stats load:', this.stats.level);
|
||||||
|
console.log('[PLAYER] PlayTime after stats load:', this.stats.playTime);
|
||||||
|
|
||||||
if (debugLogger) debugLogger.logStep('Player stats loaded', {
|
if (debugLogger) debugLogger.logStep('Player stats loaded', {
|
||||||
oldLevel: oldStats.level,
|
oldLevel: oldStats.level,
|
||||||
|
|||||||
@ -54,8 +54,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
window.debugLogger.startStep('domLoad');
|
window.debugLogger.startStep('domLoad');
|
||||||
window.debugLogger.logStep('DOM loaded, starting initialization');
|
window.debugLogger.logStep('DOM loaded, starting initialization');
|
||||||
|
|
||||||
// Auto-start local server for singleplayer mode
|
// Auto-start local server for singleplayer mode (DISABLED to prevent auto-start after multiplayer disconnect)
|
||||||
console.log('[MAIN] Checking local server status...');
|
console.log('[MAIN] Skipping local server auto-start to prevent conflicts with multiplayer mode');
|
||||||
|
/*
|
||||||
if (window.localServerManager) {
|
if (window.localServerManager) {
|
||||||
try {
|
try {
|
||||||
const serverResult = await window.localServerManager.autoStartIfSingleplayer();
|
const serverResult = await window.localServerManager.autoStartIfSingleplayer();
|
||||||
@ -78,6 +79,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
} else {
|
} else {
|
||||||
console.warn('[MAIN] LocalServerManager not available');
|
console.warn('[MAIN] LocalServerManager not available');
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// Title bar is already initialized, just log it
|
// Title bar is already initialized, just log it
|
||||||
console.log('[MAIN] DOM loaded - title bar should already be working');
|
console.log('[MAIN] DOM loaded - title bar should already be working');
|
||||||
@ -368,7 +370,7 @@ if (window.performance && window.performance.memory) {
|
|||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (window.game && window.game.isRunning) {
|
if (window.game && window.game.isRunning) {
|
||||||
const stats = window.game.getPerformanceStats();
|
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);
|
console.warn('High memory usage detected:', stats.memory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1309,7 +1309,11 @@ class BaseSystem {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
player.updateUI();
|
// Only update player UI if in multiplayer mode or game is actively running
|
||||||
|
if (this.game.shouldUpdateGUI()) {
|
||||||
|
player.updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
this.updateShipGallery();
|
this.updateShipGallery();
|
||||||
|
|
||||||
// Also update ShipSystem display
|
// Also update ShipSystem display
|
||||||
@ -1592,10 +1596,12 @@ class BaseSystem {
|
|||||||
// Apply benefits
|
// Apply benefits
|
||||||
this.applyStarbaseBenefits(newStarbase);
|
this.applyStarbaseBenefits(newStarbase);
|
||||||
|
|
||||||
// Update UI
|
// Only update UI if in multiplayer mode or game is actively running
|
||||||
economy.updateUI();
|
if (this.game.shouldUpdateGUI()) {
|
||||||
this.updateStarbaseList();
|
economy.updateUI();
|
||||||
this.updateStarbasePurchaseList();
|
this.updateStarbaseList();
|
||||||
|
this.updateStarbasePurchaseList();
|
||||||
|
}
|
||||||
|
|
||||||
this.game.showNotification(`Purchased ${starbaseTemplate.name}!`, 'success', 4000);
|
this.game.showNotification(`Purchased ${starbaseTemplate.name}!`, 'success', 4000);
|
||||||
}
|
}
|
||||||
@ -1650,11 +1656,18 @@ class BaseSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
startMiningProduction(starbase) {
|
startMiningProduction(starbase) {
|
||||||
// Set up passive credit generation
|
// Only start mining if in multiplayer mode or game is actively running
|
||||||
if (!this.miningInterval) {
|
const shouldStartMining = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
|
|
||||||
|
if (shouldStartMining && !this.miningInterval) {
|
||||||
|
// Set up passive credit generation
|
||||||
this.miningInterval = setInterval(() => {
|
this.miningInterval = setInterval(() => {
|
||||||
this.game.systems.economy.addCredits(500, 'mining_outpost');
|
this.game.systems.economy.addCredits(500, 'mining_outpost');
|
||||||
}, 3600000); // 1 hour
|
}, 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,10 +2070,12 @@ showRoomBuildMenu(x, y) {
|
|||||||
console.log('[DEBUG] Player ship updated:', player.ship);
|
console.log('[DEBUG] Player ship updated:', player.ship);
|
||||||
console.log('[DEBUG] Player attributes updated:', player.attributes);
|
console.log('[DEBUG] Player attributes updated:', player.attributes);
|
||||||
|
|
||||||
// Update UI displays
|
// Only update UI displays if in multiplayer mode or game is actively running
|
||||||
player.updateUI();
|
if (this.game.shouldUpdateGUI()) {
|
||||||
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
player.updateUI();
|
||||||
this.game.systems.ship.updateCurrentShipDisplay();
|
if (this.game.systems.ship && this.game.systems.ship.updateCurrentShipDisplay) {
|
||||||
|
this.game.systems.ship.updateCurrentShipDisplay();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -641,7 +641,13 @@ class CraftingSystem extends BaseSystem {
|
|||||||
switchCategory(category) {
|
switchCategory(category) {
|
||||||
this.currentCategory = category;
|
this.currentCategory = category;
|
||||||
this.selectedRecipe = null;
|
this.selectedRecipe = null;
|
||||||
this.updateUI();
|
|
||||||
|
// Update UI only if in multiplayer mode or game is actively running
|
||||||
|
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
|
|
||||||
|
if (shouldUpdateUI) {
|
||||||
|
this.updateUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -12,11 +12,18 @@ class IdleSystem {
|
|||||||
this.lastActiveTime = Date.now();
|
this.lastActiveTime = Date.now();
|
||||||
this.accumulatedTime = 0; // Track time for resource generation
|
this.accumulatedTime = 0; // Track time for resource generation
|
||||||
|
|
||||||
// Idle production rates
|
// Idle production rates (online rates)
|
||||||
this.productionRates = {
|
this.productionRates = {
|
||||||
credits: 10, // credits per second (increased for better gameplay)
|
credits: 0.1, // 1 credit every 10 seconds (0.1 per second)
|
||||||
experience: 1, // experience per second (increased for better progression)
|
experience: 0, // no auto experience - only from dungeons
|
||||||
energy: 0.5 // energy regeneration per second
|
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
|
// Offline rewards
|
||||||
@ -144,6 +151,20 @@ class IdleSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
claimOfflineRewards() {
|
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 &&
|
if (this.offlineRewards.credits === 0 &&
|
||||||
this.offlineRewards.experience === 0 &&
|
this.offlineRewards.experience === 0 &&
|
||||||
this.offlineRewards.items.length === 0) {
|
this.offlineRewards.items.length === 0) {
|
||||||
|
|||||||
383
Client/js/systems/ItemSystem.js
Normal file
383
Client/js/systems/ItemSystem.js
Normal 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;
|
||||||
|
}
|
||||||
@ -13,6 +13,10 @@ class QuestSystem {
|
|||||||
|
|
||||||
this.game = gameEngine;
|
this.game = gameEngine;
|
||||||
|
|
||||||
|
// Server time synchronization
|
||||||
|
this.serverTimeOffset = 0; // Difference between server and client time
|
||||||
|
this.lastServerTimeSync = 0;
|
||||||
|
|
||||||
// Quest types
|
// Quest types
|
||||||
this.questTypes = {
|
this.questTypes = {
|
||||||
main: 'Main Story',
|
main: 'Main Story',
|
||||||
@ -788,14 +792,15 @@ class QuestSystem {
|
|||||||
this.maxProceduralQuests = 3;
|
this.maxProceduralQuests = 3;
|
||||||
this.proceduralQuestRefresh = 30 * 60 * 1000; // 30 minutes
|
this.proceduralQuestRefresh = 30 * 60 * 1000; // 30 minutes
|
||||||
|
|
||||||
// Statistics
|
// Initialize stats
|
||||||
this.stats = {
|
this.stats = {
|
||||||
questsCompleted: 0,
|
questsCompleted: 0,
|
||||||
|
questsFailed: 0,
|
||||||
dailyQuestsCompleted: 0,
|
dailyQuestsCompleted: 0,
|
||||||
weeklyQuestsCompleted: 0,
|
weeklyQuestsCompleted: 0,
|
||||||
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
|
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
|
||||||
lastDailyReset: Date.now(),
|
lastDailyReset: this.getServerTime(),
|
||||||
lastWeeklyReset: Date.now()
|
lastWeeklyReset: this.getServerTime()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Initialize daily quests
|
// 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() {
|
async initialize() {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
@ -1119,7 +1161,7 @@ class QuestSystem {
|
|||||||
|
|
||||||
// Complete quest
|
// Complete quest
|
||||||
quest.status = 'completed';
|
quest.status = 'completed';
|
||||||
quest.completedAt = Date.now();
|
quest.completedAt = this.getServerTime();
|
||||||
this.completedQuests.push(quest);
|
this.completedQuests.push(quest);
|
||||||
|
|
||||||
if (debugLogger) debugLogger.logStep('Quest marked as completed', {
|
if (debugLogger) debugLogger.logStep('Quest marked as completed', {
|
||||||
@ -1131,7 +1173,7 @@ class QuestSystem {
|
|||||||
|
|
||||||
// Save completed daily quests to history
|
// Save completed daily quests to history
|
||||||
if (quest.type === 'daily') {
|
if (quest.type === 'daily') {
|
||||||
const questCopy = { ...quest, completedAt: Date.now() };
|
const questCopy = { ...quest, completedAt: this.getServerTime() };
|
||||||
this.completedDailyQuests.push(questCopy);
|
this.completedDailyQuests.push(questCopy);
|
||||||
|
|
||||||
if (debugLogger) debugLogger.logStep('Daily quest added to history', {
|
if (debugLogger) debugLogger.logStep('Daily quest added to history', {
|
||||||
@ -1143,7 +1185,7 @@ class QuestSystem {
|
|||||||
|
|
||||||
// Save completed weekly quests to history
|
// Save completed weekly quests to history
|
||||||
if (quest.type === 'weekly') {
|
if (quest.type === 'weekly') {
|
||||||
const questCopy = { ...quest, completedAt: Date.now() };
|
const questCopy = { ...quest, completedAt: this.getServerTime() };
|
||||||
this.completedWeeklyQuests.push(questCopy);
|
this.completedWeeklyQuests.push(questCopy);
|
||||||
|
|
||||||
if (debugLogger) debugLogger.logStep('Weekly quest added to history', {
|
if (debugLogger) debugLogger.logStep('Weekly quest added to history', {
|
||||||
@ -1218,22 +1260,6 @@ class QuestSystem {
|
|||||||
giveQuestRewards(quest) {
|
giveQuestRewards(quest) {
|
||||||
const debugLogger = window.debugLogger;
|
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) {
|
if (quest.rewards.credits) {
|
||||||
this.game.systems.economy.addCredits(quest.rewards.credits, 'quest');
|
this.game.systems.economy.addCredits(quest.rewards.credits, 'quest');
|
||||||
this.stats.totalRewardsEarned.credits += quest.rewards.credits;
|
this.stats.totalRewardsEarned.credits += quest.rewards.credits;
|
||||||
@ -1558,7 +1584,7 @@ class QuestSystem {
|
|||||||
this.completedQuests = [];
|
this.completedQuests = [];
|
||||||
this.dailyQuests = [];
|
this.dailyQuests = [];
|
||||||
this.selectedDailyQuests = [];
|
this.selectedDailyQuests = [];
|
||||||
this.lastDailyReset = Date.now();
|
this.lastDailyReset = this.getServerTime();
|
||||||
|
|
||||||
// Reset main quest statuses
|
// Reset main quest statuses
|
||||||
this.mainQuests.forEach(quest => {
|
this.mainQuests.forEach(quest => {
|
||||||
@ -1591,7 +1617,7 @@ class QuestSystem {
|
|||||||
|
|
||||||
checkDailyReset() {
|
checkDailyReset() {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
const now = Date.now();
|
const now = this.getServerTime();
|
||||||
const lastReset = this.lastDailyReset;
|
const lastReset = this.lastDailyReset;
|
||||||
const daysSinceReset = Math.floor((now - lastReset) / (24 * 60 * 60 * 1000));
|
const daysSinceReset = Math.floor((now - lastReset) / (24 * 60 * 60 * 1000));
|
||||||
|
|
||||||
@ -1645,20 +1671,27 @@ class QuestSystem {
|
|||||||
// Update countdown immediately
|
// Update countdown immediately
|
||||||
this.updateDailyCountdown();
|
this.updateDailyCountdown();
|
||||||
|
|
||||||
// Update every second
|
// Only start timer if in multiplayer mode or game is actively running
|
||||||
this.dailyCountdownInterval = setInterval(() => {
|
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
this.updateDailyCountdown();
|
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
console.log('[QUEST SYSTEM] Daily countdown timer started with interval:', this.dailyCountdownInterval);
|
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() {
|
updateDailyCountdown() {
|
||||||
// Always update countdown so it's ready when user switches to daily tab
|
// Always update countdown so it's ready when user switches to daily tab
|
||||||
const now = new Date();
|
const now = this.getServerDate();
|
||||||
const tomorrow = new Date(now);
|
const tomorrow = new Date();
|
||||||
tomorrow.setDate(tomorrow.getDate() + 1);
|
tomorrow.setUTCDate(now.getDate() + 1);
|
||||||
tomorrow.setHours(0, 0, 0, 0); // Set to midnight
|
tomorrow.setUTCHours(0, 0, 0, 0); // Set to midnight UTC
|
||||||
|
|
||||||
const timeUntilReset = tomorrow - now;
|
const timeUntilReset = tomorrow - now;
|
||||||
const hours = Math.floor(timeUntilReset / (1000 * 60 * 60));
|
const hours = Math.floor(timeUntilReset / (1000 * 60 * 60));
|
||||||
@ -1723,11 +1756,11 @@ class QuestSystem {
|
|||||||
|
|
||||||
checkWeeklyReset() {
|
checkWeeklyReset() {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
const now = Date.now();
|
const now = this.getServerTime();
|
||||||
const lastReset = this.lastWeeklyReset || 0;
|
const lastReset = this.lastWeeklyReset || 0;
|
||||||
|
|
||||||
// Calculate if we need to reset based on Saturday midnight
|
// Calculate if we need to reset based on Saturday midnight (server time)
|
||||||
const currentDateTime = new Date();
|
const currentDateTime = this.getServerDate();
|
||||||
const dayOfWeek = currentDateTime.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
const dayOfWeek = currentDateTime.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
||||||
const currentHour = currentDateTime.getHours();
|
const currentHour = currentDateTime.getHours();
|
||||||
const currentMinute = currentDateTime.getMinutes();
|
const currentMinute = currentDateTime.getMinutes();
|
||||||
@ -1805,18 +1838,25 @@ class QuestSystem {
|
|||||||
// Update countdown immediately
|
// Update countdown immediately
|
||||||
this.updateWeeklyCountdown();
|
this.updateWeeklyCountdown();
|
||||||
|
|
||||||
// Update every minute (weekly changes less frequently)
|
// Only start timer if in multiplayer mode or game is actively running
|
||||||
this.weeklyCountdownInterval = setInterval(() => {
|
const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
this.updateWeeklyCountdown();
|
|
||||||
// Check for weekly reset every minute
|
|
||||||
this.checkWeeklyReset();
|
|
||||||
}, 60000); // Update every minute
|
|
||||||
|
|
||||||
console.log('[QUEST SYSTEM] Weekly countdown timer started with interval:', this.weeklyCountdownInterval);
|
if (shouldStartTimer) {
|
||||||
|
// Update every minute (weekly changes less frequently)
|
||||||
|
this.weeklyCountdownInterval = setInterval(() => {
|
||||||
|
this.updateWeeklyCountdown();
|
||||||
|
// Check for weekly reset every minute
|
||||||
|
this.checkWeeklyReset();
|
||||||
|
}, 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() {
|
updateWeeklyCountdown() {
|
||||||
const now = new Date();
|
const now = this.getServerDate();
|
||||||
const dayOfWeek = now.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
const dayOfWeek = now.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
|
||||||
const currentHour = now.getHours();
|
const currentHour = now.getHours();
|
||||||
const currentMinute = now.getMinutes();
|
const currentMinute = now.getMinutes();
|
||||||
@ -1850,19 +1890,19 @@ class QuestSystem {
|
|||||||
|
|
||||||
console.log('[QUEST SYSTEM] Days until Saturday:', daysUntilSaturday);
|
console.log('[QUEST SYSTEM] Days until Saturday:', daysUntilSaturday);
|
||||||
|
|
||||||
// Create the target reset time (Saturday midnight)
|
// Create the target reset time (Saturday midnight UTC)
|
||||||
const nextSaturday = new Date(now);
|
const nextSaturday = new Date();
|
||||||
nextSaturday.setDate(now.getDate() + daysUntilSaturday);
|
nextSaturday.setUTCDate(now.getDate() + daysUntilSaturday);
|
||||||
nextSaturday.setHours(0, 0, 0, 0); // Set to midnight
|
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();
|
let timeUntilReset = nextSaturday.getTime() - now.getTime();
|
||||||
|
|
||||||
// Ensure timeUntilReset is positive (handle edge cases)
|
// Ensure timeUntilReset is positive (handle edge cases)
|
||||||
if (timeUntilReset <= 0) {
|
if (timeUntilReset <= 0) {
|
||||||
console.log('[QUEST SYSTEM] Time until reset is negative or zero, adding 7 days');
|
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();
|
timeUntilReset = nextSaturday.getTime() - now.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2067,8 +2107,58 @@ class QuestSystem {
|
|||||||
return completed.sort((a, b) => (b.completedAt || 0) - (a.completedAt || 0));
|
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
|
// UI updates
|
||||||
updateUI() {
|
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.updateQuestList();
|
||||||
this.updateQuestStats();
|
this.updateQuestStats();
|
||||||
}
|
}
|
||||||
@ -2086,6 +2176,7 @@ class QuestSystem {
|
|||||||
|
|
||||||
const quests = this.getQuestsByType(activeType);
|
const quests = this.getQuestsByType(activeType);
|
||||||
console.log(`[QUEST SYSTEM] Getting quests for type: ${activeType}, found: ${quests.length} quests`);
|
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 = '';
|
questListElement.innerHTML = '';
|
||||||
|
|
||||||
@ -2273,7 +2364,10 @@ class QuestSystem {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.updateUI();
|
// Only update player UI if in multiplayer mode or game is actively running
|
||||||
|
if (this.game.shouldUpdateGUI()) {
|
||||||
|
player.updateUI();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retry failed quest
|
// Retry failed quest
|
||||||
|
|||||||
@ -304,8 +304,12 @@ return true;
|
|||||||
player.stats.skillPoints--;
|
player.stats.skillPoints--;
|
||||||
this.levelUpSkill(category, skillId);
|
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
|
||||||
this.updateUI();
|
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
|
|
||||||
|
if (shouldUpdateUI) {
|
||||||
|
this.updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -341,8 +345,12 @@ return true;
|
|||||||
|
|
||||||
this.applySkillEffects();
|
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
|
||||||
this.updateUI();
|
const shouldUpdateUI = window.smartSaveManager?.isMultiplayer || this.game?.isRunning;
|
||||||
|
|
||||||
|
if (shouldUpdateUI) {
|
||||||
|
this.updateUI();
|
||||||
|
}
|
||||||
|
|
||||||
this.game.showNotification(`${skill.name} unlocked!`, 'success', 4000);
|
this.game.showNotification(`${skill.name} unlocked!`, 'success', 4000);
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -37,8 +37,16 @@ class LiveMainMenu {
|
|||||||
// Check for existing auth token
|
// Check for existing auth token
|
||||||
this.checkExistingAuth();
|
this.checkExistingAuth();
|
||||||
|
|
||||||
// Check for local server and update URLs if needed
|
// DISABLE local server check - always use remote multiplayer server
|
||||||
this.checkForLocalServer();
|
// 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');
|
console.log('[LIVE MAIN MENU] Constructor completed');
|
||||||
}
|
}
|
||||||
@ -435,6 +443,9 @@ class LiveMainMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async refreshServerList() {
|
async refreshServerList() {
|
||||||
|
// Build server list with local server, dev server, and API servers
|
||||||
|
const servers = [];
|
||||||
|
|
||||||
if (!this.authToken) {
|
if (!this.authToken) {
|
||||||
console.error('[LIVE MAIN MENU] No auth token for server list');
|
console.error('[LIVE MAIN MENU] No auth token for server list');
|
||||||
return;
|
return;
|
||||||
@ -447,9 +458,6 @@ class LiveMainMenu {
|
|||||||
try {
|
try {
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
// Build server list with local server, dev server, and API servers
|
|
||||||
const servers = [];
|
|
||||||
|
|
||||||
// Add local server if available
|
// Add local server if available
|
||||||
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
|
if (this.isLocalMode && window.localServerManager && window.localServerManager.localServer && window.localServerManager.localServer.mockRequest) {
|
||||||
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for local server');
|
console.log('[LIVE MAIN MENU] Using SimpleLocalServer mock API for local server');
|
||||||
@ -459,32 +467,8 @@ class LiveMainMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add dev game server
|
// Skip local dev server check to avoid blocking
|
||||||
try {
|
console.log('[LIVE MAIN MENU] Skipping local dev server check to avoid blocking');
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add API servers
|
// Add API servers
|
||||||
console.log('[LIVE MAIN MENU] Fetching server list from:', `${this.apiBaseUrl}/servers`);
|
console.log('[LIVE MAIN MENU] Fetching server list from:', `${this.apiBaseUrl}/servers`);
|
||||||
@ -495,37 +479,35 @@ class LiveMainMenu {
|
|||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (apiResponse.ok) {
|
if (apiResponse.ok) {
|
||||||
const apiData = await apiResponse.json();
|
const apiData = await apiResponse.json();
|
||||||
if (apiData.success && apiData.servers) {
|
if (apiData.success && apiData.servers) {
|
||||||
servers.push(...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) {
|
} catch (error) {
|
||||||
console.error('[LIVE MAIN MENU] Server list error:', error);
|
console.error('[LIVE MAIN MENU] Error fetching server list:', error);
|
||||||
this.servers = [];
|
this.showLoginNotice('Connection error. Please try again.', 'error');
|
||||||
this.renderServerList();
|
|
||||||
|
|
||||||
// Show error message to user
|
|
||||||
this.showLoginNotice(`Network error: ${error.message}`, 'error');
|
|
||||||
} finally {
|
} finally {
|
||||||
// Hide loading state
|
// Hide loading state
|
||||||
if (this.serverLoading) this.serverLoading.classList.add('hidden');
|
if (this.serverLoading) this.serverLoading.classList.add('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store servers
|
||||||
|
this.servers = servers;
|
||||||
|
|
||||||
|
// Render server list
|
||||||
|
this.renderServerList();
|
||||||
}
|
}
|
||||||
|
|
||||||
renderServerList() {
|
renderServerList() {
|
||||||
if (!this.servers) return;
|
|
||||||
|
|
||||||
const filteredServers = this.getFilteredServers();
|
const filteredServers = this.getFilteredServers();
|
||||||
|
|
||||||
// Handle empty state
|
// Handle empty state
|
||||||
@ -553,6 +535,22 @@ class LiveMainMenu {
|
|||||||
this.updateServerItemsSmoothly(currentItems, newItems);
|
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() {
|
removeServerItemsSmoothly() {
|
||||||
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
|
const existingItems = this.serverList?.querySelectorAll('.server-item') || [];
|
||||||
|
|
||||||
@ -1026,6 +1024,13 @@ Status: ${this.selectedServer.status}
|
|||||||
|
|
||||||
launchMultiplayerGame(server, serverData) {
|
launchMultiplayerGame(server, serverData) {
|
||||||
console.log('[LIVE MAIN MENU] Launching multiplayer game on server:', server.name);
|
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
|
// Hide main menu and start game in multiplayer mode
|
||||||
this.hideLoadingScreenAndShowGame();
|
this.hideLoadingScreenAndShowGame();
|
||||||
this.initializeMultiplayerGame(server, serverData);
|
this.initializeMultiplayerGame(server, serverData);
|
||||||
@ -1051,278 +1056,88 @@ Status: ${this.selectedServer.status}
|
|||||||
initializeMultiplayerGame(server, serverData) {
|
initializeMultiplayerGame(server, serverData) {
|
||||||
console.log('[LIVE MAIN MENU] Initializing multiplayer game');
|
console.log('[LIVE MAIN MENU] Initializing multiplayer game');
|
||||||
|
|
||||||
// Check if GameEngine is available, if not create a basic fallback
|
// DELAY GameEngine creation until after multiplayer connection is ready
|
||||||
if (typeof GameEngine === 'undefined') {
|
// First, set up GameInitializer and socket connection
|
||||||
console.warn('[LIVE MAIN MENU] GameEngine class not available, creating fallback');
|
if (!window.gameInitializer) {
|
||||||
|
console.log('[LIVE MAIN MENU] Creating new GameInitializer for multiplayer');
|
||||||
// Create a basic fallback GameEngine class
|
window.gameInitializer = new GameInitializer();
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
console.log('[LIVE MAIN MENU] Fallback GameEngine init() called');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Add simple return to menu functionality
|
|
||||||
window.returnToMainMenu = () => {
|
|
||||||
console.log('[LIVE MAIN MENU] Return to main menu requested');
|
|
||||||
if (window.liveMainMenu) {
|
|
||||||
window.liveMainMenu.showLoginSection();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
getPerformanceStats() {
|
|
||||||
console.log('[LIVE MAIN MENU] Fallback GameEngine getPerformanceStats called');
|
|
||||||
return {
|
|
||||||
gameTime: this.gameTime,
|
|
||||||
isRunning: this.isRunning,
|
|
||||||
fps: 60,
|
|
||||||
memory: 'N/A (fallback mode)'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
// Set up server URLs and connection first
|
||||||
if (!window.game) {
|
window.gameInitializer.updateServerUrls(
|
||||||
console.log('[LIVE MAIN MENU] Creating new GameEngine instance for multiplayer');
|
'https://api.korvarix.com/api',
|
||||||
try {
|
server.url || 'https://dev.gameserver.galaxystrike.online'
|
||||||
window.game = new GameEngine();
|
);
|
||||||
|
|
||||||
// Initialize the game engine
|
// Initialize multiplayer mode (this will handle GameEngine creation after authentication)
|
||||||
window.game.init().then(() => {
|
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
|
||||||
console.log('[LIVE MAIN MENU] GameEngine initialized successfully for multiplayer');
|
|
||||||
|
// Add simple return to menu functionality
|
||||||
// Apply pending save data if available (after GameEngine is ready)
|
window.returnToMainMenu = () => {
|
||||||
if (window.liveMainMenu && window.liveMainMenu.pendingSaveData) {
|
console.log('[LIVE MAIN MENU] Return to main menu requested');
|
||||||
console.log('[LIVE MAIN MENU] Applying pending save data after GameEngine init...');
|
if (window.liveMainMenu) {
|
||||||
|
window.liveMainMenu.showLoginSection();
|
||||||
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);
|
|
||||||
}
|
|
||||||
} 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');
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
// Initialize multiplayer mode through GameInitializer
|
if (serverStatus.isRunning) {
|
||||||
if (window.gameInitializer) {
|
console.log('[LIVE MAIN MENU] Local server detected, switching to local mode');
|
||||||
// Determine the correct game server URL based on server type
|
this.isLocalMode = true;
|
||||||
let gameServerUrl = this.gameServerUrl; // Default to dev server
|
this.apiBaseUrl = `http://localhost:${serverStatus.port}/api`;
|
||||||
|
this.gameServerUrl = `http://localhost:${serverStatus.port}`;
|
||||||
|
|
||||||
if (server.isLocal) {
|
console.log(`[LIVE MAIN MENU] Updated API URL to: ${this.apiBaseUrl}`);
|
||||||
gameServerUrl = this.localGameServerUrl;
|
|
||||||
} else if (server.isDev) {
|
// Update button to show local mode
|
||||||
gameServerUrl = this.gameServerUrl;
|
if (this.createServerBtn) {
|
||||||
} else {
|
this.createServerBtn.innerHTML = '<i class="fas fa-check"></i> Local Server Running';
|
||||||
// Use server address and port for remote servers
|
this.createServerBtn.classList.remove('btn-primary');
|
||||||
gameServerUrl = `http://${server.address}:${server.port}`;
|
this.createServerBtn.classList.add('btn-success');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[LIVE MAIN MENU] Using game server URL:', gameServerUrl);
|
// Auto-login for local mode
|
||||||
window.gameInitializer.updateServerUrls(this.apiBaseUrl, gameServerUrl);
|
this.autoLoginLocalMode();
|
||||||
window.gameInitializer.initializeMultiplayer(server, serverData, this.authToken, this.currentUser);
|
|
||||||
|
} else {
|
||||||
|
console.log('[LIVE MAIN MENU] No local server running');
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.log('[LIVE MAIN MENU] Local server manager not available');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async startLocalServer() {
|
async startLocalServer() {
|
||||||
console.log('[LIVE MAIN MENU] Starting local server...');
|
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 {
|
try {
|
||||||
|
// Check if LocalServerManager is available
|
||||||
if (!window.localServerManager) {
|
if (!window.localServerManager) {
|
||||||
console.error('[LIVE MAIN MENU] LocalServerManager not available');
|
console.error('[LIVE MAIN MENU] LocalServerManager not available');
|
||||||
this.showLoginNotice('Local server manager not available', 'error');
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update button to show loading state
|
// Start the local server
|
||||||
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');
|
|
||||||
|
|
||||||
const result = await window.localServerManager.startServer();
|
const result = await window.localServerManager.startServer();
|
||||||
|
|
||||||
if (result.success) {
|
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
|
// End of LiveMainMenu class
|
||||||
function initializeLiveMainMenu() {
|
|
||||||
console.log('[LIVE MAIN MENU] Initializing LiveMainMenu...');
|
|
||||||
|
|
||||||
// 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
|
// Initialize LiveMainMenu when DOM is ready
|
||||||
if (document.readyState === 'loading') {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// DOM is still loading, wait for DOMContentLoaded
|
if (typeof window !== 'undefined') {
|
||||||
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');
|
|
||||||
window.liveMainMenu = new LiveMainMenu();
|
window.liveMainMenu = new LiveMainMenu();
|
||||||
}
|
}
|
||||||
}, 1000);
|
});
|
||||||
|
|
||||||
// Export for use in other scripts
|
// Export for use in other scripts
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
if (typeof module !== 'undefined' && module.exports) {
|
||||||
|
|||||||
@ -43,16 +43,19 @@ class UIManager {
|
|||||||
const gameInterface = document.getElementById('gameInterface');
|
const gameInterface = document.getElementById('gameInterface');
|
||||||
const navButtons = document.querySelectorAll('.nav-btn');
|
const navButtons = document.querySelectorAll('.nav-btn');
|
||||||
|
|
||||||
if (debugLogger) debugLogger.logStep('DOM Check', {
|
console.log('[UI MANAGER] DOM Check:', {
|
||||||
gameInterfaceExists: !!gameInterface,
|
gameInterfaceExists: !!gameInterface,
|
||||||
gameInterfaceHidden: gameInterface?.classList.contains('hidden'),
|
gameInterfaceHidden: gameInterface?.classList.contains('hidden'),
|
||||||
navButtonsFound: navButtons.length,
|
navButtonsFound: navButtons.length,
|
||||||
documentReady: document.readyState
|
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();
|
this.proceedWithInitialization();
|
||||||
} else {
|
} else {
|
||||||
|
console.log('[UI MANAGER] Waiting for navigation buttons...');
|
||||||
setTimeout(waitForDOM, 100);
|
setTimeout(waitForDOM, 100);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -117,10 +120,6 @@ class UIManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
|
if (debugLogger) debugLogger.endStep('UIManager.setupNavigation', {
|
||||||
navButtonsSetup: navButtons.length,
|
|
||||||
skillCatButtonsSetup: skillCatButtons.length,
|
|
||||||
shopCatButtonsSetup: shopCatButtons.length,
|
|
||||||
questTabButtonsSetup: questTabButtons.length,
|
|
||||||
craftingCatButtonsSetup: craftingCatButtons.length
|
craftingCatButtonsSetup: craftingCatButtons.length
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -140,10 +139,11 @@ class UIManager {
|
|||||||
if (navButtons.length === 0) {
|
if (navButtons.length === 0) {
|
||||||
console.warn('[UIManager] No navigation buttons found!');
|
console.warn('[UIManager] No navigation buttons found!');
|
||||||
if (debugLogger) debugLogger.logStep('No navigation buttons found');
|
if (debugLogger) debugLogger.logStep('No navigation buttons found');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
navButtons.forEach((btn, index) => {
|
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
|
// Check if button already has a listener to prevent duplicates
|
||||||
if (btn.getAttribute('data-has-listener') === 'true') {
|
if (btn.getAttribute('data-has-listener') === 'true') {
|
||||||
console.log(`[UIManager] Button ${btn.dataset.tab} already has listener, skipping`);
|
console.log(`[UIManager] Button ${btn.dataset.tab} already has listener, skipping`);
|
||||||
@ -151,16 +151,30 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
btn.addEventListener('click', (e) => {
|
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;
|
const tab = btn.dataset.tab;
|
||||||
if (tab) {
|
if (tab) {
|
||||||
this.switchTab(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');
|
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
|
// Set up UI update event listener from GameEngine
|
||||||
@ -284,7 +298,7 @@ class UIManager {
|
|||||||
// if (debugLogger) debugLogger.logStep('Setting up return to menu button');
|
// if (debugLogger) debugLogger.logStep('Setting up return to menu button');
|
||||||
returnToMenuBtn.addEventListener('click', () => {
|
returnToMenuBtn.addEventListener('click', () => {
|
||||||
if (debugLogger) debugLogger.log('Return to menu button clicked');
|
if (debugLogger) debugLogger.log('Return to menu button clicked');
|
||||||
this.returnToMainMenu();
|
this.showReturnToMainMenuModal();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Mark as having listener
|
// Mark as having listener
|
||||||
@ -697,43 +711,92 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showReturnToMainMenuModal() {
|
showReturnToMainMenuModal() {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
// Show confirmation modal instead of browser confirm dialog
|
// Show confirmation modal instead of browser confirm dialog
|
||||||
let content = '<div class="confirmation-content">';
|
let content = '<div class="confirmation-content">';
|
||||||
content += '<p>Are you sure you want to return to the main menu?</p>';
|
content += '<p>Are you sure you want to return to the main menu?</p>';
|
||||||
content += '<p><strong>Warning:</strong> Any unsaved progress will be lost.</p>';
|
content += '<p><strong>Warning:</strong> Any unsaved progress will be lost.</p>';
|
||||||
content += '<div class="confirmation-actions">';
|
content += '<div class="confirmation-actions">';
|
||||||
|
|
||||||
// Check if using fallback GameEngine
|
// Check if using fallback GameEngine
|
||||||
if (window.game && window.game.isFallback) {
|
if (window.game && window.game.isFallback) {
|
||||||
content += '<button class="btn btn-primary" onclick="if(window.uiManager) { window.uiManager.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
content += '<button class="btn btn-primary" onclick="if(window.uiManager) { window.uiManager.confirmReturnToMainMenu(); }">Return to Menu</button>';
|
||||||
content += '<button class="btn btn-secondary" onclick="if(window.uiManager) { window.uiManager.closeModal(); }">Cancel</button>';
|
content += '<button class="btn btn-secondary" onclick="if(window.uiManager) { window.uiManager.closeModal(); }">Cancel</button>';
|
||||||
} else {
|
} 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-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 += '<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', {
|
if (debugLogger) debugLogger.endStep('UIManager.returnToMainMenu', {
|
||||||
success: true,
|
success: true,
|
||||||
confirmationShown: true
|
confirmationShown: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
confirmReturnToMainMenu() {
|
async confirmReturnToMainMenu() {
|
||||||
try {
|
try {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
if (debugLogger) debugLogger.startStep('UIManager.confirmReturnToMainMenu', {
|
// Reset multiplayer mode when returning to main menu
|
||||||
gameRunning: this.game ? this.game.isRunning : false
|
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;
|
||||||
|
|
||||||
// Stop the game engine and save
|
// Always stop the game and clear timers regardless of mode
|
||||||
if (this.game && typeof this.game.isRunning === 'boolean') {
|
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');
|
||||||
|
|
||||||
// if (debugLogger) debugLogger.logStep('Stopping game engine and saving');
|
// Show main menu immediately
|
||||||
|
this.showMainMenu();
|
||||||
|
this.closeModal();
|
||||||
|
|
||||||
// Handle async stop properly
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
||||||
|
success: true,
|
||||||
|
multiplayerMode: true,
|
||||||
|
localSaveSkipped: true,
|
||||||
|
mainMenuShown: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle async stop properly for singleplayer mode
|
||||||
this.game.stop().then(() => {
|
this.game.stop().then(() => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@ -747,6 +810,25 @@ class UIManager {
|
|||||||
mainMenuShown: true
|
mainMenuShown: true
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} 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 => {
|
}).catch(error => {
|
||||||
try {
|
try {
|
||||||
@ -765,26 +847,36 @@ class UIManager {
|
|||||||
saveError: true,
|
saveError: true,
|
||||||
mainMenuShown: true
|
mainMenuShown: true
|
||||||
});
|
});
|
||||||
} catch (fallbackError) {
|
} catch (loggerError) {
|
||||||
|
console.error('[UI MANAGER] Debug logger error:', loggerError);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
// Always show main menu regardless of game state
|
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(() => {
|
setTimeout(() => {
|
||||||
this.showMainMenu();
|
this.showMainMenu();
|
||||||
this.closeModal();
|
this.closeModal();
|
||||||
}, 5000); // 5 second delay to ensure full cleanup and menu readiness
|
}, 5000); // 5 second delay to ensure full cleanup and menu readiness
|
||||||
|
|
||||||
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
if (debugLogger) debugLogger.endStep('UIManager.confirmReturnToMainMenu', {
|
||||||
success: true,
|
success: true,
|
||||||
gameStopped: this.game ? !this.game.isRunning : false,
|
gameStopped: this.game ? !this.game.isRunning : false,
|
||||||
mainMenuShown: true
|
mainMenuShown: true
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} 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() {
|
showMainMenu() {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
@ -1005,8 +1097,10 @@ class UIManager {
|
|||||||
gameStateUpdated: true
|
gameStateUpdated: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update specific tab content
|
// Update specific tab content only if in multiplayer mode or game is actively running
|
||||||
this.updateTabContent(tabName);
|
if (this.shouldUpdateUI()) {
|
||||||
|
this.updateTabContent(tabName);
|
||||||
|
}
|
||||||
|
|
||||||
if (debugLogger) debugLogger.endStep('UIManager.switchTab', {
|
if (debugLogger) debugLogger.endStep('UIManager.switchTab', {
|
||||||
success: true,
|
success: true,
|
||||||
@ -1019,6 +1113,10 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateTabContent(tabName) {
|
updateTabContent(tabName) {
|
||||||
|
if (!this.shouldUpdateUI()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (debugLogger) debugLogger.startStep('UIManager.updateTabContent', {
|
if (debugLogger) debugLogger.startStep('UIManager.updateTabContent', {
|
||||||
tabName: tabName,
|
tabName: tabName,
|
||||||
currentTab: this.currentTab
|
currentTab: this.currentTab
|
||||||
@ -1208,8 +1306,14 @@ class UIManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Call economy system update
|
||||||
this.game.systems.economy.updateUI();
|
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', {
|
if (debugLogger) debugLogger.endStep('UIManager.switchShopCategory', {
|
||||||
success: true,
|
success: true,
|
||||||
category: category,
|
category: category,
|
||||||
@ -1229,13 +1333,7 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switchQuestType(type) {
|
updateQuestTabs(type) {
|
||||||
const debugLogger = window.debugLogger;
|
|
||||||
|
|
||||||
if (debugLogger) debugLogger.startStep('UIManager.switchQuestType', {
|
|
||||||
type: type
|
|
||||||
});
|
|
||||||
|
|
||||||
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
|
const questTabButtons = document.querySelectorAll('.quest-tab-btn');
|
||||||
let buttonsUpdated = 0;
|
let buttonsUpdated = 0;
|
||||||
|
|
||||||
@ -1255,7 +1353,13 @@ class UIManager {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
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', {
|
if (debugLogger) debugLogger.endStep('UIManager.switchQuestType', {
|
||||||
success: true,
|
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) {
|
handleUIUpdate(data) {
|
||||||
const debugLogger = window.debugLogger;
|
const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
@ -1447,6 +1573,10 @@ class UIManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateAllUI() {
|
updateAllUI() {
|
||||||
|
if (!this.shouldUpdateUI()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// if (debugLogger) debugLogger.log('Updating all UI elements');
|
// if (debugLogger) debugLogger.log('Updating all UI elements');
|
||||||
|
|
||||||
this.updateResourceDisplay();
|
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() {
|
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 {
|
try {
|
||||||
// Safety checks - return early if systems aren't available
|
// Safety checks - return early if systems aren't available
|
||||||
if (!this.game || !this.game.systems) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.game.systems.player || !this.game.systems.economy) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1501,18 +1653,18 @@ class UIManager {
|
|||||||
|
|
||||||
// Additional safety checks for player properties
|
// Additional safety checks for player properties
|
||||||
if (!player.stats || !player.attributes || !player.ship) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debugLogger) debugLogger.startStep('UIManager.updateResourceDisplay', {
|
// if (debugLogger) debugLogger.startStep('UIManager.updateResourceDisplay', {
|
||||||
gameSystemsAvailable: !!(this.game && this.game.systems),
|
// gameSystemsAvailable: !!(this.game && this.game.systems),
|
||||||
playerSystemAvailable: !!(this.game && this.game.systems && this.game.systems.player),
|
// playerSystemAvailable: !!(this.game && this.game.systems && this.game.systems.player),
|
||||||
economySystemAvailable: !!(this.game && this.game.systems && this.game.systems.economy),
|
// economySystemAvailable: !!(this.game && this.game.systems && this.game.systems.economy),
|
||||||
playerStatsAvailable: !!player.stats,
|
// playerStatsAvailable: !!player.stats,
|
||||||
playerAttributesAvailable: !!player.attributes,
|
// playerAttributesAvailable: !!player.attributes,
|
||||||
playerShipAvailable: !!player.ship
|
// playerShipAvailable: !!player.ship
|
||||||
});
|
// });
|
||||||
|
|
||||||
let elementsUpdated = 0;
|
let elementsUpdated = 0;
|
||||||
let elementsNotFound = 0;
|
let elementsNotFound = 0;
|
||||||
@ -1522,6 +1674,7 @@ class UIManager {
|
|||||||
if (playerLevelElement) {
|
if (playerLevelElement) {
|
||||||
const oldLevel = playerLevelElement.textContent;
|
const oldLevel = playerLevelElement.textContent;
|
||||||
const playerLevel = player.stats.level || 1;
|
const playerLevel = player.stats.level || 1;
|
||||||
|
// console.log('[UI MANAGER] Updating player level:', { oldLevel, newLevel: playerLevel, playerStats: player.stats });
|
||||||
playerLevelElement.textContent = `Lv. ${playerLevel}`;
|
playerLevelElement.textContent = `Lv. ${playerLevel}`;
|
||||||
elementsUpdated++;
|
elementsUpdated++;
|
||||||
|
|
||||||
@ -1532,7 +1685,7 @@ class UIManager {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
elementsNotFound++;
|
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
|
// Update ship level with safety checks
|
||||||
@ -1559,6 +1712,7 @@ class UIManager {
|
|||||||
if (creditsElement) {
|
if (creditsElement) {
|
||||||
const oldCredits = creditsElement.textContent;
|
const oldCredits = creditsElement.textContent;
|
||||||
const creditsAmount = economy.credits || 0;
|
const creditsAmount = economy.credits || 0;
|
||||||
|
// console.log('[UI MANAGER] Credits debug - economy.credits:', economy.credits, 'creditsAmount:', creditsAmount);
|
||||||
creditsElement.textContent = this.game.formatNumber(creditsAmount);
|
creditsElement.textContent = this.game.formatNumber(creditsAmount);
|
||||||
elementsUpdated++;
|
elementsUpdated++;
|
||||||
|
|
||||||
@ -1578,6 +1732,7 @@ class UIManager {
|
|||||||
if (gemsElement) {
|
if (gemsElement) {
|
||||||
const oldGems = gemsElement.textContent;
|
const oldGems = gemsElement.textContent;
|
||||||
const gemsAmount = economy.gems || 0;
|
const gemsAmount = economy.gems || 0;
|
||||||
|
// console.log('[UI MANAGER] Gems debug - economy.gems:', economy.gems, 'gemsAmount:', gemsAmount);
|
||||||
gemsElement.textContent = this.game.formatNumber(gemsAmount);
|
gemsElement.textContent = this.game.formatNumber(gemsAmount);
|
||||||
elementsUpdated++;
|
elementsUpdated++;
|
||||||
|
|
||||||
@ -1596,9 +1751,9 @@ class UIManager {
|
|||||||
const energyElement = document.getElementById('energy');
|
const energyElement = document.getElementById('energy');
|
||||||
if (energyElement) {
|
if (energyElement) {
|
||||||
const oldEnergy = energyElement.textContent;
|
const oldEnergy = energyElement.textContent;
|
||||||
// Ensure we're using the correct energy values, not credits
|
const currentEnergy = player.attributes.currentEnergy || player.attributes.energy || 0;
|
||||||
const currentEnergy = Math.floor(player.attributes.energy || 0);
|
const maxEnergy = player.attributes.maxEnergy || 100;
|
||||||
const maxEnergy = Math.floor(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}`;
|
energyElement.textContent = `${currentEnergy}/${maxEnergy}`;
|
||||||
elementsUpdated++;
|
elementsUpdated++;
|
||||||
|
|
||||||
@ -1615,6 +1770,65 @@ class UIManager {
|
|||||||
if (debugLogger) debugLogger.log('Energy element not found');
|
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', {
|
if (debugLogger) debugLogger.endStep('UIManager.updateResourceDisplay', {
|
||||||
elementsUpdated: elementsUpdated,
|
elementsUpdated: elementsUpdated,
|
||||||
elementsNotFound: elementsNotFound,
|
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() {
|
updateUI() {
|
||||||
const debugLogger = window.debugLogger;
|
// const debugLogger = window.debugLogger;
|
||||||
|
|
||||||
if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
|
// if (debugLogger) debugLogger.startStep('UIManager.updateUI', {
|
||||||
currentTab: this.currentTab,
|
// currentTab: this.currentTab,
|
||||||
modalOpen: this.modalOpen
|
// modalOpen: this.modalOpen
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Update resource display
|
// Update resource display only if in multiplayer mode or game is actively running
|
||||||
if (debugLogger) debugLogger.logStep('Updating resource display');
|
if (this.shouldUpdateUI()) {
|
||||||
this.updateResourceDisplay();
|
// if (debugLogger) debugLogger.logStep('Updating resource display');
|
||||||
|
this.updateResourceDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
// Update tab content
|
// Update tab content only if in multiplayer mode or game is actively running
|
||||||
if (debugLogger) debugLogger.logStep('Updating tab content', {
|
if (this.shouldUpdateUI()) {
|
||||||
currentTab: this.currentTab
|
// if (debugLogger) debugLogger.logStep('Updating tab content', {
|
||||||
});
|
// currentTab: this.currentTab
|
||||||
this.updateTabContent(this.currentTab);
|
// });
|
||||||
|
this.updateTabContent(this.currentTab);
|
||||||
|
}
|
||||||
|
|
||||||
if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
|
// if (debugLogger) debugLogger.endStep('UIManager.updateUI', {
|
||||||
resourceDisplayUpdated: true,
|
// resourceDisplayUpdated: true,
|
||||||
tabContentUpdated: true,
|
// tabContentUpdated: true,
|
||||||
currentTab: this.currentTab
|
// currentTab: this.currentTab
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Menus
|
// Menus
|
||||||
@ -1807,8 +2124,8 @@ class UIManager {
|
|||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset economy
|
// Reset economy - only reset if not in multiplayer mode
|
||||||
if (this.game.systems.economy) {
|
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
||||||
this.game.systems.economy.credits = 1000;
|
this.game.systems.economy.credits = 1000;
|
||||||
this.game.systems.economy.gems = 10;
|
this.game.systems.economy.gems = 10;
|
||||||
}
|
}
|
||||||
@ -1927,8 +2244,8 @@ class UIManager {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear economy data
|
// Clear economy data - only reset if not in multiplayer mode
|
||||||
if (this.game.systems.economy) {
|
if (this.game.systems.economy && !window.smartSaveManager?.isMultiplayer) {
|
||||||
this.game.systems.economy.credits = 1000;
|
this.game.systems.economy.credits = 1000;
|
||||||
this.game.systems.economy.gems = 10;
|
this.game.systems.economy.gems = 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1196,6 +1196,13 @@ body {
|
|||||||
.player-info {
|
.player-info {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player-info > div {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.player-name {
|
.player-name {
|
||||||
@ -1203,6 +1210,18 @@ body {
|
|||||||
color: var(--text-primary);
|
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 {
|
.player-level {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: var(--primary-color);
|
color: var(--primary-color);
|
||||||
@ -1381,6 +1400,20 @@ body {
|
|||||||
gap: 0.5rem;
|
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 {
|
.stat {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user