Release Healer Man 0.1.7

This commit is contained in:
phenom committed 2026-08-22 15:53:43 -04:00
1 parent b12fb84859
commit eca6b5db9b
99 files changed
+1931 -150

No files matched your search

+58 -11
View File
@@ -4,14 +4,18 @@ import {
learnedPartyTalentSelections,
upcomingPartyTalentSelections,
type PartyTalentSelection,
} from "../game/partyTalents";
} from "../game/partyTalentUi";
import {
PARTY_ROLE_LABELS,
usePartyStore,
type PartyCommand,
type PartyMember,
} from "../game/partyStore";
import { talentTreeById } from "../game/talentCatalog";
import {
loadTalentUiCatalog,
talentUiTreeById,
type TalentUiCatalog,
} from "../game/talentUiCatalog";
import { useGameStore } from "../game/store";
import { useMenuController, type MenuAction } from "../input/useMenuController";
import { ControllerButton } from "./ControllerButton";
@@ -70,6 +74,8 @@ function PartyManagementDialog() {
const command = usePartyStore((state) => state.command);
const openOverlay = useGameStore((state) => state.openOverlay);
const [inspectedMemberId, setInspectedMemberId] = useState(() => members[0]?.id ?? "");
const [talentCatalog, setTalentCatalog] = useState<TalentUiCatalog | null>(null);
const [talentCatalogErrorClassId, setTalentCatalogErrorClassId] = useState<string | null>(null);
const close = useCallback(() => openOverlay("pause"), [openOverlay]);
useEffect(() => {
@@ -79,13 +85,45 @@ function PartyManagementDialog() {
}, [inspectedMemberId, members]);
const inspectedMember = members.find((member) => member.id === inspectedMemberId) ?? members[0] ?? null;
const learned = useMemo(() => inspectedMember
? learnedPartyTalentSelections(inspectedMember.classId, inspectedMember.specialization, inspectedMember.level)
: [], [inspectedMember]);
useEffect(() => {
const classId = inspectedMember?.classId;
if (!classId || classId.startsWith("rom-")) {
setTalentCatalog(null);
setTalentCatalogErrorClassId(null);
return;
}
let active = true;
setTalentCatalogErrorClassId(null);
void loadTalentUiCatalog(classId).then((catalog) => {
if (active) setTalentCatalog(catalog);
}).catch(() => {
if (!active) return;
setTalentCatalog(null);
setTalentCatalogErrorClassId(classId);
});
return () => { active = false; };
}, [inspectedMember?.classId]);
const activeTalentCatalog = inspectedMember && talentCatalog?.classId === inspectedMember.classId
? talentCatalog
: null;
const learned = useMemo(() => inspectedMember && activeTalentCatalog
? learnedPartyTalentSelections(
activeTalentCatalog,
inspectedMember.classId,
inspectedMember.specialization,
inspectedMember.level,
)
: [], [activeTalentCatalog, inspectedMember]);
const currentTalents = useMemo(() => currentTalentRanks(learned), [learned]);
const upcomingTalents = useMemo(() => inspectedMember
? upcomingPartyTalentSelections(inspectedMember.classId, inspectedMember.specialization, inspectedMember.level, 3)
: [], [inspectedMember]);
const upcomingTalents = useMemo(() => inspectedMember && activeTalentCatalog
? upcomingPartyTalentSelections(
activeTalentCatalog,
inspectedMember.classId,
inspectedMember.specialization,
inspectedMember.level,
3,
)
: [], [activeTalentCatalog, inspectedMember]);
const actions = useMemo<MenuAction[]>(() => [
...members.map((member) => ({
@@ -106,7 +144,9 @@ function PartyManagementDialog() {
const memberClass = inspectedMember ? classById(inspectedMember.classId) : null;
const memberRace = inspectedMember ? raceById(inspectedMember.raceId) : null;
const primaryTree = inspectedMember ? talentTreeById(inspectedMember.talentTreeId) : null;
const primaryTree = inspectedMember && activeTalentCatalog
? talentUiTreeById(activeTalentCatalog, inspectedMember.talentTreeId)
: null;
const primaryPoints = inspectedMember
? learned.filter((selection) => selection.treeId === inspectedMember.talentTreeId).length
: 0;
@@ -210,7 +250,14 @@ function PartyManagementDialog() {
</header>
<div className="party-management__talent-list">
{currentTalents.map((selection) => <TalentSelectionCard key={selection.nodeId} selection={selection} />)}
{!currentTalents.length && (
{!activeTalentCatalog && (
<p className="party-management__empty-talents">
{talentCatalogErrorClassId === inspectedMember.classId
? "Talent details are temporarily unavailable."
: "Preparing this class's talent catalog…"}
</p>
)}
{activeTalentCatalog && !currentTalents.length && (
<p className="party-management__empty-talents">
Talent training begins at level 10. This build will advance automatically with you.
</p>
@@ -227,7 +274,7 @@ function PartyManagementDialog() {
{upcomingTalents.map((selection) => (
<TalentSelectionCard key={`${selection.level}-${selection.nodeId}`} selection={selection} upcoming />
))}
{!upcomingTalents.length && (
{activeTalentCatalog && !upcomingTalents.length && (
<p className="party-management__empty-talents">This party member has completed the level 80 talent plan.</p>
)}
</div>