export class SkillTree { constructor() { this.nodes = []; this.chosen = new Set(); } load(data) { this.nodes = data.nodes; } /** Returns nodes available to pick at next level-up (roots or children of chosen). */ getAvailable() { return this.nodes.filter(n => { if (this.chosen.has(n.id)) return false; if (n.parent === null) return true; return this.chosen.has(n.parent); }); } /** Apply a node's effect to the player stats object and mark it chosen. */ applyNode(nodeId, playerStats) { const node = this.nodes.find(n => n.id === nodeId); if (!node) return; const { stat, add, multiply } = node.effect; if (add !== undefined) { playerStats[stat] = (playerStats[stat] || 0) + add; } if (multiply !== undefined) { playerStats[stat] = (playerStats[stat] || 1) * multiply; } this.chosen.add(nodeId); return node; } reset() { this.chosen.clear(); } }