Phase 29: Gameplay Systems (5/5) - Structure interaction, NPCs, Enemies, Quests, Map
This commit is contained in:
353
src/systems/LandmarkQuestSystem.js
Normal file
353
src/systems/LandmarkQuestSystem.js
Normal file
@@ -0,0 +1,353 @@
|
||||
/**
|
||||
* 📜 LANDMARK QUEST SYSTEM
|
||||
* Quest system integrated with landmarks and structures
|
||||
* - Main quest: Visit all 5 landmarks
|
||||
* - Side quests from NPCs
|
||||
* - Exploration rewards
|
||||
* - Quest tracking
|
||||
*/
|
||||
|
||||
class LandmarkQuestSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Active quests
|
||||
this.activeQuests = [];
|
||||
|
||||
// Completed quests
|
||||
this.completedQuests = [];
|
||||
|
||||
// Quest definitions
|
||||
this.quests = {
|
||||
// Main quest chain
|
||||
'main_explore_landmarks': {
|
||||
id: 'main_explore_landmarks',
|
||||
name: 'The Five Landmarks',
|
||||
description: 'Discover all 5 legendary landmarks across the world',
|
||||
type: 'main',
|
||||
objectives: [
|
||||
{ type: 'visit_landmark', target: 'ancient_temple', name: 'Visit Ancient Temple', completed: false },
|
||||
{ type: 'visit_landmark', target: 'great_pyramid', name: 'Visit Great Pyramid', completed: false },
|
||||
{ type: 'visit_landmark', target: 'mountain_peak', name: 'Reach Mountain Peak', completed: false },
|
||||
{ type: 'visit_landmark', target: 'abandoned_city', name: 'Explore Abandoned City', completed: false },
|
||||
{ type: 'visit_landmark', target: 'dragon_skeleton', name: 'Find Dragon Skeleton', completed: false }
|
||||
],
|
||||
rewards: {
|
||||
gold: 5000,
|
||||
xp: 10000,
|
||||
item: 'legendary_compass'
|
||||
}
|
||||
},
|
||||
|
||||
// Biome exploration quests
|
||||
'explore_grassland': {
|
||||
id: 'explore_grassland',
|
||||
name: 'Grassland Explorer',
|
||||
description: 'Visit 10 structures in Grassland biome',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'visit_structures', biome: 'Grassland', count: 0, target: 10, completed: false }
|
||||
],
|
||||
rewards: { gold: 500, xp: 1000 }
|
||||
},
|
||||
|
||||
'explore_forest': {
|
||||
id: 'explore_forest',
|
||||
name: 'Forest Wanderer',
|
||||
description: 'Visit 10 structures in Forest biome',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'visit_structures', biome: 'Forest', count: 0, target: 10, completed: false }
|
||||
],
|
||||
rewards: { gold: 500, xp: 1000 }
|
||||
},
|
||||
|
||||
'explore_desert': {
|
||||
id: 'explore_desert',
|
||||
name: 'Desert Nomad',
|
||||
description: 'Visit 5 structures in Desert biome',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'visit_structures', biome: 'Desert', count: 0, target: 5, completed: false }
|
||||
],
|
||||
rewards: { gold: 750, xp: 1500 }
|
||||
},
|
||||
|
||||
'explore_mountain': {
|
||||
id: 'explore_mountain',
|
||||
name: 'Mountain Climber',
|
||||
description: 'Visit 5 structures in Mountain biome',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'visit_structures', biome: 'Mountain', count: 0, target: 5, completed: false }
|
||||
],
|
||||
rewards: { gold: 750, xp: 1500 }
|
||||
},
|
||||
|
||||
'explore_swamp': {
|
||||
id: 'explore_swamp',
|
||||
name: 'Swamp Explorer',
|
||||
description: 'Visit 5 structures in Swamp biome',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'visit_structures', biome: 'Swamp', count: 0, target: 5, completed: false }
|
||||
],
|
||||
rewards: { gold: 750, xp: 1500 }
|
||||
},
|
||||
|
||||
// Enemy quests
|
||||
'slay_enemies': {
|
||||
id: 'slay_enemies',
|
||||
name: 'Monster Hunter',
|
||||
description: 'Defeat 20 enemies',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'kill_enemies', count: 0, target: 20, completed: false }
|
||||
],
|
||||
rewards: { gold: 1000, xp: 2000 }
|
||||
},
|
||||
|
||||
// Collection quest
|
||||
'treasure_hunter': {
|
||||
id: 'treasure_hunter',
|
||||
name: 'Treasure Hunter',
|
||||
description: 'Open 30 chests',
|
||||
type: 'side',
|
||||
objectives: [
|
||||
{ type: 'open_chests', count: 0, target: 30, completed: false }
|
||||
],
|
||||
rewards: { gold: 2000, xp: 3000 }
|
||||
}
|
||||
};
|
||||
|
||||
// Tracking
|
||||
this.landmarksVisited = [];
|
||||
this.structuresVisitedByBiome = {};
|
||||
|
||||
console.log('📜 LandmarkQuestSystem initialized');
|
||||
}
|
||||
|
||||
// Start main quest automatically
|
||||
startMainQuest() {
|
||||
this.activeQuests.push('main_explore_landmarks');
|
||||
console.log('📜 Main quest started: The Five Landmarks');
|
||||
this.showQuestNotification('New Quest!', 'The Five Landmarks', 'Discover all 5 legendary landmarks');
|
||||
}
|
||||
|
||||
// Start exploration quests
|
||||
startExplorationQuests() {
|
||||
this.activeQuests.push('explore_grassland');
|
||||
this.activeQuests.push('explore_forest');
|
||||
this.activeQuests.push('explore_desert');
|
||||
this.activeQuests.push('explore_mountain');
|
||||
this.activeQuests.push('explore_swamp');
|
||||
console.log('📜 Started 5 biome exploration quests');
|
||||
}
|
||||
|
||||
// Visit landmark (called from player)
|
||||
visitLandmark(landmarkType) {
|
||||
if (this.landmarksVisited.includes(landmarkType)) return;
|
||||
|
||||
this.landmarksVisited.push(landmarkType);
|
||||
console.log(`🗿 Visited landmark: ${landmarkType}`);
|
||||
|
||||
// Update main quest
|
||||
const mainQuest = this.quests['main_explore_landmarks'];
|
||||
if (this.activeQuests.includes('main_explore_landmarks')) {
|
||||
for (const obj of mainQuest.objectives) {
|
||||
if (obj.target === landmarkType) {
|
||||
obj.completed = true;
|
||||
this.showQuestNotification('Objective Complete!', obj.name, '+2000 XP');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if all objectives complete
|
||||
if (mainQuest.objectives.every(o => o.completed)) {
|
||||
this.completeQuest('main_explore_landmarks');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit structure (for biome quests)
|
||||
visitStructure(x, y, biome) {
|
||||
const key = `${x},${y}`;
|
||||
|
||||
if (!this.structuresVisitedByBiome[biome]) {
|
||||
this.structuresVisitedByBiome[biome] = [];
|
||||
}
|
||||
|
||||
if (this.structuresVisitedByBiome[biome].includes(key)) return;
|
||||
|
||||
this.structuresVisitedByBiome[biome].push(key);
|
||||
|
||||
// Update biome exploration quests
|
||||
const questId = `explore_${biome.toLowerCase()}`;
|
||||
if (this.activeQuests.includes(questId)) {
|
||||
const quest = this.quests[questId];
|
||||
for (const obj of quest.objectives) {
|
||||
if (obj.biome === biome) {
|
||||
obj.count++;
|
||||
if (obj.count >= obj.target && !obj.completed) {
|
||||
obj.completed = true;
|
||||
this.completeQuest(questId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete quest and give rewards
|
||||
completeQuest(questId) {
|
||||
const quest = this.quests[questId];
|
||||
if (!quest) return;
|
||||
|
||||
console.log(`✅ Quest completed: ${quest.name}`);
|
||||
|
||||
// Remove from active
|
||||
const index = this.activeQuests.indexOf(questId);
|
||||
if (index > -1) {
|
||||
this.activeQuests.splice(index, 1);
|
||||
}
|
||||
|
||||
// Add to completed
|
||||
this.completedQuests.push(questId);
|
||||
|
||||
// Give rewards
|
||||
if (this.scene.inventorySystem && quest.rewards) {
|
||||
if (quest.rewards.gold) {
|
||||
this.scene.inventorySystem.gold += quest.rewards.gold;
|
||||
}
|
||||
if (quest.rewards.item) {
|
||||
this.scene.inventorySystem.addItem(quest.rewards.item, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Show completion
|
||||
this.showQuestCompleteNotification(quest);
|
||||
|
||||
// Play sound
|
||||
if (this.scene.soundManager) {
|
||||
this.scene.soundManager.beepPickup();
|
||||
}
|
||||
}
|
||||
|
||||
// Show quest notification
|
||||
showQuestNotification(title, questName, description) {
|
||||
const notification = this.scene.add.text(
|
||||
this.scene.cameras.main.centerX,
|
||||
100,
|
||||
`${title}\n${questName}\n${description}`,
|
||||
{
|
||||
fontSize: '24px',
|
||||
color: '#FFD700',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 30, y: 20 },
|
||||
align: 'center'
|
||||
}
|
||||
);
|
||||
notification.setOrigin(0.5);
|
||||
notification.setScrollFactor(0);
|
||||
notification.setDepth(10001);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: notification,
|
||||
alpha: 0,
|
||||
duration: 1000,
|
||||
delay: 3000,
|
||||
onComplete: () => notification.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
// Show quest complete notification
|
||||
showQuestCompleteNotification(quest) {
|
||||
const rewardText = [];
|
||||
if (quest.rewards.gold) rewardText.push(`+${quest.rewards.gold} gold`);
|
||||
if (quest.rewards.xp) rewardText.push(`+${quest.rewards.xp} XP`);
|
||||
if (quest.rewards.item) rewardText.push(`+${quest.rewards.item}`);
|
||||
|
||||
const notification = this.scene.add.text(
|
||||
this.scene.cameras.main.centerX,
|
||||
this.scene.cameras.main.centerY,
|
||||
`🎉 QUEST COMPLETE! 🎉\n${quest.name}\n\nRewards:\n${rewardText.join('\n')}`,
|
||||
{
|
||||
fontSize: '32px',
|
||||
color: '#FFD700',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 40, y: 30 },
|
||||
align: 'center'
|
||||
}
|
||||
);
|
||||
notification.setOrigin(0.5);
|
||||
notification.setScrollFactor(0);
|
||||
notification.setDepth(10002);
|
||||
|
||||
// Fireworks effect
|
||||
for (let i = 0; i < 30; i++) {
|
||||
const particle = this.scene.add.circle(
|
||||
this.scene.cameras.main.centerX,
|
||||
this.scene.cameras.main.centerY,
|
||||
5,
|
||||
[0xFFD700, 0xFF69B4, 0x00BFFF][i % 3]
|
||||
);
|
||||
particle.setScrollFactor(0);
|
||||
particle.setDepth(10001);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: particle,
|
||||
x: particle.x + (Math.random() - 0.5) * 400,
|
||||
y: particle.y + (Math.random() - 0.5) * 400,
|
||||
alpha: 0,
|
||||
duration: 2000,
|
||||
onComplete: () => particle.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: notification,
|
||||
alpha: 0,
|
||||
duration: 1000,
|
||||
delay: 4000,
|
||||
onComplete: () => notification.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
// Get active quests for UI
|
||||
getActiveQuests() {
|
||||
return this.activeQuests.map(id => this.quests[id]);
|
||||
}
|
||||
|
||||
// Get quest progress
|
||||
getQuestProgress(questId) {
|
||||
const quest = this.quests[questId];
|
||||
if (!quest) return null;
|
||||
|
||||
const completed = quest.objectives.filter(o => o.completed).length;
|
||||
const total = quest.objectives.length;
|
||||
|
||||
return { completed, total, objectives: quest.objectives };
|
||||
}
|
||||
|
||||
// Export/Import for save system
|
||||
exportData() {
|
||||
return {
|
||||
activeQuests: this.activeQuests,
|
||||
completedQuests: this.completedQuests,
|
||||
landmarksVisited: this.landmarksVisited,
|
||||
structuresVisitedByBiome: this.structuresVisitedByBiome
|
||||
};
|
||||
}
|
||||
|
||||
importData(data) {
|
||||
if (!data) return;
|
||||
this.activeQuests = data.activeQuests || [];
|
||||
this.completedQuests = data.completedQuests || [];
|
||||
this.landmarksVisited = data.landmarksVisited || [];
|
||||
this.structuresVisitedByBiome = data.structuresVisitedByBiome || {};
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.activeQuests = [];
|
||||
this.completedQuests = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user