import { Unit } from "./Unit.js"; /** * Explorer.js * Player character class supporting Multi-Class Mastery and Persistent Progression. */ export class Explorer extends Unit { constructor(id, name, startingClassId, classDefinition) { super(id, name, "EXPLORER", `${startingClassId}_MODEL`); this.activeClassId = startingClassId; // Persistent Mastery: Tracks progress for EVERY class this character has played // Key: ClassID, Value: { level, xp, skillPoints, unlockedNodes[] } this.classMastery = {}; // Initialize the starting class entry this.initializeMastery(startingClassId); // Hydrate stats based on the provided definition if (classDefinition) { this.recalculateBaseStats(classDefinition); this.currentHealth = this.baseStats.health; } // Inventory this.equipment = { weapon: null, armor: null, utility: null, relic: null, }; // Active Skills (Populated by Skill Tree) this.actions = []; this.passives = []; } initializeMastery(classId) { if (!this.classMastery[classId]) { this.classMastery[classId] = { level: 1, xp: 0, skillPoints: 0, unlockedNodes: [], }; } } /** * Updates base stats based on the active class's base + growth rates * level. * @param {Object} classDef - The JSON definition of the class stats. */ recalculateBaseStats(classDef) { if (classDef.id !== this.activeClassId) { console.warn( `Mismatch: Recalculating stats for ${this.activeClassId} using definition for ${classDef.id}` ); } const mastery = this.classMastery[this.activeClassId]; // 1. Start with Class Defaults let stats = { ...classDef.base_stats }; // 2. Add Level Growth // (Level 1 is base, so growth applies for levels 2+) const levelsGained = mastery.level - 1; if (levelsGained > 0) { for (let stat in classDef.growth_rates) { if (stats[stat] !== undefined) { stats[stat] += classDef.growth_rates[stat] * levelsGained; } } } this.baseStats = stats; this.maxHealth = stats.health; // Update MaxHP cap } /** * Swaps the active class logic. * NOTE: Does NOT check unlock requirements (handled by UI/MetaSystem). */ changeClass(newClassId, newClassDef) { // 1. Ensure mastery record exists this.initializeMastery(newClassId); // 2. Switch ID this.activeClassId = newClassId; // 3. Update Model ID (Visuals) this.voxelModelID = `${newClassId}_MODEL`; // 4. Recalculate Stats for the new job this.recalculateBaseStats(newClassDef); // 5. Reset Current HP to new Max (or keep percentage? Standard is reset) this.currentHealth = this.baseStats.health; } /** * Adds XP to the *current* class. */ gainExperience(amount) { const mastery = this.classMastery[this.activeClassId]; mastery.xp += amount; // Level up logic would be handled by a system checking XP curves } getLevel() { return this.classMastery[this.activeClassId].level; } }