aether-shards/src/units/Explorer.js

115 lines
3 KiB
JavaScript
Raw Normal View History

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;
}
}