Phase 2: full compendium across all categories + PF2e data
- Scraped PF2e reference from Archives of Nethys ES into public/data/pf2e/ (spells, creatures, feats, equipment, weapons, armor, ancestries, heritages, backgrounds, archetypes, actions, conditions, deities) via scripts/fetch_pf2e.ts - Registry-driven compendium: system toggle + per-category nav + generic filters - 5e expanded: weapons, armor, feats, conditions added alongside spells/monsters/items - PF2e data served as static assets (fetched, not bundled) for fast native parse - Cross-links: add spell->spellbook / item->inventory to a campaign character; add monster/creature -> open encounter - Condition tooltips in combat sourced from the conditions glossary - Tests: registry filter unit tests, compendium e2e (browse + cross-link) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,7 @@ import { createRng } from '@/lib/rng';
|
||||
import { rollDice } from '@/lib/dice/notation';
|
||||
import { getSystem, getConditions, type SystemId } from '@/lib/rules';
|
||||
import { useCharacters } from '@/features/characters/hooks';
|
||||
import { useConditionGlossary } from './useConditionGlossary';
|
||||
import {
|
||||
addCombatant,
|
||||
applyDamage,
|
||||
@@ -25,6 +26,7 @@ import { NumberField } from '@/components/ui/NumberField';
|
||||
|
||||
export function EncounterTracker({ encounter, campaign }: { encounter: Encounter; campaign: Campaign }) {
|
||||
const characters = useCharacters(campaign.id);
|
||||
const glossary = useConditionGlossary(campaign.system);
|
||||
|
||||
const mutate = (fn: (e: Encounter) => Encounter) => {
|
||||
void encountersRepo.save(fn(encounter));
|
||||
@@ -87,6 +89,7 @@ export function EncounterTracker({ encounter, campaign }: { encounter: Encounter
|
||||
key={c.id}
|
||||
combatant={c}
|
||||
system={campaign.system}
|
||||
glossary={glossary}
|
||||
isCurrent={isActive && idx === encounter.turnIndex}
|
||||
onChange={(patch) => mutate((e) => updateCombatant(e, c.id, patch))}
|
||||
onDamage={(amt) => mutate((e) => updateCombatant(e, c.id, { hp: applyDamage(c, amt).hp }))}
|
||||
@@ -206,6 +209,7 @@ function AddCombatantBar({
|
||||
function CombatantRow({
|
||||
combatant: c,
|
||||
system,
|
||||
glossary,
|
||||
isCurrent,
|
||||
onChange,
|
||||
onDamage,
|
||||
@@ -215,6 +219,7 @@ function CombatantRow({
|
||||
}: {
|
||||
combatant: Combatant;
|
||||
system: SystemId;
|
||||
glossary: Map<string, string>;
|
||||
isCurrent: boolean;
|
||||
onChange: (patch: Partial<Combatant>) => void;
|
||||
onDamage: (amt: number) => void;
|
||||
@@ -251,7 +256,7 @@ function CombatantRow({
|
||||
<button
|
||||
key={`${cond.name}-${i}`}
|
||||
className="rounded-full bg-warning/15 px-2 py-0.5 text-xs text-warning hover:line-through"
|
||||
title="Click to remove"
|
||||
title={glossary.get(cond.name.toLowerCase()) || 'Click to remove'}
|
||||
onClick={() => onChange({ conditions: c.conditions.filter((_, j) => j !== i) })}
|
||||
>
|
||||
{cond.name}
|
||||
|
||||
Reference in New Issue
Block a user