Add Pathfinder 2e game system mode
All checks were successful
CI / check (push) Successful in 2m21s
CI / build-image (push) Successful in 24s

Implements PF2e as an alternative game system alongside D&D 5e/5.5e.
Settings modal "Game System" selector switches conditions, bestiary,
stat block layout, and initiative calculation between systems.

- Valued conditions with increment/decrement UX (Clumsy 2, Frightened 3)
- 2,502 PF2e creatures from bundled search index (77 sources)
- PF2e stat block: level, traits, Perception, Fort/Ref/Will, ability mods
- Perception-based initiative rolling
- System-scoped source cache (D&D and PF2e sources don't collide)
- Backwards-compatible condition rehydration (ConditionId[] → ConditionEntry[])
- Difficulty indicator hidden in PF2e mode (excluded from MVP)

Closes dostulata/initiative#19

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-04-07 01:26:22 +02:00
parent 8f6eebc43b
commit e62c49434c
67 changed files with 27758 additions and 527 deletions

View File

@@ -3,23 +3,30 @@ import { useId, useState } from "react";
import { useAdapters } from "../contexts/adapter-context.js";
import { useBestiaryContext } from "../contexts/bestiary-context.js";
import { useBulkImportContext } from "../contexts/bulk-import-context.js";
import { useRulesEditionContext } from "../contexts/rules-edition-context.js";
import { useSidePanelContext } from "../contexts/side-panel-context.js";
import { Button } from "./ui/button.js";
import { Input } from "./ui/input.js";
const DEFAULT_BASE_URL =
const DND_BASE_URL =
"https://raw.githubusercontent.com/5etools-mirror-3/5etools-src/main/data/bestiary/";
const PF2E_BASE_URL =
"https://raw.githubusercontent.com/Pf2eToolsOrg/Pf2eTools/dev/data/bestiary/";
export function BulkImportPrompt() {
const { bestiaryIndex } = useAdapters();
const { bestiaryIndex, pf2eBestiaryIndex } = useAdapters();
const { fetchAndCacheSource, isSourceCached, refreshCache } =
useBestiaryContext();
const { state: importState, startImport, reset } = useBulkImportContext();
const { dismissPanel } = useSidePanelContext();
const { edition } = useRulesEditionContext();
const [baseUrl, setBaseUrl] = useState(DEFAULT_BASE_URL);
const indexPort = edition === "pf2e" ? pf2eBestiaryIndex : bestiaryIndex;
const defaultUrl = edition === "pf2e" ? PF2E_BASE_URL : DND_BASE_URL;
const [baseUrl, setBaseUrl] = useState(defaultUrl);
const baseUrlId = useId();
const totalSources = bestiaryIndex.getAllSourceCodes().length;
const totalSources = indexPort.getAllSourceCodes().length;
const handleStart = (url: string) => {
startImport(url, fetchAndCacheSource, isSourceCached, refreshCache);