56 lines
2.1 KiB
TypeScript
56 lines
2.1 KiB
TypeScript
import { use, useMemo } from "react";
|
|
import { classById, type CoaClassId } from "../app/characterCatalog";
|
|
import { useCombatStore } from "../game/combatStore";
|
|
import {
|
|
runtimeSpentTalentPointsInTree,
|
|
runtimeUnspentCoaEssence,
|
|
runtimeUnspentTalentPoints,
|
|
} from "../game/talentRuntimeCatalog";
|
|
import { loadedTalentUiCatalog, loadTalentUiCatalog, talentUiNodesForTree } from "../game/talentUiCatalog";
|
|
import { TalentsPanel } from "./TalentsPanel";
|
|
|
|
function treeSigil(name: string): string {
|
|
return name.split(/\s+/).map((word) => word[0]).join("").slice(0, 2).toUpperCase();
|
|
}
|
|
|
|
export default function TalentGameplayPanel({ readOnly = false, open, onClose }: {
|
|
readOnly?: boolean;
|
|
open?: boolean;
|
|
onClose?: () => void;
|
|
} = {}) {
|
|
const classId = useCombatStore((state) => state.classId);
|
|
const level = useCombatStore((state) => state.level);
|
|
const talentRanks = useCombatStore((state) => state.talentRanks);
|
|
const classDefinition = classById(classId);
|
|
const catalog = loadedTalentUiCatalog(classId) ?? use(loadTalentUiCatalog(classId));
|
|
const talentTrees = useMemo(() => catalog.trees.map((tree) => ({
|
|
id: tree.id,
|
|
name: tree.name,
|
|
description: tree.description,
|
|
points: runtimeSpentTalentPointsInTree(talentRanks, tree.id),
|
|
color: classDefinition.color,
|
|
sigil: treeSigil(tree.name),
|
|
iconUrl: tree.icon,
|
|
backgroundUrl: tree.background,
|
|
nodes: talentUiNodesForTree(catalog, tree.id),
|
|
})), [catalog, classDefinition.color, talentRanks]);
|
|
const coaEssence = classDefinition.mode === "conquest"
|
|
? runtimeUnspentCoaEssence(level, talentRanks, classId as CoaClassId)
|
|
: null;
|
|
|
|
return <TalentsPanel
|
|
trees={talentTrees}
|
|
ranks={talentRanks}
|
|
classId={classId}
|
|
playerLevel={level}
|
|
availablePoints={runtimeUnspentTalentPoints(level, talentRanks, classId)}
|
|
abilityEssence={coaEssence?.ability}
|
|
talentEssence={coaEssence?.talent}
|
|
onInvest={(nodeId) => { if (!readOnly) useCombatStore.getState().allocateTalent(nodeId); }}
|
|
onReset={() => { if (!readOnly) useCombatStore.getState().resetTalents(); }}
|
|
readOnly={readOnly}
|
|
open={open}
|
|
onClose={onClose}
|
|
/>;
|
|
}
|