Show inline on-hit effects on attack lines (e.g., "plus Grab"), frequency limits on abilities (e.g., "(1/day)"), and perception details text alongside senses. Strip redundant frequency lines from Foundry descriptions. Also add resilient PF2e source fetching: batched requests with retry, graceful handling of ad-blocker-blocked creature files (partial success with toast warning and re-fetch prompt for missing creatures). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
2.1 KiB
TypeScript
88 lines
2.1 KiB
TypeScript
import type {
|
|
Pf2eBestiaryIndex,
|
|
Pf2eBestiaryIndexEntry,
|
|
} from "@initiative/domain";
|
|
|
|
import rawIndex from "../../../../data/bestiary/pf2e-index.json";
|
|
|
|
interface CompactCreature {
|
|
readonly n: string;
|
|
readonly s: string;
|
|
readonly lv: number;
|
|
readonly ac: number;
|
|
readonly hp: number;
|
|
readonly pc: number;
|
|
readonly sz: string;
|
|
readonly tp: string;
|
|
readonly f: string;
|
|
readonly li: string;
|
|
}
|
|
|
|
interface CompactIndex {
|
|
readonly sources: Record<string, string>;
|
|
readonly creatures: readonly CompactCreature[];
|
|
}
|
|
|
|
function mapCreature(c: CompactCreature): Pf2eBestiaryIndexEntry {
|
|
return {
|
|
name: c.n,
|
|
source: c.s,
|
|
level: c.lv,
|
|
ac: c.ac,
|
|
hp: c.hp,
|
|
perception: c.pc,
|
|
size: c.sz,
|
|
type: c.tp,
|
|
};
|
|
}
|
|
|
|
let cachedIndex: Pf2eBestiaryIndex | undefined;
|
|
|
|
export function loadPf2eBestiaryIndex(): Pf2eBestiaryIndex {
|
|
if (cachedIndex) return cachedIndex;
|
|
|
|
const compact = rawIndex as unknown as CompactIndex;
|
|
cachedIndex = {
|
|
sources: compact.sources,
|
|
creatures: compact.creatures.map(mapCreature),
|
|
};
|
|
return cachedIndex;
|
|
}
|
|
|
|
export function getAllPf2eSourceCodes(): string[] {
|
|
const index = loadPf2eBestiaryIndex();
|
|
return Object.keys(index.sources);
|
|
}
|
|
|
|
export function getDefaultPf2eFetchUrl(
|
|
_sourceCode: string,
|
|
baseUrl?: string,
|
|
): string {
|
|
if (baseUrl !== undefined) {
|
|
return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
|
|
}
|
|
return "https://raw.githubusercontent.com/foundryvtt/pf2e/v13-dev/packs/pf2e/";
|
|
}
|
|
|
|
export function getCreaturePathsForSource(sourceCode: string): string[] {
|
|
const compact = rawIndex as unknown as CompactIndex;
|
|
return compact.creatures.filter((c) => c.s === sourceCode).map((c) => c.f);
|
|
}
|
|
|
|
export function getCreatureNamesByPaths(paths: string[]): Map<string, string> {
|
|
const compact = rawIndex as unknown as CompactIndex;
|
|
const pathSet = new Set(paths);
|
|
const result = new Map<string, string>();
|
|
for (const c of compact.creatures) {
|
|
if (pathSet.has(c.f)) {
|
|
result.set(c.f, c.n);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export function getPf2eSourceDisplayName(sourceCode: string): string {
|
|
const index = loadPf2eBestiaryIndex();
|
|
return index.sources[sourceCode] ?? sourceCode;
|
|
}
|