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:
@@ -1,4 +1,13 @@
|
||||
import type { Monster, Spell, MagicItem } from './types';
|
||||
import type {
|
||||
Monster,
|
||||
Spell,
|
||||
MagicItem,
|
||||
Weapon5e,
|
||||
Armor5e,
|
||||
Feat5e,
|
||||
Condition5e,
|
||||
CompendiumEntry,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Lazy, cached loaders for the SRD datasets. Dynamic `import()` keeps the
|
||||
@@ -33,6 +42,54 @@ export async function loadItems(): Promise<MagicItem[]> {
|
||||
return itemsCache;
|
||||
}
|
||||
|
||||
// ---- Additional 5e categories (bundled — these files are small) ----
|
||||
const cache = new Map<string, unknown[]>();
|
||||
|
||||
export async function loadWeapons5e(): Promise<Weapon5e[]> {
|
||||
if (!cache.has('w5e')) {
|
||||
const mod = await import('@/data/srd/weapons-full.json');
|
||||
cache.set('w5e', mod.default as unknown as Weapon5e[]);
|
||||
}
|
||||
return cache.get('w5e') as Weapon5e[];
|
||||
}
|
||||
|
||||
export async function loadArmor5e(): Promise<Armor5e[]> {
|
||||
if (!cache.has('a5e')) {
|
||||
const mod = await import('@/data/srd/equipment.json');
|
||||
cache.set('a5e', (mod.default as { armor: Armor5e[] }).armor);
|
||||
}
|
||||
return cache.get('a5e') as Armor5e[];
|
||||
}
|
||||
|
||||
export async function loadFeats5e(): Promise<Feat5e[]> {
|
||||
if (!cache.has('f5e')) {
|
||||
const mod = await import('@/data/srd/mpmb-feats.json');
|
||||
const obj = mod.default as Record<string, Feat5e>;
|
||||
cache.set('f5e', Object.values(obj).sort((a, b) => a.name.localeCompare(b.name)));
|
||||
}
|
||||
return cache.get('f5e') as Feat5e[];
|
||||
}
|
||||
|
||||
export async function loadConditions5e(): Promise<Condition5e[]> {
|
||||
if (!cache.has('c5e')) {
|
||||
const mod = await import('@/data/srd/conditions.json');
|
||||
cache.set('c5e', mod.default as unknown as Condition5e[]);
|
||||
}
|
||||
return cache.get('c5e') as Condition5e[];
|
||||
}
|
||||
|
||||
// ---- PF2e categories (static assets fetched at runtime; large files) ----
|
||||
const pf2eCache = new Map<string, CompendiumEntry[]>();
|
||||
|
||||
export async function loadPf2e(file: string): Promise<CompendiumEntry[]> {
|
||||
if (!pf2eCache.has(file)) {
|
||||
const res = await fetch(`${import.meta.env.BASE_URL}data/pf2e/${file}.json`);
|
||||
if (!res.ok) throw new Error(`Failed to load PF2e ${file} (${res.status})`);
|
||||
pf2eCache.set(file, (await res.json()) as CompendiumEntry[]);
|
||||
}
|
||||
return pf2eCache.get(file)!;
|
||||
}
|
||||
|
||||
/** Build a combat-ready stat block summary from a monster. */
|
||||
export function monsterToCombatant(m: Monster): {
|
||||
name: string;
|
||||
|
||||
@@ -73,3 +73,39 @@ export interface MagicItem {
|
||||
}
|
||||
|
||||
export type CompendiumKind = 'monsters' | 'spells' | 'items';
|
||||
|
||||
/** A loosely-typed entry for the generic, registry-driven categories. */
|
||||
export type CompendiumEntry = Record<string, unknown> & { name: string; slug?: string };
|
||||
|
||||
export interface Weapon5e {
|
||||
name: string;
|
||||
slug: string;
|
||||
category?: string;
|
||||
cost?: string;
|
||||
damage_dice?: string;
|
||||
damage_type?: string;
|
||||
weight?: string | number;
|
||||
properties?: string[];
|
||||
}
|
||||
|
||||
export interface Armor5e {
|
||||
name: string;
|
||||
type?: string;
|
||||
ac?: string;
|
||||
dexCap?: number | null;
|
||||
stealthPenalty?: boolean;
|
||||
weight?: number;
|
||||
cost?: string;
|
||||
}
|
||||
|
||||
export interface Feat5e {
|
||||
name: string;
|
||||
description?: string;
|
||||
source?: { source: string; page: number }[];
|
||||
}
|
||||
|
||||
export interface Condition5e {
|
||||
name: string;
|
||||
description?: string;
|
||||
effects?: string[];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user