/** * Galaxy Strike Online - Quest System * Manages hand-crafted and procedural quests */ class QuestSystem { constructor(gameEngine) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.constructor', { gameEngineProvided: !!gameEngine }); this.game = gameEngine; // Server time synchronization this.serverTimeOffset = 0; // Difference between server and client time this.lastServerTimeSync = 0; // Quest types this.questTypes = { main: 'Main Story', daily: 'Daily', weekly: 'Weekly', completed: 'Completed', failed: 'Failed Quests' }; // Quest status this.questStatus = { available: 'available', active: 'active', completed: 'completed', failed: 'failed' }; if (debugLogger) debugLogger.logStep('Quest system configuration initialized', { questTypes: Object.keys(this.questTypes), questStatus: Object.keys(this.questStatus) }); // Main story quests this.mainQuests = [ { id: 'tutorial_complete', name: 'First Steps', description: 'Complete the tutorial dungeon and learn the basics', type: 'main', status: 'available', requirements: { level: 1 }, objectives: [ { id: 'clear_tutorial_dungeon', description: 'Complete the tutorial dungeon', target: 1, current: 0, type: 'tutorial_dungeon' }, { id: 'reach_level_2', description: 'Reach level 2', target: 2, current: 0, type: 'level' } ], rewards: { credits: 500, experience: 100, gems: 5 }, nextQuest: 'first_ship_upgrade' }, { id: 'first_ship_upgrade', name: 'Ship Enhancement', description: 'Upgrade your ship for better performance', type: 'main', status: 'available', requirements: { quest: 'tutorial_complete' }, objectives: [ { id: 'upgrade_weapon', description: 'Upgrade ship weapons', target: 1, current: 0, type: 'upgrade' }, { id: 'upgrade_shield', description: 'Upgrade ship shields', target: 1, current: 0, type: 'upgrade' } ], rewards: { credits: 1000, experience: 200, gems: 10 }, nextQuest: 'join_guild' }, { id: 'join_guild', name: 'Guild Recruitment', description: 'Join a guild and participate in guild activities', type: 'main', status: 'available', requirements: { quest: 'first_ship_upgrade', level: 5 }, objectives: [ { id: 'join_guild', description: 'Join a guild', target: 1, current: 0, type: 'guild' }, { id: 'guild_contribution', description: 'Contribute to guild', target: 100, current: 0, type: 'contribution' } ], rewards: { credits: 2000, experience: 500, gems: 20 }, nextQuest: 'master_commander' }, { id: 'master_commander', name: 'Master Commander', description: 'Become a master commander and lead your fleet to victory', type: 'main', status: 'available', requirements: { quest: 'join_guild', level: 10 }, objectives: [ { id: 'reach_level_10', description: 'Reach level 10', target: 10, current: 0, type: 'level' }, { id: 'clear_10_dungeons', description: 'Clear 10 dungeons', target: 10, current: 0, type: 'dungeon' }, { id: 'max_skill', description: 'Max out one skill', target: 10, current: 0, type: 'skill' } ], rewards: { credits: 5000, experience: 1000, gems: 50, item: 'legendary_weapon' } } ]; // All possible daily quests (20 total) this.allDailyQuests = [ // Easy quests (difficulty: 1) { id: 'daily_dungeon_easy', name: 'Quick Dungeon Run', description: 'Complete any dungeon', type: 'daily', difficulty: 1, status: 'available', objectives: [ { id: 'clear_dungeon', description: 'Clear 1 dungeon', target: 1, current: 0, type: 'dungeon' } ], rewards: { credits: 100, experience: 25, gems: 1 } }, { id: 'daily_combat_easy', name: 'Light Combat', description: 'Defeat a few enemies', type: 'daily', difficulty: 1, status: 'available', objectives: [ { id: 'defeat_enemies', description: 'Defeat 10 enemies', target: 10, current: 0, type: 'combat' } ], rewards: { credits: 80, experience: 20, gems: 1 } }, { id: 'daily_crafting_easy', name: 'Basic Crafting', description: 'Craft some items', type: 'daily', difficulty: 1, status: 'available', objectives: [ { id: 'craft_items', description: 'Craft 2 items', target: 2, current: 0, type: 'crafting' } ], rewards: { credits: 90, experience: 22, gems: 1 } }, { id: 'daily_level_easy', name: 'Level Up', description: 'Gain experience and level up', type: 'daily', difficulty: 1, status: 'available', objectives: [ { id: 'gain_level', description: 'Gain 1 level', target: 1, current: 0, type: 'level' } ], rewards: { credits: 120, experience: 30, gems: 2 } }, { id: 'daily_energy_easy', name: 'Energy Management', description: 'Use energy efficiently', type: 'daily', difficulty: 1, status: 'available', objectives: [ { id: 'use_energy', description: 'Use 50 energy', target: 50, current: 0, type: 'energy' } ], rewards: { credits: 70, experience: 18, gems: 1 } }, // Medium quests (difficulty: 2) { id: 'daily_dungeon_medium', name: 'Dungeon Explorer', description: 'Complete multiple dungeons', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'clear_dungeons', description: 'Clear 3 dungeons', target: 3, current: 0, type: 'dungeon' } ], rewards: { credits: 300, experience: 75, gems: 3 } }, { id: 'daily_combat_medium', name: 'Combat Training', description: 'Defeat enemies in combat', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'defeat_enemies', description: 'Defeat 20 enemies', target: 20, current: 0, type: 'combat' } ], rewards: { credits: 150, experience: 40, gems: 1 } }, { id: 'daily_combat_hard', name: 'Combat Veteran', description: 'Defeat many enemies', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'defeat_enemies', description: 'Defeat 50 enemies', target: 50, current: 0, type: 'combat' } ], rewards: { credits: 250, experience: 60, gems: 3 } }, { id: 'daily_crafting_medium', name: 'Master Crafter', description: 'Craft many items', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'craft_items', description: 'Craft 5 items', target: 5, current: 0, type: 'crafting' } ], rewards: { credits: 280, experience: 70, gems: 3 } }, { id: 'daily_upgrade_medium', name: 'Equipment Upgrade', description: 'Upgrade your equipment', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'upgrade_items', description: 'Upgrade 3 items', target: 3, current: 0, type: 'upgrade' } ], rewards: { credits: 320, experience: 80, gems: 4 } }, { id: 'daily_wealth_medium', name: 'Wealth Accumulator', description: 'Earn credits', type: 'daily', difficulty: 2, status: 'available', objectives: [ { id: 'earn_credits', description: 'Earn 1000 credits', target: 1000, current: 0, type: 'credits' } ], rewards: { credits: 400, experience: 50, gems: 3 } }, // Hard quests (difficulty: 3) { id: 'daily_dungeon_hard', name: 'Dungeon Master', description: 'Complete many dungeons', type: 'daily', difficulty: 3, status: 'available', objectives: [ { id: 'clear_dungeons', description: 'Clear 5 dungeons', target: 5, current: 0, type: 'dungeon' } ], rewards: { credits: 600, experience: 150, gems: 6 } }, { id: 'daily_combat_hard', name: 'Combat Master', description: 'Defeat many powerful enemies', type: 'daily', difficulty: 3, status: 'available', objectives: [ { id: 'defeat_enemies', description: 'Defeat 100 enemies', target: 100, current: 0, type: 'combat' } ], rewards: { credits: 500, experience: 120, gems: 5 } }, { id: 'daily_level_hard', name: 'Power Leveling', description: 'Gain multiple levels', type: 'daily', difficulty: 3, status: 'available', objectives: [ { id: 'gain_levels', description: 'Gain 3 levels', target: 3, current: 0, type: 'level' } ], rewards: { credits: 700, experience: 200, gems: 7 } }, { id: 'daily_boss_hard', name: 'Boss Hunter', description: 'Defeat boss enemies', type: 'daily', difficulty: 3, status: 'available', objectives: [ { id: 'defeat_bosses', description: 'Defeat 3 bosses', target: 3, current: 0, type: 'boss' } ], rewards: { credits: 800, experience: 180, gems: 8 } }, { id: 'daily_collection_hard', name: 'Master Collector', description: 'Collect rare items', type: 'daily', difficulty: 3, status: 'available', objectives: [ { id: 'collect_rare', description: 'Collect 10 rare items', target: 10, current: 0, type: 'collection' } ], rewards: { credits: 650, experience: 140, gems: 6 } }, // Special quests (difficulty: 4) { id: 'daily_speedrun', name: 'Speed Runner', description: 'Complete dungeons quickly', type: 'daily', difficulty: 4, status: 'available', objectives: [ { id: 'fast_dungeon', description: 'Complete 2 dungeons under 5 minutes', target: 2, current: 0, type: 'speedrun' } ], rewards: { credits: 1000, experience: 250, gems: 10 } }, { id: 'daily_perfection', name: 'Perfectionist', description: 'Complete objectives without taking damage', type: 'daily', difficulty: 4, status: 'available', objectives: [ { id: 'perfect_runs', description: '3 perfect dungeon runs', target: 3, current: 0, type: 'perfect' } ], rewards: { credits: 1200, experience: 300, gems: 12 } }, { id: 'daily_multitask', name: 'Multitask Master', description: 'Complete multiple quest types', type: 'daily', difficulty: 4, status: 'available', objectives: [ { id: 'dungeon_task', description: 'Clear 2 dungeons', target: 2, current: 0, type: 'dungeon' }, { id: 'combat_task', description: 'Defeat 30 enemies', target: 30, current: 0, type: 'combat' }, { id: 'craft_task', description: 'Craft 2 items', target: 2, current: 0, type: 'crafting' } ], rewards: { credits: 1500, experience: 400, gems: 15 } }, { id: 'daily_endurance', name: 'Endurance Test', description: 'Complete long activities', type: 'daily', difficulty: 4, status: 'available', objectives: [ { id: 'long_dungeon', description: 'Complete 1 dungeon without healing', target: 1, current: 0, type: 'endurance' } ], rewards: { credits: 1100, experience: 280, gems: 11 } }, { id: 'daily_legendary', name: 'Legendary Challenge', description: 'Complete legendary difficulty content', type: 'daily', difficulty: 4, status: 'available', objectives: [ { id: 'legendary_content', description: 'Complete 1 legendary dungeon', target: 1, current: 0, type: 'legendary' } ], rewards: { credits: 2000, experience: 500, gems: 20, item: 'rare_material' } } ]; // Weekly quests (25 total quests with varied objectives) this.allWeeklyQuests = [ // Combat-focused weekly quests { id: 'weekly_combat_basic', name: 'Weekly Combat Duty', description: 'Complete combat objectives throughout the week', type: 'weekly', difficulty: 1, status: 'available', objectives: [ { id: 'defeat_enemies', description: 'Defeat 100 enemies', target: 100, current: 0, type: 'combat' } ], rewards: { credits: 800, experience: 200, gems: 8 } }, { id: 'weekly_combat_elite', name: 'Elite Hunter Weekly', description: 'Hunt down elite enemies', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'defeat_elites', description: 'Defeat 25 elite enemies', target: 25, current: 0, type: 'elite_combat' } ], rewards: { credits: 1500, experience: 400, gems: 15 } }, { id: 'weekly_boss_hunter', name: 'Boss Hunter Weekly', description: 'Defeat powerful boss enemies', type: 'weekly', difficulty: 4, status: 'available', objectives: [ { id: 'defeat_bosses', description: 'Defeat 10 bosses', target: 10, current: 0, type: 'boss' } ], rewards: { credits: 2500, experience: 600, gems: 25, item: 'boss_material' } }, // Dungeon-focused weekly quests { id: 'weekly_dungeon_explorer', name: 'Weekly Dungeon Explorer', description: 'Explore various dungeons', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'clear_dungeons', description: 'Clear 15 dungeons', target: 15, current: 0, type: 'dungeon' } ], rewards: { credits: 1200, experience: 300, gems: 12 } }, { id: 'weekly_dungeon_master', name: 'Weekly Dungeon Master', description: 'Master difficult dungeons', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'clear_hard_dungeons', description: 'Clear 10 hard dungeons', target: 10, current: 0, type: 'hard_dungeon' } ], rewards: { credits: 2000, experience: 500, gems: 20 } }, { id: 'weekly_dungeon_extreme', name: 'Extreme Dungeon Challenge', description: 'Conquer extreme difficulty dungeons', type: 'weekly', difficulty: 4, status: 'available', objectives: [ { id: 'clear_extreme_dungeons', description: 'Clear 5 extreme dungeons', target: 5, current: 0, type: 'extreme_dungeon' } ], rewards: { credits: 3500, experience: 800, gems: 35, item: 'extreme_material' } }, // Crafting and upgrade weekly quests { id: 'weekly_crafting_basic', name: 'Weekly Crafting Session', description: 'Craft items throughout the week', type: 'weekly', difficulty: 1, status: 'available', objectives: [ { id: 'craft_items', description: 'Craft 20 items', target: 20, current: 0, type: 'crafting' } ], rewards: { credits: 600, experience: 150, gems: 6 } }, { id: 'weekly_crafting_master', name: 'Master Crafter Weekly', description: 'Craft advanced items', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'craft_advanced', description: 'Craft 10 advanced items', target: 10, current: 0, type: 'advanced_crafting' } ], rewards: { credits: 1800, experience: 450, gems: 18 } }, { id: 'weekly_upgrade_specialist', name: 'Weekly Upgrade Specialist', description: 'Upgrade equipment and systems', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'upgrade_items', description: 'Upgrade 15 items', target: 15, current: 0, type: 'upgrade' } ], rewards: { credits: 1400, experience: 350, gems: 14 } }, // Progression weekly quests { id: 'weekly_level_up', name: 'Weekly Level Up Challenge', description: 'Gain levels throughout the week', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'gain_levels', description: 'Gain 5 levels', target: 5, current: 0, type: 'level' } ], rewards: { credits: 1000, experience: 250, gems: 10 } }, { id: 'weekly_skill_master', name: 'Weekly Skill Mastery', description: 'Improve your skills', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'improve_skills', description: 'Gain 20 skill points', target: 20, current: 0, type: 'skill' } ], rewards: { credits: 1600, experience: 400, gems: 16 } }, // Resource and wealth weekly quests { id: 'weekly_wealth_collector', name: 'Weekly Wealth Collector', description: 'Accumulate wealth', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'earn_credits', description: 'Earn 5000 credits', target: 5000, current: 0, type: 'credits' } ], rewards: { credits: 2000, experience: 300, gems: 12 } }, { id: 'weekly_resource_gatherer', name: 'Weekly Resource Gathering', description: 'Collect valuable resources', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'collect_resources', description: 'Collect 500 resources', target: 500, current: 0, type: 'collection' } ], rewards: { credits: 1200, experience: 320, gems: 13 } }, // Special activity weekly quests { id: 'weekly_energy_management', name: 'Weekly Energy Management', description: 'Use energy efficiently', type: 'weekly', difficulty: 1, status: 'available', objectives: [ { id: 'use_energy', description: 'Use 500 energy', target: 500, current: 0, type: 'energy' } ], rewards: { credits: 800, experience: 180, gems: 8 } }, { id: 'weekly_speed_demon', name: 'Weekly Speed Demon', description: 'Complete activities quickly', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'speed_runs', description: 'Complete 10 speed runs', target: 10, current: 0, type: 'speedrun' } ], rewards: { credits: 2200, experience: 550, gems: 22 } }, { id: 'weekly_perfectionist', name: 'Weekly Perfectionist', description: 'Complete flawless runs', type: 'weekly', difficulty: 4, status: 'available', objectives: [ { id: 'perfect_runs', description: 'Complete 8 perfect runs', target: 8, current: 0, type: 'perfect' } ], rewards: { credits: 3000, experience: 700, gems: 30, item: 'perfection_material' } }, // Multi-objective weekly quests { id: 'weekly_all_rounder', name: 'Weekly All-Rounder', description: 'Complete various activities', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'dungeon_task', description: 'Clear 8 dungeons', target: 8, current: 0, type: 'dungeon' }, { id: 'combat_task', description: 'Defeat 50 enemies', target: 50, current: 0, type: 'combat' }, { id: 'craft_task', description: 'Craft 5 items', target: 5, current: 0, type: 'crafting' } ], rewards: { credits: 2500, experience: 600, gems: 25 } }, { id: 'weekly_specialist', name: 'Weekly Specialist', description: 'Focus on specialized activities', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'special_dungeons', description: 'Clear 5 themed dungeons', target: 5, current: 0, type: 'themed_dungeon' }, { id: 'special_crafting', description: 'Craft 8 themed items', target: 8, current: 0, type: 'themed_crafting' } ], rewards: { credits: 2300, experience: 580, gems: 23 } }, // Exploration and discovery weekly quests { id: 'weekly_explorer', name: 'Weekly Explorer', description: 'Explore new areas and content', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'explore_areas', description: 'Explore 20 new areas', target: 20, current: 0, type: 'exploration' } ], rewards: { credits: 1300, experience: 340, gems: 13 } }, { id: 'weekly_discovery', name: 'Weekly Discovery', description: 'Discover hidden secrets', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'discover_secrets', description: 'Discover 15 secrets', target: 15, current: 0, type: 'discovery' } ], rewards: { credits: 1900, experience: 480, gems: 19 } }, // Endurance and challenge weekly quests { id: 'weekly_endurance', name: 'Weekly Endurance Test', description: 'Complete long-form challenges', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'endurance_runs', description: 'Complete 5 endurance runs', target: 5, current: 0, type: 'endurance' } ], rewards: { credits: 2100, experience: 530, gems: 21 } }, { id: 'weekly_survivor', name: 'Weekly Survivor', description: 'Survive challenging conditions', type: 'weekly', difficulty: 4, status: 'available', objectives: [ { id: 'survival_runs', description: 'Complete 3 survival runs', target: 3, current: 0, type: 'survival' } ], rewards: { credits: 3200, experience: 750, gems: 32, item: 'survival_material' } }, // Social and community weekly quests { id: 'weekly_helper', name: 'Weekly Helper', description: 'Assist other players', type: 'weekly', difficulty: 2, status: 'available', objectives: [ { id: 'assist_players', description: 'Assist 10 players', target: 10, current: 0, type: 'assist' } ], rewards: { credits: 1100, experience: 280, gems: 11 } }, { id: 'weekly_leader', name: 'Weekly Leader', description: 'Lead group activities', type: 'weekly', difficulty: 3, status: 'available', objectives: [ { id: 'lead_activities', description: 'Lead 5 group activities', target: 5, current: 0, type: 'leadership' } ], rewards: { credits: 1700, experience: 430, gems: 17 } }, // Legendary weekly quests { id: 'weekly_legendary', name: 'Weekly Legendary Challenge', description: 'Complete legendary difficulty content', type: 'weekly', difficulty: 5, status: 'available', objectives: [ { id: 'legendary_content', description: 'Complete 3 legendary dungeons', target: 3, current: 0, type: 'legendary' } ], rewards: { credits: 5000, experience: 1200, gems: 50, item: 'legendary_material' } }, { id: 'weekly_mythic', name: 'Weekly Mythic Trial', description: 'Face mythic level challenges', type: 'weekly', difficulty: 5, status: 'available', objectives: [ { id: 'mythic_trials', description: 'Complete 2 mythic trials', target: 2, current: 0, type: 'mythic' } ], rewards: { credits: 6000, experience: 1500, gems: 60, item: 'mythic_material' } } ]; // Currently active daily quests (3 random from allDailyQuests) this.dailyQuests = []; this.selectedDailyQuests = []; // Currently active weekly quests (5 random from allWeeklyQuests) this.weeklyQuests = []; this.selectedWeeklyQuests = []; // Current active quests this.activeQuests = []; this.completedQuests = []; this.failedQuests = []; this.completedDailyQuests = []; // History of completed daily quests this.completedWeeklyQuests = []; // History of completed weekly quests // Initialize daily quests with safety check try { if (this.allDailyQuests && Array.isArray(this.allDailyQuests)) { console.log('[QUEST SYSTEM] Initializing daily quests...'); this.randomizeDailyQuests(); } else { console.warn('[QUEST SYSTEM] allDailyQuests not properly initialized, skipping daily quest initialization'); this.dailyQuests = []; this.selectedDailyQuests = []; } } catch (error) { console.error('[QUEST SYSTEM] Error initializing daily quests:', error); // Fallback to empty arrays to prevent crash this.dailyQuests = []; this.selectedDailyQuests = []; this.activeQuests = []; } // Initialize weekly quests with safety check try { if (this.allWeeklyQuests && Array.isArray(this.allWeeklyQuests)) { console.log('[QUEST SYSTEM] Initializing weekly quests...'); this.randomizeWeeklyQuests(); } else { console.warn('[QUEST SYSTEM] allWeeklyQuests not properly initialized, skipping weekly quest initialization'); this.weeklyQuests = []; this.selectedWeeklyQuests = []; } } catch (error) { console.error('[QUEST SYSTEM] Error initializing weekly quests:', error); // Fallback to empty arrays to prevent crash this.weeklyQuests = []; this.selectedWeeklyQuests = []; this.activeQuests = []; } // Procedural quest templates this.proceduralTemplates = { bounty: { name: 'Bounty Hunt', description: 'Hunt down dangerous targets in the galaxy', objectives: [ { id: 'defeat_targets', description: 'Defeat {target} targets', target: 5, current: 0, type: 'combat' } ], rewards: { credits: 300, experience: 75 } }, exploration: { name: 'Exploration Mission', description: 'Explore uncharted regions of space', objectives: [ { id: 'explore_areas', description: 'Explore {target} areas', target: 3, current: 0, type: 'exploration' } ], rewards: { credits: 250, experience: 60 } }, collection: { name: 'Resource Collection', description: 'Collect valuable resources', objectives: [ { id: 'collect_resources', description: 'Collect {target} resources', target: 100, current: 0, type: 'collection' } ], rewards: { credits: 200, experience: 50 } }, escort: { name: 'Escort Mission', description: 'Escort valuable cargo through dangerous space', objectives: [ { id: 'escort_complete', description: 'Complete escort mission', target: 1, current: 0, type: 'escort' } ], rewards: { credits: 400, experience: 100 } } }; // Quest generation settings this.maxProceduralQuests = 3; this.proceduralQuestRefresh = 30 * 60 * 1000; // 30 minutes // Initialize stats this.stats = { questsCompleted: 0, questsFailed: 0, dailyQuestsCompleted: 0, weeklyQuestsCompleted: 0, totalRewardsEarned: { credits: 0, experience: 0, gems: 0 }, lastDailyReset: this.getServerTime(), lastWeeklyReset: this.getServerTime() }; // Initialize daily quests this.randomizeDailyQuests(); // Initialize weekly quests this.randomizeWeeklyQuests(); if (debugLogger) debugLogger.endStep('QuestSystem.constructor', { mainQuestsCount: this.mainQuests.length, allDailyQuestsCount: this.allDailyQuests.length, allWeeklyQuestsCount: this.allWeeklyQuests.length, maxProceduralQuests: this.maxProceduralQuests, proceduralQuestRefresh: this.proceduralQuestRefresh, initialStats: this.stats, dailyQuestsInitialized: this.dailyQuests.length, weeklyQuestsInitialized: this.weeklyQuests.length }); } // Server time synchronization methods getServerTime() { // In multiplayer mode, use UTC time as server time if (window.smartSaveManager?.isMultiplayer) { // Get current UTC timestamp const utcTime = Date.now(); console.log('[QUEST SYSTEM] Using UTC time as server time:', utcTime); console.log('[QUEST SYSTEM] Local time:', Date.now()); return utcTime; } // Fallback to client time in singleplayer return Date.now(); } getServerDate() { // Create a date that displays in UTC const timestamp = this.getServerTime(); const utcDate = new Date(timestamp); // Force UTC display by using UTC methods return { getTime: () => timestamp, getDay: () => utcDate.getUTCDay(), getHours: () => utcDate.getUTCHours(), getMinutes: () => utcDate.getUTCMinutes(), getSeconds: () => utcDate.getUTCSeconds(), getDate: () => utcDate.getUTCDate(), getFullYear: () => utcDate.getUTCFullYear(), getMonth: () => utcDate.getUTCMonth(), toString: () => utcDate.toUTCString(), valueOf: () => timestamp }; } async initialize() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.initialize', { mainQuestsCount: this.mainQuests.length, activeQuestsCount: this.activeQuests.length, dailyQuestsCount: this.dailyQuests.length }); // Initialize main quests if (debugLogger) debugLogger.logStep('Initializing main quests'); this.initializeMainQuests(); // Check for daily reset if (debugLogger) debugLogger.logStep('Checking for daily reset'); this.checkDailyReset(); // Check for weekly reset if (debugLogger) debugLogger.logStep('Checking for weekly reset'); this.checkWeeklyReset(); // Start daily countdown timer if (debugLogger) debugLogger.logStep('Starting daily countdown timer'); this.startDailyCountdown(); // Start weekly countdown timer if (debugLogger) debugLogger.logStep('Starting weekly countdown timer'); this.startWeeklyCountdown(); // Update UI this.updateQuestList(); if (debugLogger) debugLogger.endStep('QuestSystem.initialize', { mainQuestsInitialized: true, dailyResetChecked: true, weeklyResetChecked: true, countdownStarted: true, weeklyQuestsInitialized: true, uiUpdated: true }); } initializeMainQuests() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.initializeMainQuests', { mainQuestsCount: this.mainQuests.length }); // Set all quests to locked initially, then unlock based on requirements this.mainQuests.forEach(quest => { quest.status = 'locked'; }); if (debugLogger) debugLogger.logStep('All main quests set to locked status'); // Unlock first quest if (this.mainQuests.length > 0) { const firstQuest = this.mainQuests[0]; firstQuest.status = 'available'; if (debugLogger) debugLogger.logStep('First quest unlocked', { questId: firstQuest.id, questName: firstQuest.name }); } // Check quest availability based on requirements if (debugLogger) debugLogger.logStep('Checking quest availability based on requirements'); this.checkQuestAvailability(); if (debugLogger) debugLogger.endStep('QuestSystem.initializeMainQuests', { questsProcessed: this.mainQuests.length, availableQuests: this.mainQuests.filter(q => q.status === 'available').length, lockedQuests: this.mainQuests.filter(q => q.status === 'locked').length }); } checkQuestAvailability() { const debugLogger = window.debugLogger; const player = this.game.systems.player; if (debugLogger) debugLogger.startStep('QuestSystem.checkQuestAvailability', { playerLevel: player.stats.level, mainQuestsCount: this.mainQuests.length }); const availabilityChanges = []; this.mainQuests.forEach(quest => { const oldStatus = quest.status; const requirementsMet = this.checkQuestRequirements(quest); if (quest.status === 'locked' && requirementsMet) { quest.status = 'available'; availabilityChanges.push({ questId: quest.id, questName: quest.name, oldStatus: oldStatus, newStatus: 'available', reason: 'Requirements met' }); this.game.showNotification(`New quest available: ${quest.name}`, 'info', 5000); } else if (quest.status === 'available' && !requirementsMet) { // Hide quests that were available but no longer meet requirements quest.status = 'locked'; availabilityChanges.push({ questId: quest.id, questName: quest.name, oldStatus: oldStatus, newStatus: 'locked', reason: 'Requirements no longer met' }); } }); if (debugLogger) debugLogger.endStep('QuestSystem.checkQuestAvailability', { availabilityChanges: availabilityChanges, questsProcessed: this.mainQuests.length, availableQuests: this.mainQuests.filter(q => q.status === 'available').length, lockedQuests: this.mainQuests.filter(q => q.status === 'locked').length }); } // Quest management startQuest(questId) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.startQuest', { questId: questId, currentActiveQuests: this.activeQuests.length }); const quest = this.findQuest(questId); if (!quest) { console.log('Quest not found:', questId); if (debugLogger) debugLogger.endStep('QuestSystem.startQuest', { success: false, reason: 'Quest not found', questId: questId }); return false; } console.log('Attempting to start quest:', questId, 'status:', quest.status); if (debugLogger) debugLogger.logStep('Quest found', { questId: quest.id, questName: quest.name, questType: quest.type, currentStatus: quest.status, requirements: quest.requirements }); if (quest.status !== 'available') { console.log('Quest not available, status:', quest.status); this.game.showNotification('Quest is not available', 'error', 3000); if (debugLogger) debugLogger.endStep('QuestSystem.startQuest', { success: false, reason: 'Quest not available', questId: questId, questName: quest.name, currentStatus: quest.status }); return false; } // Check requirements const requirementsMet = this.checkQuestRequirements(quest); console.log('Requirements met:', requirementsMet, 'for quest:', questId); if (debugLogger) debugLogger.logStep('Requirements check', { requirements: quest.requirements, requirementsMet: requirementsMet }); if (!requirementsMet) { this.game.showNotification('Requirements not met', 'error', 3000); if (debugLogger) debugLogger.endStep('QuestSystem.startQuest', { success: false, reason: 'Requirements not met', questId: questId, questName: quest.name, requirements: quest.requirements }); return false; } console.log('Before status change - quest status:', quest.status); quest.status = 'active'; console.log('After status change - quest status:', quest.status); // Also update the quest in the main quests array to ensure consistency const mainQuest = this.mainQuests.find(q => q.id === questId); if (mainQuest) { mainQuest.status = 'active'; console.log('Updated mainQuest status to:', mainQuest.status); if (debugLogger) debugLogger.logStep('Main quest status updated', { questId: mainQuest.id, newStatus: mainQuest.status }); } this.activeQuests.push(quest); // Check initial progress for existing player stats if (debugLogger) debugLogger.logStep('Checking initial quest progress'); this.checkInitialQuestProgress(quest); // Update the UI to reflect the status change this.updateQuestList(); this.game.showNotification(`Quest started: ${quest.name}`, 'success', 3000); if (debugLogger) debugLogger.endStep('QuestSystem.startQuest', { success: true, questId: questId, questName: quest.name, questType: quest.type, objectives: quest.objectives.map(obj => ({ id: obj.id, description: obj.description, target: obj.target, current: obj.current })), activeQuestsCount: this.activeQuests.length }); return true; } completeQuest(questId) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.completeQuest', { questId: questId, currentActiveQuests: this.activeQuests.length, completedQuestsCount: this.completedQuests.length }); const quest = this.findQuest(questId); if (!quest) { if (debugLogger) debugLogger.endStep('QuestSystem.completeQuest', { success: false, reason: 'Quest not found', questId: questId }); return false; } if (debugLogger) debugLogger.logStep('Quest found for completion', { questId: quest.id, questName: quest.name, questType: quest.type, currentStatus: quest.status, objectives: quest.objectives.map(obj => ({ id: obj.id, description: obj.description, target: obj.target, current: obj.current, completed: obj.current >= obj.target })) }); if (quest.status !== 'active') { this.game.showNotification('Quest is not active', 'error', 3000); if (debugLogger) debugLogger.endStep('QuestSystem.completeQuest', { success: false, reason: 'Quest not active', questId: questId, questName: quest.name, currentStatus: quest.status }); return false; } // Check if all objectives are completed const allObjectivesComplete = quest.objectives.every(obj => obj.current >= obj.target); if (!allObjectivesComplete) { this.game.showNotification('Not all objectives completed', 'warning', 3000); if (debugLogger) debugLogger.endStep('QuestSystem.completeQuest', { success: false, reason: 'Not all objectives completed', questId: questId, questName: quest.name, objectives: quest.objectives.map(obj => ({ id: obj.id, current: obj.current, target: obj.target, completed: obj.current >= obj.target })) }); return false; } // Complete quest quest.status = 'completed'; quest.completedAt = this.getServerTime(); this.completedQuests.push(quest); if (debugLogger) debugLogger.logStep('Quest marked as completed', { questId: quest.id, questName: quest.name, completedAt: quest.completedAt, rewards: quest.rewards }); // Save completed daily quests to history if (quest.type === 'daily') { const questCopy = { ...quest, completedAt: this.getServerTime() }; this.completedDailyQuests.push(questCopy); if (debugLogger) debugLogger.logStep('Daily quest added to history', { questId: quest.id, questName: quest.name, completedDailyQuestsCount: this.completedDailyQuests.length }); } // Save completed weekly quests to history if (quest.type === 'weekly') { const questCopy = { ...quest, completedAt: this.getServerTime() }; this.completedWeeklyQuests.push(questCopy); if (debugLogger) debugLogger.logStep('Weekly quest added to history', { questId: quest.id, questName: quest.name, completedWeeklyQuestsCount: this.completedWeeklyQuests.length }); } // Remove from active quests const activeIndex = this.activeQuests.findIndex(q => q.id === questId); if (activeIndex !== -1) { this.activeQuests.splice(activeIndex, 1); if (debugLogger) debugLogger.logStep('Quest removed from active list', { questId: questId, removedIndex: activeIndex, remainingActiveQuests: this.activeQuests.length }); } // Give rewards if (debugLogger) debugLogger.logStep('Giving quest rewards'); this.giveQuestRewards(quest); // Update statistics const oldStats = { ...this.stats }; this.stats.questsCompleted++; if (quest.type === 'daily') { this.stats.dailyQuestsCompleted++; } if (quest.type === 'weekly') { this.stats.weeklyQuestsCompleted++; } if (debugLogger) debugLogger.logStep('Quest statistics updated', { oldStats: oldStats, newStats: this.stats, questsCompletedIncrement: this.stats.questsCompleted - oldStats.questsCompleted, dailyQuestsCompletedIncrement: this.stats.dailyQuestsCompleted - oldStats.dailyQuestsCompleted, weeklyQuestsCompletedIncrement: this.stats.weeklyQuestsCompleted - oldStats.weeklyQuestsCompleted }); // Unlock next quest if it's a main quest if (quest.nextQuest) { if (debugLogger) debugLogger.logStep('Unlocking next quest', { nextQuestId: quest.nextQuest }); this.unlockNextQuest(quest.nextQuest); } // Check for other quests that might now be available if (debugLogger) debugLogger.logStep('Checking for newly available quests'); this.checkQuestAvailability(); this.game.showNotification(`Quest completed: ${quest.name}!`, 'success', 5000); if (debugLogger) debugLogger.endStep('QuestSystem.completeQuest', { success: true, questId: questId, questName: quest.name, questType: quest.type, rewardsGiven: quest.rewards, nextQuestUnlocked: quest.nextQuest || null, finalActiveQuestsCount: this.activeQuests.length, completedQuestsCount: this.completedQuests.length }); return true; } giveQuestRewards(quest) { const debugLogger = window.debugLogger; if (quest.rewards.credits) { this.game.systems.economy.addCredits(quest.rewards.credits, 'quest'); this.stats.totalRewardsEarned.credits += quest.rewards.credits; rewardsGiven.credits = quest.rewards.credits; if (debugLogger) debugLogger.logStep('Credits reward given', { amount: quest.rewards.credits, oldCredits: oldPlayerStats.credits, newCredits: this.game.systems.economy.credits }); } if (quest.rewards.experience) { this.game.systems.player.addExperience(quest.rewards.experience); this.stats.totalRewardsEarned.experience += quest.rewards.experience; rewardsGiven.experience = quest.rewards.experience; if (debugLogger) debugLogger.logStep('Experience reward given', { amount: quest.rewards.experience, oldExperience: oldPlayerStats.experience, newExperience: this.game.systems.player.stats.experience, oldLevel: oldPlayerStats.level, newLevel: this.game.systems.player.stats.level, leveledUp: this.game.systems.player.stats.level > oldPlayerStats.level }); } if (quest.rewards.gems) { this.game.systems.economy.addGems(quest.rewards.gems, 'quest'); this.stats.totalRewardsEarned.gems += quest.rewards.gems; rewardsGiven.gems = quest.rewards.gems; if (debugLogger) debugLogger.logStep('Gems reward given', { amount: quest.rewards.gems, oldGems: oldPlayerStats.gems, newGems: this.game.systems.economy.gems }); } if (quest.rewards.item) { const item = this.game.systems.inventory.generateItem('weapon', 'legendary'); this.game.systems.inventory.addItem(item); rewardsGiven.item = item; if (debugLogger) debugLogger.logStep('Item reward given', { itemGenerated: item, itemType: item.type, itemRarity: item.rarity, itemName: item.name }); } if (debugLogger) debugLogger.endStep('QuestSystem.giveQuestRewards', { questId: quest.id, questName: quest.name, rewardsGiven: rewardsGiven, playerChanges: { credits: { old: oldPlayerStats.credits, new: this.game.systems.economy.credits }, gems: { old: oldPlayerStats.gems, new: this.game.systems.economy.gems }, experience: { old: oldPlayerStats.experience, new: this.game.systems.player.stats.experience }, level: { old: oldPlayerStats.level, new: this.game.systems.player.stats.level } }, totalRewardsEarnedUpdated: this.stats.totalRewardsEarned }); } // Objective progress updateObjectiveProgress(type, amount, context = {}) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.updateObjectiveProgress', { type: type, amount: amount, context: context, activeQuestsCount: this.activeQuests.length }); const progressUpdates = []; // Update all active quests this.activeQuests.forEach(quest => { const questProgress = []; quest.objectives.forEach(objective => { if (objective.type === type && objective.current < objective.target) { const oldProgress = objective.current; objective.current = Math.min(objective.current + amount, objective.target); const actualProgress = objective.current - oldProgress; if (actualProgress > 0) { questProgress.push({ objectiveId: objective.id, description: objective.description, oldProgress: oldProgress, newProgress: objective.current, target: objective.target, progressMade: actualProgress, completed: objective.current >= objective.target }); } } }); if (questProgress.length > 0) { progressUpdates.push({ questId: quest.id, questName: quest.name, questType: quest.type, objectivesUpdated: questProgress }); // Check if quest is completed if (quest.objectives.every(obj => obj.current >= obj.target)) { this.game.showNotification(`Quest ready to turn in: ${quest.name}`, 'success', 4000); if (debugLogger) debugLogger.logStep('Quest completed via progress update', { questId: quest.id, questName: quest.name, allObjectivesCompleted: true }); } } }); if (debugLogger) debugLogger.endStep('QuestSystem.updateObjectiveProgress', { type: type, amount: amount, progressUpdates: progressUpdates, questsUpdated: progressUpdates.length }); } // Event listeners for quest progress onDungeonCompleted() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.log('QuestSystem.onDungeonCompleted triggered', { activeQuestsCount: this.activeQuests.length }); this.updateObjectiveProgress('dungeon', 1); } onEnemyDefeated() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.log('QuestSystem.onEnemyDefeated triggered', { activeQuestsCount: this.activeQuests.length }); this.updateObjectiveProgress('combat', 1); } onLevelUp(newLevel) { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.log('QuestSystem.onLevelUp triggered', { newLevel: newLevel, activeQuestsCount: this.activeQuests.length }); this.updateObjectiveProgress('level', 1); } onItemCrafted() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.log('QuestSystem.onItemCrafted triggered', { activeQuestsCount: this.activeQuests.length }); this.updateObjectiveProgress('crafting', 1); } // Procedural quest generation (deprecated - replaced by weekly quests) /* generateProceduralQuests() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.generateProceduralQuests', { currentActiveQuests: this.activeQuests.length, maxProceduralQuests: this.maxProceduralQuests, proceduralTemplatesCount: Object.keys(this.proceduralTemplates).length, proceduralQuestRefresh: this.proceduralQuestRefresh }); // Clear existing procedural quests const oldProceduralQuests = this.activeQuests.filter(q => q.type === 'procedural'); this.activeQuests = this.activeQuests.filter(q => q.type !== 'procedural'); if (debugLogger) debugLogger.logStep('Cleared existing procedural quests', { oldProceduralQuestsCount: oldProceduralQuests.length, oldProceduralQuests: oldProceduralQuests.map(q => ({ id: q.id, name: q.name })) }); // Generate new procedural quests const templates = Object.keys(this.proceduralTemplates); const questCount = Math.min(this.maxProceduralQuests, templates.length); const generatedQuests = []; for (let i = 0; i < questCount; i++) { const templateKey = templates[Math.floor(Math.random() * templates.length)]; const template = this.proceduralTemplates[templateKey]; const quest = { id: `procedural_${Date.now()}_${i}`, name: template.name, description: template.description.replace('{target}', template.objectives[0].target), type: 'procedural', status: 'available', objectives: template.objectives.map(obj => ({ ...obj })), rewards: { ...template.rewards }, expiresAt: Date.now() + this.proceduralQuestRefresh }; this.activeQuests.push(quest); generatedQuests.push(quest); if (debugLogger) debugLogger.logStep('Procedural quest generated', { templateKey: templateKey, questId: quest.id, questName: quest.name, questDescription: quest.description, objectives: quest.objectives, rewards: quest.rewards, expiresAt: quest.expiresAt }); } // Schedule next refresh setTimeout(() => this.generateProceduralQuests(), this.proceduralQuestRefresh); if (debugLogger) debugLogger.endStep('QuestSystem.generateProceduralQuests', { oldProceduralQuestsRemoved: oldProceduralQuests.length, newProceduralQuestsGenerated: generatedQuests.length, generatedQuests: generatedQuests.map(q => ({ id: q.id, name: q.name, type: q.type })), nextRefreshScheduled: true, refreshInterval: this.proceduralQuestRefresh }); } */ randomizeDailyQuests() { const debugLogger = window.debugLogger; console.log('[QUEST SYSTEM] randomizeDailyQuests called'); // Safety check for allDailyQuests if (!this.allDailyQuests || !Array.isArray(this.allDailyQuests)) { console.error('[QUEST SYSTEM] allDailyQuests is not available or not an array'); return; } console.log(`[QUEST SYSTEM] allDailyQuests count: ${this.allDailyQuests.length}`); if (debugLogger) debugLogger.startStep('QuestSystem.randomizeDailyQuests', { allDailyQuestsCount: this.allDailyQuests.length, currentDailyQuestsCount: this.dailyQuests.length, currentSelectedDailyQuestsCount: this.selectedDailyQuests.length }); // Clear current daily quests this.dailyQuests = []; this.selectedDailyQuests = []; if (debugLogger) debugLogger.logStep('Cleared current daily quests'); // Select 3 random quests from allDailyQuests const shuffled = [...this.allDailyQuests].sort(() => Math.random() - 0.5); this.selectedDailyQuests = shuffled.slice(0, 3); console.log(`[QUEST SYSTEM] Selected ${this.selectedDailyQuests.length} random daily quests`); if (debugLogger) debugLogger.logStep('Selected random daily quests', { selectedQuests: this.selectedDailyQuests.map(q => ({ id: q.id, name: q.name, difficulty: q.difficulty })) }); // Create deep copies for active quests and automatically start them this.selectedDailyQuests.forEach(questTemplate => { try { const quest = { ...questTemplate, id: `${questTemplate.id}_${Date.now()}`, status: 'active', // Auto-start daily quests objectives: questTemplate.objectives.map(obj => ({ ...obj, current: 0 })) }; this.dailyQuests.push(quest); this.activeQuests.push(quest); // Add to active quests for progress tracking console.log(`[QUEST SYSTEM] Created daily quest: ${quest.id}, name: ${quest.name}, status: ${quest.status}`); } catch (error) { console.error('[QUEST SYSTEM] Error creating daily quest from template:', error); } }); if (debugLogger) debugLogger.endStep('QuestSystem.randomizeDailyQuests', { dailyQuestsCreated: this.dailyQuests.length, activeQuestsCount: this.activeQuests.length, selectedDailyQuestsCount: this.selectedDailyQuests.length }); } // Daily reset reset() { const debugLogger = window.debugLogger; const oldState = { activeQuestsCount: this.activeQuests.length, completedQuestsCount: this.completedQuests.length, dailyQuestsCount: this.dailyQuests.length, selectedDailyQuestsCount: this.selectedDailyQuests.length }; if (debugLogger) debugLogger.startStep('QuestSystem.reset', { oldState: oldState }); this.activeQuests = []; this.completedQuests = []; this.dailyQuests = []; this.selectedDailyQuests = []; this.lastDailyReset = this.getServerTime(); // Reset main quest statuses this.mainQuests.forEach(quest => { quest.status = quest.id === 'tutorial_complete' ? 'available' : 'locked'; }); if (debugLogger) debugLogger.endStep('QuestSystem.reset', { oldState: oldState, newState: { activeQuestsCount: this.activeQuests.length, completedQuestsCount: this.completedQuests.length, dailyQuestsCount: this.dailyQuests.length, selectedDailyQuestsCount: this.selectedDailyQuests.length, mainQuestsReset: true } }); } clear() { const debugLogger = window.debugLogger; if (debugLogger) debugLogger.startStep('QuestSystem.clear'); this.reset(); if (debugLogger) debugLogger.endStep('QuestSystem.clear', { resetCompleted: true }); } checkDailyReset() { const debugLogger = window.debugLogger; const now = this.getServerTime(); const lastReset = this.lastDailyReset; const daysSinceReset = Math.floor((now - lastReset) / (24 * 60 * 60 * 1000)); if (debugLogger) debugLogger.startStep('QuestSystem.checkDailyReset', { now: now, lastReset: lastReset, daysSinceReset: daysSinceReset, threshold: 1 }); if (daysSinceReset >= 1) { if (debugLogger) debugLogger.logStep('Daily reset triggered', { daysSinceReset: daysSinceReset }); this.resetDailyQuests(); this.stats.lastDailyReset = now; this.stats.dailyQuestsCompleted = 0; this.game.showNotification('Daily quests refreshed!', 'success', 4000); if (debugLogger) debugLogger.logStep('Daily reset completed', { newLastDailyReset: this.stats.lastDailyReset, dailyQuestsCompletedReset: this.stats.dailyQuestsCompleted }); } // Remove only COMPLETED daily quests from active list, not all daily quests const oldActiveQuestsCount = this.activeQuests.length; this.activeQuests = this.activeQuests.filter(q => q.type !== 'daily' || q.status !== 'completed'); const removedDailyQuests = oldActiveQuestsCount - this.activeQuests.length; if (debugLogger) debugLogger.endStep('QuestSystem.checkDailyReset', { resetTriggered: daysSinceReset >= 1, removedDailyQuests: removedDailyQuests, finalActiveQuestsCount: this.activeQuests.length }); } resetDailyQuests() { // Remove old daily quests from active list first this.activeQuests = this.activeQuests.filter(q => q.type !== 'daily'); // Generate new random daily quests this.randomizeDailyQuests(); } startDailyCountdown() { console.log('[QUEST SYSTEM] Starting daily countdown timer'); // Update countdown immediately this.updateDailyCountdown(); // Only start timer if in multiplayer mode or game is actively running const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning; if (shouldStartTimer) { // Update every second this.dailyCountdownInterval = setInterval(() => { this.updateDailyCountdown(); }, 1000); console.log('[QUEST SYSTEM] Daily countdown timer started with interval:', this.dailyCountdownInterval); } else { console.log('[QUEST SYSTEM] Skipping daily countdown timer - not in multiplayer mode'); } } updateDailyCountdown() { // Always update countdown so it's ready when user switches to daily tab const now = this.getServerDate(); const tomorrow = new Date(); tomorrow.setUTCDate(now.getDate() + 1); tomorrow.setUTCHours(0, 0, 0, 0); // Set to midnight UTC const timeUntilReset = tomorrow - now; const hours = Math.floor(timeUntilReset / (1000 * 60 * 60)); const minutes = Math.floor((timeUntilReset % (1000 * 60 * 60)) / (1000 * 60)); const seconds = Math.floor((timeUntilReset % (1000 * 60)) / 1000); // Update countdown display const countdownElement = document.getElementById('dailyCountdown'); if (countdownElement) { countdownElement.textContent = `Daily quests reset in: ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; console.log('[QUEST SYSTEM] Daily countdown updated:', countdownElement.textContent); } else { console.log('[QUEST SYSTEM] Daily countdown element not found'); } } // Weekly quest management functions randomizeWeeklyQuests() { const debugLogger = window.debugLogger; console.log('[QUEST SYSTEM] randomizeWeeklyQuests called'); // Safety check for allWeeklyQuests if (!this.allWeeklyQuests || !Array.isArray(this.allWeeklyQuests)) { console.error('[QUEST SYSTEM] allWeeklyQuests not properly initialized'); this.weeklyQuests = []; this.selectedWeeklyQuests = []; return; } console.log(`[QUEST SYSTEM] allWeeklyQuests count: ${this.allWeeklyQuests.length}`); if (debugLogger) debugLogger.startStep('QuestSystem.randomizeWeeklyQuests', { allWeeklyQuestsCount: this.allWeeklyQuests.length, currentWeeklyQuestsCount: this.weeklyQuests.length, currentSelectedWeeklyQuestsCount: this.selectedWeeklyQuests.length }); // Clear existing weekly quests from active quests this.activeQuests = this.activeQuests.filter(q => q.type !== 'weekly'); // Select 5 random weekly quests const shuffled = [...this.allWeeklyQuests].sort(() => Math.random() - 0.5); this.selectedWeeklyQuests = shuffled.slice(0, 5); this.weeklyQuests = this.selectedWeeklyQuests.map(quest => ({ ...quest })); // Add weekly quests to active quests this.weeklyQuests.forEach(quest => { if (quest.status === 'available') { this.activeQuests.push(quest); } }); console.log(`[QUEST SYSTEM] Created ${this.weeklyQuests.length} weekly quests`); if (debugLogger) debugLogger.endStep('QuestSystem.randomizeWeeklyQuests', { weeklyQuestsCreated: this.weeklyQuests.length, activeQuestsCount: this.activeQuests.length, selectedWeeklyQuestsCount: this.selectedWeeklyQuests.length }); } checkWeeklyReset() { const debugLogger = window.debugLogger; const now = this.getServerTime(); const lastReset = this.lastWeeklyReset || 0; // Calculate if we need to reset based on Saturday midnight (server time) const currentDateTime = this.getServerDate(); const dayOfWeek = currentDateTime.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday const currentHour = currentDateTime.getHours(); const currentMinute = currentDateTime.getMinutes(); const currentSecond = currentDateTime.getSeconds(); let shouldReset = false; let resetTime; if (dayOfWeek === 6) { // Today is Saturday resetTime = new Date(currentDateTime); resetTime.setHours(0, 0, 0, 0); // Set to midnight // Reset at exactly midnight on Saturday if (currentHour === 0 && currentMinute === 0 && currentSecond === 0 && lastReset < resetTime.getTime()) { shouldReset = true; } } else { // Calculate last Saturday's reset time (midnight) const daysSinceLastSaturday = (dayOfWeek + 1) % 7 || 7; const lastSaturday = new Date(currentDateTime); lastSaturday.setDate(currentDateTime.getDate() - daysSinceLastSaturday); lastSaturday.setHours(0, 0, 0, 0); resetTime = lastSaturday; if (lastReset < resetTime.getTime()) { shouldReset = true; } } if (debugLogger) debugLogger.startStep('QuestSystem.checkWeeklyReset', { now: now, lastReset: lastReset, currentDayOfWeek: dayOfWeek, currentHour: currentHour, currentMinute: currentMinute, resetTime: resetTime ? resetTime.getTime() : null, shouldReset: shouldReset }); if (shouldReset) { console.log('[QUEST SYSTEM] Weekly reset triggered'); // Reset weekly quests this.lastWeeklyReset = now; // Remove completed weekly quests from active quests const oldActiveQuestsCount = this.activeQuests.length; this.activeQuests = this.activeQuests.filter(q => q.type !== 'weekly' || q.status !== 'completed'); const removedWeeklyQuests = oldActiveQuestsCount - this.activeQuests.length; if (debugLogger) debugLogger.endStep('QuestSystem.checkWeeklyReset', { resetTriggered: true, removedWeeklyQuests: removedWeeklyQuests, finalActiveQuestsCount: this.activeQuests.length }); // Clear weekly quest history and generate new ones this.completedWeeklyQuests = []; this.activeQuests = this.activeQuests.filter(q => q.type !== 'weekly'); // Generate new random weekly quests this.randomizeWeeklyQuests(); // Update UI to show new weekly quests this.updateQuestList(); // Show notification to player this.game.showNotification('Weekly quests have been reset! New quests available.', 'info', 5000); } } startWeeklyCountdown() { console.log('[QUEST SYSTEM] Starting weekly countdown timer'); // Update countdown immediately this.updateWeeklyCountdown(); // Only start timer if in multiplayer mode or game is actively running const shouldStartTimer = window.smartSaveManager?.isMultiplayer || this.game?.isRunning; if (shouldStartTimer) { // Update every minute (weekly changes less frequently) this.weeklyCountdownInterval = setInterval(() => { this.updateWeeklyCountdown(); // Check for weekly reset every minute this.checkWeeklyReset(); }, 60000); // 1 minute console.log('[QUEST SYSTEM] Weekly countdown timer started with interval:', this.weeklyCountdownInterval); } else { console.log('[QUEST SYSTEM] Skipping weekly countdown timer - not in multiplayer mode'); } } updateWeeklyCountdown() { const now = this.getServerDate(); const dayOfWeek = now.getDay(); // 0 = Sunday, 1 = Monday, ..., 6 = Saturday const currentHour = now.getHours(); const currentMinute = now.getMinutes(); const currentSecond = now.getSeconds(); console.log('[QUEST SYSTEM] Weekly countdown debug:', { now: now.toString(), dayOfWeek: dayOfWeek, dayName: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'][dayOfWeek], currentHour: currentHour, currentMinute: currentMinute, currentSecond: currentSecond }); // Calculate days until Saturday midnight (00:00:00) let daysUntilSaturday; if (dayOfWeek === 6) { // Today is Saturday // Check if it's before midnight if (now.getHours() < 0 || (now.getHours() === 0 && now.getMinutes() === 0 && now.getSeconds() === 0)) { daysUntilSaturday = 0; } else { // It's after midnight on Saturday, next reset is next Saturday daysUntilSaturday = 7; } } else { // Simple calculation: days until Saturday = 6 - current day // Sunday (0) -> 6 days, Monday (1) -> 5 days, ..., Friday (5) -> 1 day daysUntilSaturday = 6 - dayOfWeek; if (daysUntilSaturday <= 0) daysUntilSaturday += 7; // Ensure positive } console.log('[QUEST SYSTEM] Days until Saturday:', daysUntilSaturday); // Create the target reset time (Saturday midnight UTC) const nextSaturday = new Date(); nextSaturday.setUTCDate(now.getDate() + daysUntilSaturday); nextSaturday.setUTCHours(0, 0, 0, 0); // Set to midnight UTC console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toUTCString()); let timeUntilReset = nextSaturday.getTime() - now.getTime(); // Ensure timeUntilReset is positive (handle edge cases) if (timeUntilReset <= 0) { console.log('[QUEST SYSTEM] Time until reset is negative or zero, adding 7 days'); nextSaturday.setUTCDate(nextSaturday.getDate() + 7); timeUntilReset = nextSaturday.getTime() - now.getTime(); } console.log('[QUEST SYSTEM] Time until reset (ms):', timeUntilReset); // Convert to days, hours, minutes, seconds const totalSeconds = Math.floor(timeUntilReset / 1000); const days = Math.floor(totalSeconds / (24 * 60 * 60)); const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60)); const minutes = Math.floor((totalSeconds % (60 * 60)) / 60); const seconds = totalSeconds % 60; console.log('[QUEST SYSTEM] Time breakdown:', { timeUntilReset: timeUntilReset, totalSeconds: totalSeconds, days: days, hours: hours, minutes: minutes, seconds: seconds, daysUntilSaturday: daysUntilSaturday, nextSaturdayDate: nextSaturday.toString(), currentDate: now.toString() }); // Update countdown display const countdownElement = document.getElementById('weeklyCountdown'); if (countdownElement) { // Use the calculated days from timeUntilReset, not daysUntilSaturday if (days > 0) { countdownElement.textContent = `Weekly quests reset in: ${days}d ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } else if (hours > 0) { countdownElement.textContent = `Weekly quests reset in: ${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } else { countdownElement.textContent = `Weekly quests reset in: ${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } console.log('[QUEST SYSTEM] Weekly countdown updated:', countdownElement.textContent, `(${days}d ${hours}h ${minutes}m ${seconds}s)`); } else { console.log('[QUEST SYSTEM] Weekly countdown element not found'); } } // ... (rest of the code remains the same) // Quest requirements and unlocking checkQuestRequirements(quest) { console.log('Checking requirements for quest:', quest.id, quest.requirements); if (!quest.requirements) { console.log('No requirements, returning true'); return true; } const player = this.game.systems.player; const dungeonSystem = this.game.systems.dungeonSystem; if (quest.requirements.level) { console.log('Level requirement:', quest.requirements.level, 'Player level:', player.stats.level); if (player.stats.level < quest.requirements.level) { console.log('Level requirement not met'); return false; } } if (quest.requirements.quest) { const requiredQuest = this.findQuest(quest.requirements.quest); console.log('Required quest:', quest.requirements.quest, 'Found:', requiredQuest ? requiredQuest.id : 'null', 'Status:', requiredQuest ? requiredQuest.status : 'null'); if (!requiredQuest || requiredQuest.status !== 'completed') { console.log('Quest requirement not met'); return false; } } if (quest.requirements.guild) { // Check if player is in a guild if (!player.stats.guildJoined) { return false; } } if (quest.requirements.dungeons) { const dungeonsCleared = player.stats.dungeonsCleared || 0; if (dungeonsCleared < quest.requirements.dungeons) { return false; } } if (quest.requirements.upgrades) { // Check ship upgrade requirements const upgradesCompleted = this.checkUpgradeProgress(quest); if (upgradesCompleted < quest.requirements.upgrades) { return false; } } return true; } checkUpgradeProgress(quest) { const player = this.game.systems.player; let upgradesCompleted = 0; quest.objectives.forEach(objective => { if (objective.type === 'upgrade') { if (player.stats[`upgraded_${objective.id}`]) { upgradesCompleted++; } } }); return upgradesCompleted; } getMaxSkillLevel(player) { // Get the highest skill level from player if (!player.skills) return 0; let maxLevel = 0; Object.values(player.skills).forEach(skill => { if (skill.level > maxLevel) { maxLevel = skill.level; } }); return maxLevel; } unlockNextQuest(nextQuestId) { const nextQuest = this.findQuest(nextQuestId); if (nextQuest && nextQuest.status === 'locked') { nextQuest.status = 'available'; this.game.showNotification(`New quest available: ${nextQuest.name}`, 'info', 4000); } } findQuest(questId) { // Search in all quest arrays including failed quests with safety checks const allQuests = [ ...(this.mainQuests || []), ...(this.dailyQuests || []), ...(this.activeQuests || []), ...(this.completedQuests || []), ...(this.failedQuests || []) ]; return allQuests.find(q => q.id === questId); } getQuestsByType(type) { console.log(`[QUEST SYSTEM] getQuestsByType called with type: ${type}`); switch (type) { case 'main': const mainQuests = (this.mainQuests || []).filter(q => q.status === 'available' || q.status === 'active'); console.log(`[QUEST SYSTEM] Main quests found: ${mainQuests.length}`); return mainQuests; case 'daily': // Ensure daily quests are initialized if (!this.dailyQuests || this.dailyQuests.length === 0) { console.log('[QUEST SYSTEM] Daily quests not initialized, forcing initialization'); this.randomizeDailyQuests(); } const dailyQuests = (this.dailyQuests || []).filter(q => q.status !== 'failed'); console.log(`[QUEST SYSTEM] Daily quests found: ${dailyQuests.length}`); console.log(`[QUEST SYSTEM] All daily quests array:`, this.dailyQuests); dailyQuests.forEach(quest => { console.log(`[QUEST SYSTEM] Daily quest: ${quest.id}, status: ${quest.status}, name: ${quest.name}`); }); return dailyQuests; case 'weekly': const weeklyQuests = (this.weeklyQuests || []).filter(q => q.status !== 'failed'); console.log(`[QUEST SYSTEM] Weekly quests found: ${weeklyQuests.length}`); return weeklyQuests; case 'completed': return this.getCompletedQuests(); case 'failed': return (this.failedQuests || []); default: console.log(`[QUEST SYSTEM] Unknown quest type: ${type}`); return []; } } getCompletedQuests() { const completed = []; // Add completed main quests if (this.mainQuests) { completed.push(...this.mainQuests.filter(q => q.status === 'completed')); } // Add completed daily quests (from history) if (this.completedDailyQuests) { completed.push(...this.completedDailyQuests); } // Add completed weekly quests if (this.weeklyQuests) { completed.push(...this.weeklyQuests.filter(q => q.status === 'completed')); } // Sort by completion time (most recent first) return completed.sort((a, b) => (b.completedAt || 0) - (a.completedAt || 0)); } // Load quests from server data loadServerQuests(serverQuestData) { console.log('[QUEST SYSTEM] Loading server quest data:', serverQuestData); if (!serverQuestData) { console.log('[QUEST SYSTEM] No server quest data provided'); return; } // Clear existing quests this.mainQuests = []; this.dailyQuests = []; this.weeklyQuests = []; this.activeQuests = []; this.completedQuests = []; // Load quests from server data if (serverQuestData.mainQuests && Array.isArray(serverQuestData.mainQuests)) { this.mainQuests = serverQuestData.mainQuests; console.log('[QUEST SYSTEM] Loaded', this.mainQuests.length, 'main quests'); } if (serverQuestData.dailyQuests && Array.isArray(serverQuestData.dailyQuests)) { this.dailyQuests = serverQuestData.dailyQuests; console.log('[QUEST SYSTEM] Loaded', this.dailyQuests.length, 'daily quests'); } if (serverQuestData.activeQuests && Array.isArray(serverQuestData.activeQuests)) { this.activeQuests = serverQuestData.activeQuests; console.log('[QUEST SYSTEM] Loaded', this.activeQuests.length, 'active quests'); } if (serverQuestData.completedQuests && Array.isArray(serverQuestData.completedQuests)) { this.completedQuests = serverQuestData.completedQuests; console.log('[QUEST SYSTEM] Loaded', this.completedQuests.length, 'completed quests'); } console.log('[QUEST SYSTEM] Server quest data loaded successfully'); console.log('[QUEST SYSTEM] Total quests loaded:', { main: this.mainQuests.length, daily: this.dailyQuests.length, active: this.activeQuests.length, completed: this.completedQuests.length }); } // UI updates updateUI() { console.log('[QUEST SYSTEM] updateUI called'); console.log('[QUEST SYSTEM] Game available:', !!this.game); console.log('[QUEST SYSTEM] Multiplayer mode:', window.smartSaveManager?.isMultiplayer); this.updateQuestList(); this.updateQuestStats(); } updateQuestList() { console.log('[QUEST SYSTEM] updateQuestList called'); const questListElement = document.getElementById('questList'); if (!questListElement) { console.log('[QUEST SYSTEM] questListElement not found'); return; } const activeType = document.querySelector('.quest-tab-btn.active')?.dataset.type || 'main'; console.log(`[QUEST SYSTEM] Active quest tab type: ${activeType}`); const quests = this.getQuestsByType(activeType); console.log(`[QUEST SYSTEM] Getting quests for type: ${activeType}, found: ${quests.length} quests`); console.log('[QUEST SYSTEM] First few quests:', quests.slice(0, 3)); questListElement.innerHTML = ''; if (quests.length === 0) { console.log(`[QUEST SYSTEM] No quests found for type: ${activeType}`); questListElement.innerHTML = '
No quests available
'; return; } console.log(`[QUEST SYSTEM] Rendering ${quests.length} quests for type: ${activeType}`); quests.forEach(quest => { console.log(`[QUEST SYSTEM] Rendering quest: ${quest.id}, status: ${quest.status}`); const questElement = document.createElement('div'); questElement.className = `quest-item ${quest.status}`; // Add difficulty indicator for daily quests const difficultyIndicator = quest.type === 'daily' && quest.difficulty ? `