440 lines
13 KiB
JavaScript
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;
|