2727 lines
112 KiB
JavaScript
2727 lines
112 KiB
JavaScript
/**
|
|
* 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;
|
|
|
|
// 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
|
|
|
|
// Statistics
|
|
this.stats = {
|
|
questsCompleted: 0,
|
|
dailyQuestsCompleted: 0,
|
|
weeklyQuestsCompleted: 0,
|
|
totalRewardsEarned: { credits: 0, experience: 0, gems: 0 },
|
|
lastDailyReset: Date.now(),
|
|
lastWeeklyReset: Date.now()
|
|
};
|
|
|
|
// 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
|
|
});
|
|
}
|
|
|
|
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 = Date.now();
|
|
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: Date.now() };
|
|
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: Date.now() };
|
|
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 = Date.now();
|
|
|
|
// 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 = Date.now();
|
|
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 = new Date();
|
|
const tomorrow = new Date(now);
|
|
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
tomorrow.setHours(0, 0, 0, 0); // Set to midnight
|
|
|
|
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 = Date.now();
|
|
const lastReset = this.lastWeeklyReset || 0;
|
|
|
|
// Calculate if we need to reset based on Saturday midnight
|
|
const currentDateTime = new Date();
|
|
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 = new Date();
|
|
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)
|
|
const nextSaturday = new Date(now);
|
|
nextSaturday.setDate(now.getDate() + daysUntilSaturday);
|
|
nextSaturday.setHours(0, 0, 0, 0); // Set to midnight
|
|
|
|
console.log('[QUEST SYSTEM] Next Saturday reset time:', nextSaturday.toString());
|
|
|
|
let timeUntilReset = nextSaturday.getTime() - now.getTime();
|
|
|
|
// Ensure timeUntilReset is positive (handle edge cases)
|
|
if (timeUntilReset <= 0) {
|
|
console.log('[QUEST SYSTEM] Time until reset is negative or zero, adding 7 days');
|
|
nextSaturday.setDate(nextSaturday.getDate() + 7);
|
|
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));
|
|
}
|
|
|
|
// UI updates
|
|
updateUI() {
|
|
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`);
|
|
|
|
questListElement.innerHTML = '';
|
|
|
|
if (quests.length === 0) {
|
|
console.log(`[QUEST SYSTEM] No quests found for type: ${activeType}`);
|
|
questListElement.innerHTML = '<p class="no-quests">No quests available</p>';
|
|
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 ?
|
|
`<div class="quest-difficulty difficulty-${quest.difficulty}">
|
|
${'★'.repeat(quest.difficulty)}
|
|
</div>` : '';
|
|
|
|
// Handle completed quests differently
|
|
const isCompleted = quest.status === 'completed';
|
|
const progressPercent = isCompleted ? 100 : (quest.objectives.length > 0 ?
|
|
(quest.objectives.reduce((sum, obj) => sum + (obj.current / obj.target), 0) / quest.objectives.length) * 100 : 0);
|
|
|
|
const objectivesHtml = isCompleted ?
|
|
'<div class="all-objectives-completed">✓ All objectives completed</div>' :
|
|
quest.objectives.map(obj => `
|
|
<div class="quest-objective">
|
|
<span class="objective-description">${obj.description}</span>
|
|
<span class="objective-progress">${obj.current}/${obj.target}</span>
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${(obj.current / obj.target) * 100}%"></div>
|
|
</div>
|
|
</div>
|
|
`).join('');
|
|
|
|
const rewardsHtml = Object.entries(quest.rewards)
|
|
.filter(([key]) => key !== 'item')
|
|
.map(([key, value]) => {
|
|
const icon = key === 'credits' ? 'fa-coins' : key === 'experience' ? 'fa-star' : 'fa-gem';
|
|
return `<div class="quest-reward"><i class="fas ${icon}"></i> ${value}</div>`;
|
|
}).join('');
|
|
|
|
// Add completion time for completed quests
|
|
const completionTime = isCompleted && quest.completedAt ?
|
|
`<div class="completion-time">Completed: ${new Date(quest.completedAt).toLocaleDateString()}</div>` : '';
|
|
|
|
questElement.innerHTML = `
|
|
<div class="quest-header">
|
|
<div class="quest-title">${quest.name}</div>
|
|
<div class="quest-header-info">
|
|
${difficultyIndicator}
|
|
<div class="quest-rewards">
|
|
${rewardsHtml}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="quest-description">${quest.description}</div>
|
|
<div class="quest-objectives">
|
|
${objectivesHtml}
|
|
</div>
|
|
${completionTime}
|
|
<div class="quest-progress">
|
|
<div class="progress-bar">
|
|
<div class="progress-fill" style="width: ${progressPercent}%"></div>
|
|
</div>
|
|
<span>${isCompleted ? 'Completed' : Math.round(progressPercent) + '% Complete'}</span>
|
|
</div>
|
|
<div class="quest-actions">
|
|
${quest.status === 'available' ?
|
|
`<button class="btn btn-primary" onclick="if(window.game && window.game.systems) window.game.systems.questSystem.startQuest('${quest.id}')">Start Quest</button>` :
|
|
quest.status === 'active' ?
|
|
`<div class="active-quest-actions">
|
|
<button class="btn btn-warning" onclick="if(window.game && window.game.systems) window.game.systems.questSystem.cancelQuest('${quest.id}')">
|
|
Cancel Quest
|
|
</button>
|
|
<button class="btn btn-success ${progressPercent < 100 ? 'disabled' : ''}"
|
|
onclick="if(window.game && window.game.systems) window.game.systems.questSystem.completeQuest('${quest.id}')"
|
|
${progressPercent < 100 ? 'disabled' : ''}>
|
|
Turn In
|
|
</button>
|
|
</div>` :
|
|
quest.status === 'completed' ?
|
|
'<span class="completed-badge">Completed</span>' :
|
|
quest.status === 'failed' ?
|
|
`<div class="failed-quest-actions">
|
|
<span class="failed-reason">Failed: ${quest.failureReason || 'Cancelled'}</span>
|
|
<button class="btn btn-secondary" onclick="if(window.game && window.game.systems) window.game.systems.questSystem.retryQuest('${quest.id}')">
|
|
Retry Quest
|
|
</button>
|
|
</div>` :
|
|
'<span class="quest-badge">Available</span>'
|
|
}
|
|
</div>
|
|
`;
|
|
|
|
questListElement.appendChild(questElement);
|
|
});
|
|
}
|
|
|
|
updateQuestStats() {
|
|
// Update quest statistics if elements exist
|
|
const questsCompletedElement = document.getElementById('questsCompleted');
|
|
if (questsCompletedElement) {
|
|
questsCompletedElement.textContent = this.stats.questsCompleted;
|
|
}
|
|
}
|
|
|
|
// Quest cancellation
|
|
cancelQuest(questId) {
|
|
const quest = this.findQuest(questId);
|
|
if (!quest) {
|
|
this.game.showNotification('Quest not found!', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
if (quest.status !== 'active') {
|
|
this.game.showNotification('Only active quests can be cancelled!', 'warning', 3000);
|
|
return;
|
|
}
|
|
|
|
if (!confirm(`Are you sure you want to cancel "${quest.name}"? This quest will be marked as failed.`)) {
|
|
return;
|
|
}
|
|
|
|
// Move quest to failed
|
|
quest.status = 'failed';
|
|
quest.failedAt = Date.now();
|
|
quest.failureReason = 'Cancelled by player';
|
|
|
|
// Remove from active quests
|
|
this.activeQuests = this.activeQuests.filter(q => q.id !== questId);
|
|
|
|
// Add to failed quests
|
|
this.failedQuests.push({...quest});
|
|
|
|
// Apply failure penalty
|
|
this.applyQuestFailurePenalty(quest);
|
|
|
|
this.game.showNotification(`Quest "${quest.name}" cancelled and marked as failed.`, 'warning', 4000);
|
|
this.switchToFailedTab();
|
|
this.updateQuestList();
|
|
}
|
|
|
|
// Quest failure handling
|
|
failQuest(questId, reason = 'Time expired') {
|
|
const quest = this.findQuest(questId);
|
|
if (!quest) return;
|
|
|
|
if (quest.status !== 'active') return;
|
|
|
|
quest.status = 'failed';
|
|
quest.failedAt = Date.now();
|
|
quest.failureReason = reason;
|
|
|
|
// Remove from active quests
|
|
this.activeQuests = this.activeQuests.filter(q => q.id !== questId);
|
|
|
|
// Add to failed quests
|
|
this.failedQuests.push({...quest});
|
|
|
|
// Apply failure penalty
|
|
this.applyQuestFailurePenalty(quest);
|
|
|
|
this.game.showNotification(`Quest "${quest.name}" failed: ${reason}`, 'error', 4000);
|
|
this.switchToFailedTab();
|
|
this.updateQuestList();
|
|
}
|
|
|
|
applyQuestFailurePenalty(quest) {
|
|
// Apply failure penalties
|
|
const player = this.game.systems.player;
|
|
|
|
// Reduce reputation
|
|
if (player.stats.reputation) {
|
|
player.stats.reputation = Math.max(0, player.stats.reputation - 10);
|
|
}
|
|
|
|
// Apply other penalties based on quest type
|
|
switch (quest.type) {
|
|
case 'daily':
|
|
this.stats.dailyQuestsCompleted = Math.max(0, this.stats.dailyQuestsCompleted - 1);
|
|
break;
|
|
}
|
|
|
|
// Only update player UI if in multiplayer mode or game is actively running
|
|
if (this.game.shouldUpdateGUI()) {
|
|
player.updateUI();
|
|
}
|
|
}
|
|
|
|
// Retry failed quest
|
|
retryQuest(questId) {
|
|
const failedQuestIndex = this.failedQuests.findIndex(q => q.id === questId);
|
|
if (failedQuestIndex === -1) {
|
|
this.game.showNotification('Failed quest not found!', 'error', 3000);
|
|
return;
|
|
}
|
|
|
|
const quest = this.failedQuests[failedQuestIndex];
|
|
|
|
// Check if retry is allowed (24 hour cooldown)
|
|
const timeSinceFailure = Date.now() - quest.failedAt;
|
|
const retryCooldown = 24 * 60 * 60 * 1000; // 24 hours
|
|
|
|
if (timeSinceFailure < retryCooldown) {
|
|
const remainingTime = Math.ceil((retryCooldown - timeSinceFailure) / (60 * 60 * 1000));
|
|
this.game.showNotification(`Can retry this quest in ${remainingTime} hours.`, 'warning', 3000);
|
|
return;
|
|
}
|
|
|
|
// Reset quest progress
|
|
quest.objectives.forEach(obj => {
|
|
obj.current = 0;
|
|
});
|
|
quest.status = 'available';
|
|
quest.failedAt = null;
|
|
quest.failureReason = null;
|
|
|
|
// Remove from failed quests
|
|
this.failedQuests.splice(failedQuestIndex, 1);
|
|
|
|
this.game.showNotification(`Quest "${quest.name}" is now available to retry.`, 'success', 3000);
|
|
this.updateQuestList();
|
|
}
|
|
|
|
// Switch to failed quests tab
|
|
switchToFailedTab() {
|
|
// Remove active class from all quest tab buttons
|
|
document.querySelectorAll('.quest-tab-btn').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
|
|
// Add active class to failed quests tab
|
|
const failedTabBtn = document.querySelector('[data-type="failed"]');
|
|
if (failedTabBtn) {
|
|
failedTabBtn.classList.add('active');
|
|
}
|
|
|
|
// Update the quest list to show failed quests
|
|
this.updateQuestList();
|
|
}
|
|
|
|
// Quest progress tracking
|
|
updateQuestProgress(objectiveType, amount = 1) {
|
|
// Update progress for all active quests with this objective type
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === objectiveType || objective.id.includes(objectiveType)) {
|
|
const oldValue = objective.current;
|
|
objective.current = Math.min(objective.current + amount, objective.target);
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
}
|
|
|
|
updateLevelProgress(newLevel) {
|
|
// Update progress for level-based objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === 'level' || objective.id.includes('level')) {
|
|
const oldValue = objective.current;
|
|
objective.current = Math.min(newLevel, objective.target);
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
}
|
|
|
|
updateDungeonProgress() {
|
|
// Update progress for dungeon-based objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === 'dungeon' || objective.id.includes('dungeon') || objective.id.includes('clear_dungeon')) {
|
|
const oldValue = objective.current;
|
|
objective.current = Math.min(objective.current + 1, objective.target);
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
}
|
|
|
|
updateTutorialDungeonProgress() {
|
|
// Update progress for tutorial dungeon objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === 'tutorial_dungeon' || objective.id.includes('tutorial_dungeon')) {
|
|
const oldValue = objective.current;
|
|
objective.current = 1; // Tutorial dungeon is completed
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
}
|
|
|
|
updateUpgradeProgress(upgradeType) {
|
|
// Update progress for upgrade objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === 'upgrade' && (objective.id === upgradeType || objective.id.includes(upgradeType))) {
|
|
const oldValue = objective.current;
|
|
objective.current = 1; // Upgrade completed
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
this.checkQuestAvailability();
|
|
}
|
|
|
|
updateGuildProgress(action, amount = 1) {
|
|
// Update progress for guild objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (action === 'join' && (objective.type === 'guild' || objective.id.includes('guild'))) {
|
|
const oldValue = objective.current;
|
|
objective.current = 1; // Guild joined
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
|
|
if (action === 'contribute' && (objective.type === 'contribution' || objective.id.includes('contribution'))) {
|
|
const oldValue = objective.current;
|
|
objective.current = Math.min(objective.current + amount, objective.target);
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
this.checkQuestAvailability();
|
|
}
|
|
|
|
updateSkillProgress() {
|
|
// Update progress for skill objectives
|
|
[...(this.activeQuests || []), ...(this.mainQuests || []), ...(this.dailyQuests || [])].forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
quest.objectives.forEach(objective => {
|
|
if (objective.type === 'skill' || objective.id.includes('skill')) {
|
|
const player = this.game.systems.player;
|
|
const maxSkillLevel = this.getMaxSkillLevel(player);
|
|
const oldValue = objective.current;
|
|
objective.current = Math.min(maxSkillLevel, objective.target);
|
|
|
|
if (objective.current !== oldValue) {
|
|
this.game.showNotification(`${objective.description}: ${objective.current}/${objective.target}`, 'info', 2000);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
this.updateQuestList();
|
|
this.checkQuestCompletion();
|
|
this.checkQuestAvailability();
|
|
}
|
|
|
|
checkInitialQuestProgress(quest) {
|
|
const player = this.game.systems.player;
|
|
const dungeonSystem = this.game.systems.dungeonSystem;
|
|
|
|
console.log(`[QUEST SYSTEM] Checking initial progress for quest: ${quest.id}`);
|
|
console.log(`[QUEST SYSTEM] Player stats:`, player.stats);
|
|
|
|
quest.objectives.forEach(objective => {
|
|
console.log(`[QUEST SYSTEM] Processing objective: ${objective.id}, type: ${objective.type}`);
|
|
|
|
// Check level-based objectives
|
|
if (objective.type === 'level' || objective.id.includes('level')) {
|
|
objective.current = Math.min(player.stats.level, objective.target);
|
|
console.log(`[QUEST SYSTEM] Level objective ${objective.id}: ${objective.current}/${objective.target}`);
|
|
}
|
|
|
|
// Check dungeon-based objectives
|
|
if (objective.type === 'dungeon' || objective.id.includes('dungeon') || objective.id.includes('clear_dungeon')) {
|
|
// Check any dungeon completion - use multiple sources
|
|
const playerDungeons = player.stats.dungeonsCleared || 0;
|
|
const dungeonSystemStats = dungeonSystem ? dungeonSystem.stats.dungeonsCompleted || 0 : 0;
|
|
const dungeonsCleared = Math.max(playerDungeons, dungeonSystemStats);
|
|
|
|
objective.current = Math.min(dungeonsCleared, objective.target);
|
|
|
|
// Debug logging
|
|
console.log(`Dungeon objective check: Player=${playerDungeons}, DungeonSystem=${dungeonSystemStats}, Final=${dungeonsCleared}`);
|
|
}
|
|
|
|
// Check tutorial dungeon objective
|
|
if (objective.type === 'tutorial_dungeon' || objective.id.includes('tutorial_dungeon')) {
|
|
// Check if tutorial dungeon has been completed
|
|
const tutorialCompleted = player.stats.tutorialDungeonCompleted || false;
|
|
objective.current = tutorialCompleted ? 1 : 0;
|
|
console.log(`[QUEST SYSTEM] Tutorial dungeon objective ${objective.id}: ${objective.current}/${objective.target}, completed: ${tutorialCompleted}`);
|
|
}
|
|
|
|
// Check upgrade objectives
|
|
if (objective.type === 'upgrade' || objective.id.includes('upgrade')) {
|
|
const upgradeCompleted = player.stats[`upgraded_${objective.id}`] || false;
|
|
objective.current = upgradeCompleted ? 1 : 0;
|
|
}
|
|
|
|
// Check guild objectives
|
|
if (objective.type === 'guild' || objective.id.includes('guild')) {
|
|
const guildJoined = player.stats.guildJoined || false;
|
|
objective.current = guildJoined ? 1 : 0;
|
|
}
|
|
|
|
// Check contribution objectives
|
|
if (objective.type === 'contribution' || objective.id.includes('contribution')) {
|
|
const contribution = player.stats.guildContribution || 0;
|
|
objective.current = Math.min(contribution, objective.target);
|
|
}
|
|
|
|
// Check skill objectives
|
|
if (objective.type === 'skill' || objective.id.includes('skill')) {
|
|
const maxSkillLevel = this.getMaxSkillLevel(player);
|
|
objective.current = Math.min(maxSkillLevel, objective.target);
|
|
}
|
|
|
|
// Check other objective types
|
|
if (objective.type === 'collection' || objective.id.includes('collect')) {
|
|
// Check inventory for collected items
|
|
const inventory = this.game.systems.inventory;
|
|
if (inventory && inventory.items) {
|
|
const totalCollected = Object.values(inventory.items).reduce((sum, item) => sum + item.quantity, 0);
|
|
objective.current = Math.min(totalCollected, objective.target);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Check if quest is already complete
|
|
const allComplete = quest.objectives.every(obj => obj.current >= obj.target);
|
|
if (allComplete) {
|
|
quest.status = 'completed';
|
|
this.completeQuest(quest.id);
|
|
}
|
|
}
|
|
|
|
checkQuestCompletion() {
|
|
// Check if any active quests are complete
|
|
this.activeQuests.forEach(quest => {
|
|
if (quest.status === 'active') {
|
|
const allComplete = quest.objectives.every(obj => obj.current >= obj.target);
|
|
if (allComplete) {
|
|
quest.status = 'completed';
|
|
this.completeQuest(quest.id);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Save/Load
|
|
save() {
|
|
const debugLogger = window.debugLogger;
|
|
|
|
// if (debugLogger) debugLogger.startStep('QuestSystem.save', {
|
|
// mainQuestsCount: this.mainQuests.length,
|
|
// dailyQuestsCount: this.dailyQuests.length,
|
|
// activeQuestsCount: this.activeQuests.length,
|
|
// completedQuestsCount: this.completedQuests.length,
|
|
// currentStats: this.stats
|
|
// });
|
|
|
|
const saveData = {
|
|
mainQuests: this.mainQuests,
|
|
dailyQuests: this.dailyQuests,
|
|
activeQuests: this.activeQuests,
|
|
completedQuests: this.completedQuests,
|
|
stats: this.stats
|
|
};
|
|
|
|
// if (debugLogger) debugLogger.endStep('QuestSystem.save', {
|
|
// saveDataSize: JSON.stringify(saveData).length,
|
|
// mainQuestsSaved: this.mainQuests.length,
|
|
// dailyQuestsSaved: this.dailyQuests.length,
|
|
// activeQuestsSaved: this.activeQuests.length,
|
|
// completedQuestsSaved: this.completedQuests.length,
|
|
// statsSaved: this.stats,
|
|
// saveData: saveData
|
|
// });
|
|
|
|
return saveData;
|
|
}
|
|
|
|
load(data) {
|
|
const debugLogger = window.debugLogger;
|
|
const oldState = {
|
|
mainQuestsCount: this.mainQuests.length,
|
|
dailyQuestsCount: this.dailyQuests.length,
|
|
activeQuestsCount: this.activeQuests.length,
|
|
completedQuestsCount: this.completedQuests.length,
|
|
stats: this.stats
|
|
};
|
|
|
|
if (debugLogger) debugLogger.startStep('QuestSystem.load', {
|
|
oldState: oldState,
|
|
loadData: data
|
|
});
|
|
|
|
try {
|
|
if (data.mainQuests) {
|
|
this.mainQuests = data.mainQuests;
|
|
|
|
if (debugLogger) debugLogger.logStep('Loaded main quests', {
|
|
mainQuestsLoaded: this.mainQuests.length,
|
|
mainQuests: this.mainQuests.map(q => ({
|
|
id: q.id,
|
|
name: q.name,
|
|
status: q.status
|
|
}))
|
|
});
|
|
}
|
|
|
|
if (data.dailyQuests) {
|
|
this.dailyQuests = data.dailyQuests;
|
|
|
|
if (debugLogger) debugLogger.logStep('Loaded daily quests', {
|
|
dailyQuestsLoaded: this.dailyQuests.length,
|
|
dailyQuests: this.dailyQuests.map(q => ({
|
|
id: q.id,
|
|
name: q.name,
|
|
status: q.status
|
|
}))
|
|
});
|
|
}
|
|
|
|
if (data.activeQuests) {
|
|
this.activeQuests = data.activeQuests;
|
|
|
|
if (debugLogger) debugLogger.logStep('Loaded active quests', {
|
|
activeQuestsLoaded: this.activeQuests.length,
|
|
activeQuests: this.activeQuests.map(q => ({
|
|
id: q.id,
|
|
name: q.name,
|
|
type: q.type,
|
|
status: q.status
|
|
}))
|
|
});
|
|
}
|
|
|
|
if (data.completedQuests) {
|
|
this.completedQuests = data.completedQuests;
|
|
|
|
if (debugLogger) debugLogger.logStep('Loaded completed quests', {
|
|
completedQuestsLoaded: this.completedQuests.length,
|
|
completedQuests: this.completedQuests.map(q => ({
|
|
id: q.id,
|
|
name: q.name,
|
|
type: q.type,
|
|
completedAt: q.completedAt
|
|
}))
|
|
});
|
|
}
|
|
|
|
if (data.stats) {
|
|
const oldStats = { ...this.stats };
|
|
this.stats = { ...this.stats, ...data.stats };
|
|
|
|
if (debugLogger) debugLogger.logStep('Loaded quest statistics', {
|
|
oldStats: oldStats,
|
|
newStats: this.stats,
|
|
statsMerged: true
|
|
});
|
|
}
|
|
|
|
// Check for daily reset after loading
|
|
if (debugLogger) debugLogger.logStep('Checking daily reset after load');
|
|
this.checkDailyReset();
|
|
|
|
if (debugLogger) debugLogger.endStep('QuestSystem.load', {
|
|
success: true,
|
|
oldState: oldState,
|
|
newState: {
|
|
mainQuestsCount: this.mainQuests.length,
|
|
dailyQuestsCount: this.dailyQuests.length,
|
|
activeQuestsCount: this.activeQuests.length,
|
|
completedQuestsCount: this.completedQuests.length,
|
|
stats: this.stats
|
|
},
|
|
dailyResetChecked: true
|
|
});
|
|
} catch (error) {
|
|
if (debugLogger) debugLogger.errorEvent('QuestSystem.load', error, {
|
|
oldState: oldState,
|
|
loadData: data,
|
|
error: error.message
|
|
});
|
|
throw error;
|
|
}
|
|
}
|
|
}
|