📚 DOCUMENTATION COMPLETE: AUDIO_ASSET_MANIFEST.md (61 files detailed) and VFX_IMPLEMENTATION_GUIDE.md (6 systems with code examples). Ready for asset production phase.
This commit is contained in:
316
src/systems/SchoolBuffSystem.js
Normal file
316
src/systems/SchoolBuffSystem.js
Normal file
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* SCHOOL BUFF SYSTEM
|
||||
* Learning skills from Teacher NPC
|
||||
* Temporary and permanent buffs
|
||||
*/
|
||||
|
||||
export class SchoolBuffSystem {
|
||||
constructor(scene) {
|
||||
this.scene = scene;
|
||||
|
||||
// Available lessons
|
||||
this.lessons = new Map();
|
||||
this.learnedSkills = new Set();
|
||||
|
||||
// Active buffs
|
||||
this.activeBuffs = new Map();
|
||||
|
||||
// Teacher NPC reference
|
||||
this.teacher = null;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.initializeLessons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all available lessons
|
||||
*/
|
||||
initializeLessons() {
|
||||
// FARMING LESSONS
|
||||
this.registerLesson({
|
||||
id: 'basic_farming',
|
||||
name: 'Basic Farming',
|
||||
category: 'farming',
|
||||
cost: 100,
|
||||
duration: 'permanent',
|
||||
description: '+10% crop yield',
|
||||
effect: () => this.scene.gameState.buffs.crop_yield = (this.scene.gameState.buffs.crop_yield || 1.0) * 1.1
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'advanced_farming',
|
||||
name: 'Advanced Farming',
|
||||
category: 'farming',
|
||||
cost: 500,
|
||||
requires: 'basic_farming',
|
||||
duration: 'permanent',
|
||||
description: '+20% crop growth speed',
|
||||
effect: () => this.scene.gameState.buffs.crop_growth_speed = (this.scene.gameState.buffs.crop_growth_speed || 1.0) * 1.2
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'fertilizer_mastery',
|
||||
name: 'Fertilizer Mastery',
|
||||
category: 'farming',
|
||||
cost: 300,
|
||||
duration: 'permanent',
|
||||
description: 'Fertilizer lasts 2x longer',
|
||||
effect: () => this.scene.gameState.buffs.fertilizer_duration = 2.0
|
||||
});
|
||||
|
||||
// COMBAT LESSONS
|
||||
this.registerLesson({
|
||||
id: 'basic_combat',
|
||||
name: 'Basic Combat',
|
||||
category: 'combat',
|
||||
cost: 200,
|
||||
duration: 'permanent',
|
||||
description: '+5 damage to all attacks',
|
||||
effect: () => this.scene.player.attackDamage += 5
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'defense_training',
|
||||
name: 'Defense Training',
|
||||
category: 'combat',
|
||||
cost: 400,
|
||||
duration: 'permanent',
|
||||
description: '+15% damage resistance',
|
||||
effect: () => this.scene.player.damageResistance = (this.scene.player.damageResistance || 0) + 0.15
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'weapon_mastery',
|
||||
name: 'Weapon Mastery',
|
||||
category: 'combat',
|
||||
cost: 800,
|
||||
requires: 'basic_combat',
|
||||
duration: 'permanent',
|
||||
description: '+20% critical hit chance',
|
||||
effect: () => this.scene.player.critChance = (this.scene.player.critChance || 0) + 0.2
|
||||
});
|
||||
|
||||
// SURVIVAL LESSONS
|
||||
this.registerLesson({
|
||||
id: 'herbalism',
|
||||
name: 'Herbalism',
|
||||
category: 'survival',
|
||||
cost: 250,
|
||||
duration: 'permanent',
|
||||
description: 'Healing items restore 50% more HP',
|
||||
effect: () => this.scene.gameState.buffs.healing_bonus = 1.5
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'scavenging',
|
||||
name: 'Scavenging',
|
||||
category: 'survival',
|
||||
cost: 350,
|
||||
duration: 'permanent',
|
||||
description: '+25% loot from containers',
|
||||
effect: () => this.scene.gameState.buffs.loot_bonus = 1.25
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'endurance',
|
||||
name: 'Endurance Training',
|
||||
category: 'survival',
|
||||
cost: 600,
|
||||
duration: 'permanent',
|
||||
description: '+20 max stamina',
|
||||
effect: () => this.scene.player.maxStamina += 20
|
||||
});
|
||||
|
||||
// TEMPORARY BUFFS (Study Sessions)
|
||||
this.registerLesson({
|
||||
id: 'focus_boost',
|
||||
name: 'Focus Boost',
|
||||
category: 'temporary',
|
||||
cost: 50,
|
||||
duration: 300000, // 5 minutes
|
||||
description: '+50% XP gain for 5 minutes',
|
||||
effect: () => this.applyTemporaryBuff('xp_boost', 1.5, 300000)
|
||||
});
|
||||
|
||||
this.registerLesson({
|
||||
id: 'energy_surge',
|
||||
name: 'Energy Surge',
|
||||
category: 'temporary',
|
||||
cost: 75,
|
||||
duration: 180000, // 3 minutes
|
||||
description: '+100% stamina regen for 3 minutes',
|
||||
effect: () => this.applyTemporaryBuff('stamina_regen', 2.0, 180000)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a lesson
|
||||
*/
|
||||
registerLesson(lessonData) {
|
||||
this.lessons.set(lessonData.id, {
|
||||
...lessonData,
|
||||
learned: false
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Learn a skill from Teacher
|
||||
*/
|
||||
learnSkill(lessonId) {
|
||||
const lesson = this.lessons.get(lessonId);
|
||||
if (!lesson) return false;
|
||||
|
||||
// Check if already learned (permanent skills only)
|
||||
if (lesson.duration === 'permanent' && lesson.learned) {
|
||||
console.warn(`Already learned: ${lesson.name}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check prerequisites
|
||||
if (lesson.requires && !this.learnedSkills.has(lesson.requires)) {
|
||||
const required = this.lessons.get(lesson.requires);
|
||||
console.warn(`Must learn ${required.name} first`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check cost
|
||||
const currency = this.scene.economySystem?.getCurrency() || 0;
|
||||
if (currency < lesson.cost) {
|
||||
console.warn(`Insufficient funds: need ${lesson.cost}, have ${currency}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Pay cost
|
||||
this.scene.economySystem.addCurrency(-lesson.cost);
|
||||
|
||||
// Apply effect
|
||||
lesson.effect();
|
||||
|
||||
// Mark as learned
|
||||
if (lesson.duration === 'permanent') {
|
||||
lesson.learned = true;
|
||||
this.learnedSkills.add(lessonId);
|
||||
}
|
||||
|
||||
// Notification
|
||||
this.scene.uiSystem?.showNotification(
|
||||
`Learned: ${lesson.name}!`,
|
||||
'success',
|
||||
{ description: lesson.description }
|
||||
);
|
||||
|
||||
// Teacher dialogue
|
||||
this.scene.dialogueSystem?.startDialogue('teacher', 'lesson_complete', { skill: lesson.name });
|
||||
|
||||
console.log(`📚 Learned: ${lesson.name} (-${lesson.cost} coins)`);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply temporary buff
|
||||
*/
|
||||
applyTemporaryBuff(buffId, multiplier, duration) {
|
||||
// Store buff
|
||||
this.activeBuffs.set(buffId, {
|
||||
multiplier,
|
||||
expiresAt: Date.now() + duration
|
||||
});
|
||||
|
||||
// VFX
|
||||
this.scene.vfxSystem?.playEffect('buff_applied', this.scene.player.x, this.scene.player.y);
|
||||
|
||||
// Remove after duration
|
||||
this.scene.time.delayedCall(duration, () => {
|
||||
this.activeBuffs.delete(buffId);
|
||||
this.scene.uiSystem?.showNotification(`${buffId} expired`, 'info');
|
||||
console.log(`⏱️ Buff expired: ${buffId}`);
|
||||
});
|
||||
|
||||
console.log(`✨ Applied buff: ${buffId} (${duration / 1000}s)`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if buff is active
|
||||
*/
|
||||
hasActiveBuff(buffId) {
|
||||
const buff = this.activeBuffs.get(buffId);
|
||||
if (!buff) return false;
|
||||
|
||||
const now = Date.now();
|
||||
if (now > buff.expiresAt) {
|
||||
this.activeBuffs.delete(buffId);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get buff multiplier
|
||||
*/
|
||||
getBuffMultiplier(buffId) {
|
||||
const buff = this.activeBuffs.get(buffId);
|
||||
return buff ? buff.multiplier : 1.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lessons by category
|
||||
*/
|
||||
getLessonsByCategory(category) {
|
||||
return Array.from(this.lessons.values()).filter(l => l.category === category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available lessons (can be learned now)
|
||||
*/
|
||||
getAvailableLessons() {
|
||||
return Array.from(this.lessons.values()).filter(l => {
|
||||
if (l.duration === 'permanent' && l.learned) return false;
|
||||
if (l.requires && !this.learnedSkills.has(l.requires)) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get learned skills
|
||||
*/
|
||||
getLearnedSkills() {
|
||||
return Array.from(this.lessons.values()).filter(l => l.learned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save/Load
|
||||
*/
|
||||
getSaveData() {
|
||||
return {
|
||||
learnedSkills: Array.from(this.learnedSkills),
|
||||
activeBuffs: Array.from(this.activeBuffs.entries())
|
||||
};
|
||||
}
|
||||
|
||||
loadSaveData(data) {
|
||||
this.learnedSkills = new Set(data.learnedSkills || []);
|
||||
|
||||
// Mark lessons as learned
|
||||
this.learnedSkills.forEach(skillId => {
|
||||
const lesson = this.lessons.get(skillId);
|
||||
if (lesson) {
|
||||
lesson.learned = true;
|
||||
lesson.effect(); // Re-apply permanent effects
|
||||
}
|
||||
});
|
||||
|
||||
// Restore active buffs
|
||||
if (data.activeBuffs) {
|
||||
data.activeBuffs.forEach(([buffId, buffData]) => {
|
||||
const remaining = buffData.expiresAt - Date.now();
|
||||
if (remaining > 0) {
|
||||
this.applyTemporaryBuff(buffId, buffData.multiplier, remaining);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user