import { lazy, Suspense, useMemo } from "react";
import { classById } from "../app/characterCatalog";
import { useShellStore } from "../app/shellStore";
import { useCombatStore } from "../game/combatStore";
import {
abilityAtLevel,
abilityRankForLevel,
} from "../game/abilityCatalog";
import { useGameStore } from "../game/store";
import { OptionsPanel } from "./OptionsPanel";
import { AbilityBindingsPanel } from "./AbilityBindingsPanel";
import { SpellbookPanel } from "./SpellbookPanel";
import { EquipmentPanel } from "./EquipmentPanel";
import { RomSkillsPanel } from "./RomSkillsPanel";
import { getLoadedTalentGameplayPanel, loadTalentGameplayPanel } from "./talentGameplayResources";
import {
getLoadedBossGuidePanel,
getLoadedPartyManagementPanel,
loadBossGuidePanel,
loadPartyManagementPanel,
} from "./gameplayResources";
const PartyManagementPanel = lazy(() => loadPartyManagementPanel().then((module) => ({ default: module.PartyManagementPanel })));
const BossGuidePanel = lazy(() => loadBossGuidePanel().then((module) => ({ default: module.BossGuidePanel })));
const TalentGameplayPanel = lazy(loadTalentGameplayPanel);
function TalentsPanelLoading() {
const openOverlay = useGameStore((state) => state.openOverlay);
return (
Preparing talent trees…
);
}
/** Maps the data-driven combat catalogs into the full-screen game panels. */
export function GameplayPanels() {
const classId = useCombatStore((state) => state.classId);
const level = useCombatStore((state) => state.level);
const abilities = useCombatStore((state) => state.abilities);
const talentRanks = useCombatStore((state) => state.talentRanks);
const settings = useCombatStore((state) => state.settings);
const presentationSettings = useShellStore((state) => state.combatPresentationSettings);
const overlay = useGameStore((state) => state.overlay);
const classDefinition = classById(classId);
const PreloadedTalentGameplayPanel = getLoadedTalentGameplayPanel();
const PreloadedPartyManagementPanel = getLoadedPartyManagementPanel();
const PreloadedBossGuidePanel = getLoadedBossGuidePanel();
const spellbookAbilities = useMemo(() => [...abilities]
.sort((left, right) => left.unlockLevel - right.unlockLevel)
.map((catalogAbility) => {
const learnedTalentRank = catalogAbility.talentEntryId === undefined
? undefined
: talentRanks[`coa-entry-${catalogAbility.talentEntryId}`] ?? 0;
const ability = abilityAtLevel(catalogAbility, level, learnedTalentRank);
const activeRank = abilityRankForLevel(catalogAbility, level, learnedTalentRank);
return {
id: ability.id,
name: ability.name,
description: ability.description,
level: ability.unlockLevel,
color: classDefinition.color,
sigil: ability.sigil,
iconUrl: ability.icon,
school: classDefinition.name,
resourceCost: ability.cost.amount,
resourceLabel: useCombatStore.getState().resourceName,
cooldownSeconds: ability.cooldownMs / 1_000,
castSeconds: ability.castTimeMs / 1_000,
range: ability.range.max,
known: catalogAbility.talentEntryId === undefined || Boolean(learnedTalentRank),
talentLocked: catalogAbility.talentEntryId !== undefined,
passive: ability.passive,
rank: activeRank?.rank,
rankCount: catalogAbility.ranks?.length,
ranks: catalogAbility.ranks?.map((rank) => ({
rank: rank.rank,
level: rank.level,
spellId: rank.spellId,
description: rank.description,
})),
};
}), [abilities, classDefinition.color, classDefinition.name, level, talentRanks]);
const castAbility = (abilityId: string) => {
const game = useGameStore.getState();
game.closeOverlay();
useCombatStore.getState().castAbility(abilityId, game.playerPosition, Date.now());
};
return (
<>
{overlay === "party"
? PreloadedPartyManagementPanel
?
:
: null}
{overlay === "boss-guide"
? PreloadedBossGuidePanel
?
:
: null}
{overlay === "talents"
? classId.startsWith("rom-")
?
: PreloadedTalentGameplayPanel
?
: }>
: null}
useCombatStore.getState().updateSettings(patch)}
onReset={() => useCombatStore.getState().resetSettings()}
presentationSettings={presentationSettings}
onPresentationChange={(patch) => useShellStore.getState().updateCombatPresentationSettings(patch)}
onPresentationReset={() => useShellStore.getState().resetCombatPresentationSettings()}
/>
>
);
}