This repository has been archived on 2026-05-04. You can view files and clone it, but cannot push or open issues or pull requests.
Galaxy-Strike-Online/GameServer/systems/QuestSystem.js
2026-01-24 21:39:56 -04:00

440 lines
13 KiB
JavaScript

/**
* Galaxy Strike Online - Server Quest System
* Manages quests, progress tracking, and rewards
*/
class QuestSystem {
constructor() {
this.quests = new Map();
this.playerQuests = new Map(); // userId -> quest data
this.initializeQuests();
}
initializeQuests() {
// Tutorial quests
this.addQuest('tutorial_first_battle', {
name: 'First Battle',
description: 'Complete your first battle to learn the basics',
type: 'tutorial',
difficulty: 'easy',
requirements: {
battlesWon: 1
},
rewards: {
experience: 100,
credits: 500,
items: ['health_kit', 'energy_pack']
},
prerequisites: [],
repeatable: false,
timeLimit: null
});
// Combat quests
this.addQuest('warrior_path', {
name: 'Warrior Path',
description: 'Win 10 battles to prove your combat skills',
type: 'combat',
difficulty: 'medium',
requirements: {
battlesWon: 10,
enemiesDefeated: 50
},
rewards: {
experience: 500,
credits: 2000,
items: ['basic_armor']
},
prerequisites: ['tutorial_first_battle'],
repeatable: false,
timeLimit: null
});
// Crafting quests
this.addQuest('novice_crafter', {
name: 'Novice Crafter',
description: 'Craft 5 items to learn the basics of crafting',
type: 'crafting',
difficulty: 'easy',
requirements: {
itemsCrafted: 5
},
rewards: {
experience: 200,
credits: 1000,
craftingExperience: 100
},
prerequisites: [],
repeatable: false,
timeLimit: null
});
// Exploration quests
this.addQuest('explorer_spirit', {
name: 'Explorer Spirit',
description: 'Discover 5 different locations in the galaxy',
type: 'exploration',
difficulty: 'medium',
requirements: {
locationsDiscovered: 5
},
rewards: {
experience: 300,
credits: 1500,
items: ['navigation_device']
},
prerequisites: ['tutorial_first_battle'],
repeatable: false,
timeLimit: null
});
// Daily quests
this.addQuest('daily_bounty', {
name: 'Daily Bounty',
description: 'Complete 3 battles today',
type: 'daily',
difficulty: 'easy',
requirements: {
battlesWon: 3
},
rewards: {
experience: 150,
credits: 750
},
prerequisites: [],
repeatable: true,
timeLimit: 86400000 // 24 hours
});
// Weekly quests
this.addQuest('weekly_champion', {
name: 'Weekly Champion',
description: 'Win 20 battles this week',
type: 'weekly',
difficulty: 'hard',
requirements: {
battlesWon: 20
},
rewards: {
experience: 1000,
credits: 5000,
items: ['rare_weapon_part']
},
prerequisites: [],
repeatable: true,
timeLimit: 604800000 // 7 days
});
}
addQuest(id, quest) {
this.quests.set(id, {
id,
...quest,
createdAt: new Date().toISOString()
});
}
getQuest(id) {
return this.quests.get(id);
}
getAllQuests() {
return Array.from(this.quests.values());
}
getQuestsByType(type) {
return Array.from(this.quests.values()).filter(quest => quest.type === type);
}
getQuestsByDifficulty(difficulty) {
return Array.from(this.quests.values()).filter(quest => quest.difficulty === difficulty);
}
initializePlayerData(userId) {
if (!this.playerQuests.has(userId)) {
this.playerQuests.set(userId, {
activeQuests: new Map(),
completedQuests: new Map(),
questHistory: [],
totalQuestsCompleted: 0,
dailyQuestsCompleted: 0,
weeklyQuestsCompleted: 0
});
}
return this.playerQuests.get(userId);
}
getPlayerData(userId) {
return this.playerQuests.get(userId) || this.initializePlayerData(userId);
}
getAvailableQuests(userId) {
const playerData = this.getPlayerData(userId);
const availableQuests = [];
for (const [questId, quest] of this.quests) {
// Skip if already active or completed (for non-repeatable quests)
if (playerData.activeQuests.has(questId)) continue;
if (playerData.completedQuests.has(questId) && !quest.repeatable) continue;
// Check prerequisites
const prerequisitesMet = quest.prerequisites.every(prereqId =>
playerData.completedQuests.has(prereqId)
);
if (prerequisitesMet) {
availableQuests.push({
...quest,
status: playerData.activeQuests.has(questId) ? 'active' : 'available'
});
}
}
return availableQuests;
}
startQuest(userId, questId) {
const quest = this.getQuest(questId);
if (!quest) {
throw new Error('Quest not found');
}
const playerData = this.getPlayerData(userId);
// Check if quest is already active
if (playerData.activeQuests.has(questId)) {
throw new Error('Quest already active');
}
// Check if quest is completed and not repeatable
if (playerData.completedQuests.has(questId) && !quest.repeatable) {
throw new Error('Quest already completed');
}
// Check prerequisites
const prerequisitesMet = quest.prerequisites.every(prereqId =>
playerData.completedQuests.has(prereqId)
);
if (!prerequisitesMet) {
throw new Error('Prerequisites not met');
}
// Start the quest
const questProgress = {
questId,
startedAt: new Date().toISOString(),
progress: {},
completed: false,
expiredAt: quest.timeLimit ? new Date(Date.now() + quest.timeLimit).toISOString() : null
};
// Initialize progress tracking
for (const requirement of Object.keys(quest.requirements)) {
questProgress.progress[requirement] = 0;
}
playerData.activeQuests.set(questId, questProgress);
return {
success: true,
quest,
progress: questProgress
};
}
updateQuestProgress(userId, questId, progressUpdates) {
const playerData = this.getPlayerData(userId);
const activeQuest = playerData.activeQuests.get(questId);
if (!activeQuest) {
throw new Error('Quest not active');
}
// Check if quest is expired
if (activeQuest.expiredAt && new Date() > new Date(activeQuest.expiredAt)) {
playerData.activeQuests.delete(questId);
throw new Error('Quest expired');
}
const quest = this.getQuest(questId);
let updated = false;
// Update progress
for (const [requirement, amount] of Object.entries(progressUpdates)) {
if (quest.requirements[requirement] !== undefined) {
activeQuest.progress[requirement] = Math.min(
activeQuest.progress[requirement] + amount,
quest.requirements[requirement]
);
updated = true;
}
}
// Check if quest is completed
const isCompleted = Object.entries(quest.requirements).every(
([requirement, requiredAmount]) =>
activeQuest.progress[requirement] >= requiredAmount
);
if (isCompleted && !activeQuest.completed) {
activeQuest.completed = true;
activeQuest.completedAt = new Date().toISOString();
return {
success: true,
questCompleted: true,
quest,
progress: activeQuest.progress
};
}
return {
success: true,
questCompleted: false,
quest,
progress: activeQuest.progress,
updated
};
}
completeQuest(userId, questId) {
const playerData = this.getPlayerData(userId);
const activeQuest = playerData.activeQuests.get(questId);
if (!activeQuest) {
throw new Error('Quest not active');
}
if (!activeQuest.completed) {
throw new Error('Quest requirements not met');
}
const quest = this.getQuest(questId);
// Move to completed quests
playerData.completedQuests.set(questId, {
...activeQuest,
quest,
completedAt: new Date().toISOString()
});
// Remove from active quests
playerData.activeQuests.delete(questId);
// Update statistics
playerData.totalQuestsCompleted += 1;
if (quest.type === 'daily') {
playerData.dailyQuestsCompleted += 1;
} else if (quest.type === 'weekly') {
playerData.weeklyQuestsCompleted += 1;
}
// Add to history
playerData.questHistory.push({
questId,
questName: quest.name,
completedAt: new Date().toISOString(),
rewards: quest.rewards
});
// Keep only last 100 quest records
if (playerData.questHistory.length > 100) {
playerData.questHistory = playerData.questHistory.slice(-100);
}
return {
success: true,
quest,
rewards: quest.rewards,
statistics: {
totalCompleted: playerData.totalQuestsCompleted,
dailyCompleted: playerData.dailyQuestsCompleted,
weeklyCompleted: playerData.weeklyQuestsCompleted
}
};
}
getPlayerActiveQuests(userId) {
const playerData = this.getPlayerData(userId);
const activeQuests = [];
for (const [questId, progress] of playerData.activeQuests) {
const quest = this.getQuest(questId);
activeQuests.push({
...quest,
progress: progress.progress,
startedAt: progress.startedAt,
expiredAt: progress.expiredAt
});
}
return activeQuests;
}
getPlayerCompletedQuests(userId) {
const playerData = this.getPlayerData(userId);
const completedQuests = [];
for (const [questId, completion] of playerData.completedQuests) {
completedQuests.push({
...completion.quest,
completedAt: completion.completedAt,
progress: completion.progress
});
}
return completedQuests;
}
getQuestStatistics(userId) {
const playerData = this.getPlayerData(userId);
const availableQuests = this.getAvailableQuests(userId);
return {
activeQuests: playerData.activeQuests.size,
completedQuests: playerData.completedQuests.size,
availableQuests: availableQuests.length,
totalCompleted: playerData.totalQuestsCompleted,
dailyCompleted: playerData.dailyQuestsCompleted,
weeklyCompleted: playerData.weeklyQuestsCompleted,
recentHistory: playerData.questHistory.slice(-10)
};
}
resetDailyQuests(userId) {
const playerData = this.getPlayerData(userId);
// Remove completed daily quests
for (const [questId, quest] of this.quests) {
if (quest.type === 'daily') {
playerData.completedQuests.delete(questId);
playerData.activeQuests.delete(questId);
}
}
playerData.dailyQuestsCompleted = 0;
return { success: true, message: 'Daily quests reset' };
}
resetWeeklyQuests(userId) {
const playerData = this.getPlayerData(userId);
// Remove completed weekly quests
for (const [questId, quest] of this.quests) {
if (quest.type === 'weekly') {
playerData.completedQuests.delete(questId);
playerData.activeQuests.delete(questId);
}
}
playerData.weeklyQuestsCompleted = 0;
return { success: true, message: 'Weekly quests reset' };
}
}
module.exports = QuestSystem;