Add Pathfinder 2e game system mode
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:
@@ -1,21 +1,48 @@
|
||||
export type ConditionId =
|
||||
| "blinded"
|
||||
| "charmed"
|
||||
| "clumsy"
|
||||
| "concealed"
|
||||
| "confused"
|
||||
| "controlled"
|
||||
| "dazzled"
|
||||
| "deafened"
|
||||
| "doomed"
|
||||
| "drained"
|
||||
| "dying"
|
||||
| "enfeebled"
|
||||
| "exhaustion"
|
||||
| "fascinated"
|
||||
| "fatigued"
|
||||
| "fleeing"
|
||||
| "frightened"
|
||||
| "grabbed"
|
||||
| "grappled"
|
||||
| "hidden"
|
||||
| "immobilized"
|
||||
| "incapacitated"
|
||||
| "invisible"
|
||||
| "off-guard"
|
||||
| "paralyzed"
|
||||
| "petrified"
|
||||
| "poisoned"
|
||||
| "prone"
|
||||
| "quickened"
|
||||
| "restrained"
|
||||
| "sapped"
|
||||
| "sickened"
|
||||
| "slowed"
|
||||
| "slowed-pf2e"
|
||||
| "stunned"
|
||||
| "unconscious";
|
||||
| "stupefied"
|
||||
| "unconscious"
|
||||
| "undetected"
|
||||
| "wounded";
|
||||
|
||||
export interface ConditionEntry {
|
||||
readonly id: ConditionId;
|
||||
readonly value?: number;
|
||||
}
|
||||
|
||||
import type { RulesEdition } from "./rules-edition.js";
|
||||
|
||||
@@ -24,20 +51,24 @@ export interface ConditionDefinition {
|
||||
readonly label: string;
|
||||
readonly description: string;
|
||||
readonly description5e: string;
|
||||
readonly descriptionPf2e?: string;
|
||||
readonly iconName: string;
|
||||
readonly color: string;
|
||||
/** When set, the condition only appears in this edition's picker. */
|
||||
readonly edition?: RulesEdition;
|
||||
/** When set, the condition only appears in these systems' pickers. */
|
||||
readonly systems?: readonly RulesEdition[];
|
||||
readonly valued?: boolean;
|
||||
}
|
||||
|
||||
export function getConditionDescription(
|
||||
def: ConditionDefinition,
|
||||
edition: RulesEdition,
|
||||
): string {
|
||||
if (edition === "pf2e" && def.descriptionPf2e) return def.descriptionPf2e;
|
||||
return edition === "5e" ? def.description5e : def.description;
|
||||
}
|
||||
|
||||
export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
// ── Shared conditions (D&D + PF2e) ──
|
||||
{
|
||||
id: "blinded",
|
||||
label: "Blinded",
|
||||
@@ -45,6 +76,8 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Can't see. Auto-fail sight checks. Attacks have Disadvantage; attacks against have Advantage.",
|
||||
description5e:
|
||||
"Can't see. Auto-fail sight checks. Attacks have Disadvantage; attacks against have Advantage.",
|
||||
descriptionPf2e:
|
||||
"Can't see. All terrain is difficult terrain. –4 status penalty to Perception checks involving sight. Immune to visual effects. Auto-fail checks requiring sight. Off-guard.",
|
||||
iconName: "EyeOff",
|
||||
color: "neutral",
|
||||
},
|
||||
@@ -57,12 +90,15 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Can't attack or target the charmer with harmful abilities. Charmer has Advantage on social checks.",
|
||||
iconName: "Heart",
|
||||
color: "pink",
|
||||
systems: ["5e", "5.5e"],
|
||||
},
|
||||
{
|
||||
id: "deafened",
|
||||
label: "Deafened",
|
||||
description: "Can't hear. Auto-fail hearing checks.",
|
||||
description5e: "Can't hear. Auto-fail hearing checks.",
|
||||
descriptionPf2e:
|
||||
"Can't hear. –2 status penalty to Perception checks and Initiative. Auto-fail hearing checks. Immune to auditory effects.",
|
||||
iconName: "EarOff",
|
||||
color: "neutral",
|
||||
},
|
||||
@@ -75,6 +111,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"L1: Disadvantage on ability checks\nL2: Speed halved\nL3: Disadvantage on attacks and saves\nL4: HP max halved\nL5: Speed 0\nL6: Death\nLong rest removes 1 level.",
|
||||
iconName: "BatteryLow",
|
||||
color: "amber",
|
||||
systems: ["5e", "5.5e"],
|
||||
},
|
||||
{
|
||||
id: "frightened",
|
||||
@@ -83,8 +120,11 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Disadvantage on ability checks and attacks while source of fear is in line of sight. Can't willingly move closer to the source.",
|
||||
description5e:
|
||||
"Disadvantage on ability checks and attacks while source of fear is in line of sight. Can't willingly move closer to the source.",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to all checks and DCs (X = value). Can't willingly approach the source.",
|
||||
iconName: "Siren",
|
||||
color: "orange",
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "grappled",
|
||||
@@ -95,6 +135,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Speed 0. Ends if grappler is Incapacitated or moved out of reach.",
|
||||
iconName: "Hand",
|
||||
color: "neutral",
|
||||
systems: ["5e", "5.5e"],
|
||||
},
|
||||
{
|
||||
id: "incapacitated",
|
||||
@@ -104,6 +145,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
description5e: "Can't take Actions or Reactions.",
|
||||
iconName: "Ban",
|
||||
color: "gray",
|
||||
systems: ["5e", "5.5e"],
|
||||
},
|
||||
{
|
||||
id: "invisible",
|
||||
@@ -112,6 +154,8 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Can't be seen. Advantage on Initiative. Not affected by effects requiring sight (unless caster sees you). Attacks have Advantage; attacks against have Disadvantage.",
|
||||
description5e:
|
||||
"Impossible to see without magic or special sense. Heavily Obscured. Attacks have Advantage; attacks against have Disadvantage.",
|
||||
descriptionPf2e:
|
||||
"Can't be seen except by special senses. Undetected to everyone. Can't be targeted except by effects that don't require sight.",
|
||||
iconName: "Ghost",
|
||||
color: "violet",
|
||||
},
|
||||
@@ -122,6 +166,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Incapacitated. Can't move or speak. Auto-fail Str/Dex saves. Attacks against have Advantage. Hits within 5 ft. are critical.",
|
||||
description5e:
|
||||
"Incapacitated. Can't move or speak. Auto-fail Str/Dex saves. Attacks against have Advantage. Hits within 5 ft. are critical.",
|
||||
descriptionPf2e: "Can't act. Off-guard. –4 status penalty to AC.",
|
||||
iconName: "ZapOff",
|
||||
color: "yellow",
|
||||
},
|
||||
@@ -132,6 +177,8 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Turned to stone. Weight \u00D710. Incapacitated. Can't move or speak. Attacks against have Advantage. Auto-fail Str/Dex saves. Resistant to all damage. Immune to poison and disease.",
|
||||
description5e:
|
||||
"Turned to stone. Weight \u00D710. Incapacitated. Can't move or speak. Attacks against have Advantage. Auto-fail Str/Dex saves. Resistant to all damage. Immune to poison and disease.",
|
||||
descriptionPf2e:
|
||||
"Can't act. Can't sense anything. AC = 9. Hardness 8. Immune to most effects.",
|
||||
iconName: "Gem",
|
||||
color: "slate",
|
||||
},
|
||||
@@ -142,6 +189,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
description5e: "Disadvantage on attack rolls and ability checks.",
|
||||
iconName: "Droplet",
|
||||
color: "green",
|
||||
systems: ["5e", "5.5e"],
|
||||
},
|
||||
{
|
||||
id: "prone",
|
||||
@@ -150,6 +198,8 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Can only crawl (costs extra movement). Disadvantage on attacks. Attacks within 5 ft. have Advantage; ranged attacks have Disadvantage. Standing up costs half movement.",
|
||||
description5e:
|
||||
"Can only crawl (costs extra movement). Disadvantage on attacks. Attacks within 5 ft. have Advantage; ranged attacks have Disadvantage. Standing up costs half movement.",
|
||||
descriptionPf2e:
|
||||
"Off-guard. –2 circumstance penalty to attack rolls. Only movement is Crawl and Stand. +1 circumstance bonus to AC vs. ranged attacks, –2 vs. melee.",
|
||||
iconName: "ArrowDown",
|
||||
color: "neutral",
|
||||
},
|
||||
@@ -160,6 +210,8 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Speed is 0. Attacks have Disadvantage. Attacks against have Advantage. Disadvantage on Dex saves.",
|
||||
description5e:
|
||||
"Speed is 0. Attacks have Disadvantage. Attacks against have Advantage. Disadvantage on Dex saves.",
|
||||
descriptionPf2e:
|
||||
"Off-guard. Immobilized. Can't use any actions with the attack trait except to attempt to Escape.",
|
||||
iconName: "Link",
|
||||
color: "neutral",
|
||||
},
|
||||
@@ -171,7 +223,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
description5e: "",
|
||||
iconName: "ShieldMinus",
|
||||
color: "amber",
|
||||
edition: "5.5e",
|
||||
systems: ["5.5e"],
|
||||
},
|
||||
{
|
||||
id: "slowed",
|
||||
@@ -181,7 +233,7 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
description5e: "",
|
||||
iconName: "Snail",
|
||||
color: "sky",
|
||||
edition: "5.5e",
|
||||
systems: ["5.5e"],
|
||||
},
|
||||
{
|
||||
id: "stunned",
|
||||
@@ -190,8 +242,11 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Incapacitated (can't act or speak). Auto-fail Str/Dex saves. Attacks against have Advantage.",
|
||||
description5e:
|
||||
"Incapacitated. Can't move. Can speak only falteringly. Auto-fail Str/Dex saves. Attacks against have Advantage.",
|
||||
descriptionPf2e:
|
||||
"Can't act. –X value to actions per turn while the value counts down.",
|
||||
iconName: "Sparkles",
|
||||
color: "yellow",
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "unconscious",
|
||||
@@ -200,9 +255,261 @@ export const CONDITION_DEFINITIONS: readonly ConditionDefinition[] = [
|
||||
"Incapacitated. Speed 0. Can't move or speak. Unaware of surroundings. Drops held items, falls Prone. Auto-fail Str/Dex saves. Attacks against have Advantage. Hits within 5 ft. are critical.",
|
||||
description5e:
|
||||
"Incapacitated. Speed 0. Can't move or speak. Unaware of surroundings. Drops held items, falls Prone. Auto-fail Str/Dex saves. Attacks against have Advantage. Hits within 5 ft. are critical.",
|
||||
descriptionPf2e:
|
||||
"Can't act. Off-guard. –4 status penalty to AC. –3 to Perception. Fall prone, drop items.",
|
||||
iconName: "Moon",
|
||||
color: "indigo",
|
||||
},
|
||||
// ── PF2e-only conditions ──
|
||||
{
|
||||
id: "clumsy",
|
||||
label: "Clumsy",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to Dex-based checks and DCs, including AC, Reflex saves, and ranged attack rolls.",
|
||||
iconName: "Footprints",
|
||||
color: "amber",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "concealed",
|
||||
label: "Concealed",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"DC 5 flat check for targeted attacks. Doesn't change which creatures can see you.",
|
||||
iconName: "CloudFog",
|
||||
color: "slate",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "confused",
|
||||
label: "Confused",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Off-guard. Can't Delay, Ready, or use reactions. GM determines targets randomly. Flat check DC 11 to act normally each turn.",
|
||||
iconName: "CircleHelp",
|
||||
color: "pink",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "controlled",
|
||||
label: "Controlled",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Another creature determines your actions. You gain no actions of your own.",
|
||||
iconName: "Drama",
|
||||
color: "pink",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "dazzled",
|
||||
label: "Dazzled",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"All creatures and objects are concealed to you. DC 5 flat check for targeted attacks requiring sight.",
|
||||
iconName: "Sun",
|
||||
color: "yellow",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "doomed",
|
||||
label: "Doomed",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Die at dying X (where X = 4 – doomed value instead of dying 4). Decreases by 1 on full night's rest.",
|
||||
iconName: "Skull",
|
||||
color: "red",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "drained",
|
||||
label: "Drained",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to Con-based checks and DCs. Lose X × Hit Die in max HP. Decreases by 1 on full night's rest.",
|
||||
iconName: "Droplets",
|
||||
color: "red",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "dying",
|
||||
label: "Dying",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Unconscious. Make recovery checks at start of turn. At dying 4 (or 4 – doomed), you die.",
|
||||
iconName: "HeartPulse",
|
||||
color: "red",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "enfeebled",
|
||||
label: "Enfeebled",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to Str-based rolls, including melee attack and damage rolls.",
|
||||
iconName: "TrendingDown",
|
||||
color: "amber",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "fascinated",
|
||||
label: "Fascinated",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–2 status penalty to all checks. Can't use hostile actions. Ends if hostile action is used against you.",
|
||||
iconName: "Eye",
|
||||
color: "violet",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "fatigued",
|
||||
label: "Fatigued",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–1 status penalty to AC and saves. Can't use exploration activities while traveling. Recover after a full night's rest.",
|
||||
iconName: "BatteryLow",
|
||||
color: "amber",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "fleeing",
|
||||
label: "Fleeing",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Must spend actions to move away from the source. Can't Delay or Ready.",
|
||||
iconName: "PersonStanding",
|
||||
color: "orange",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "grabbed",
|
||||
label: "Grabbed",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Immobilized. Off-guard. Can't use actions with the move trait unless to Break Grapple.",
|
||||
iconName: "Hand",
|
||||
color: "neutral",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "hidden",
|
||||
label: "Hidden",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Known location but can't be seen. DC 11 flat check to target. Can use Seek to find.",
|
||||
iconName: "EyeOff",
|
||||
color: "slate",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "immobilized",
|
||||
label: "Immobilized",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Can't use any action with the move trait to change position.",
|
||||
iconName: "Anchor",
|
||||
color: "neutral",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "off-guard",
|
||||
label: "Off-Guard",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e: "–2 circumstance penalty to AC. (Formerly flat-footed.)",
|
||||
iconName: "ShieldOff",
|
||||
color: "amber",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "quickened",
|
||||
label: "Quickened",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Gain 1 extra action at the start of your turn each round (limited uses specified by the effect).",
|
||||
iconName: "Zap",
|
||||
color: "green",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "sickened",
|
||||
label: "Sickened",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to all checks and DCs. Can't willingly ingest anything. Reduce by retching (Fortitude save).",
|
||||
iconName: "Droplet",
|
||||
color: "green",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "slowed-pf2e",
|
||||
label: "Slowed",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e: "Lose X actions at the start of your turn each round.",
|
||||
iconName: "Snail",
|
||||
color: "sky",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "stupefied",
|
||||
label: "Stupefied",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"–X status penalty to Int/Wis/Cha-based checks and DCs, including spell attack rolls and spell DCs. DC 5 + X flat check to cast spells or lose the spell.",
|
||||
iconName: "BrainCog",
|
||||
color: "violet",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
{
|
||||
id: "undetected",
|
||||
label: "Undetected",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Location unknown. Must pick a square to target; DC 11 flat check. Attacker is off-guard against your attacks.",
|
||||
iconName: "Ghost",
|
||||
color: "violet",
|
||||
systems: ["pf2e"],
|
||||
},
|
||||
{
|
||||
id: "wounded",
|
||||
label: "Wounded",
|
||||
description: "",
|
||||
description5e: "",
|
||||
descriptionPf2e:
|
||||
"Next time you gain dying, add wounded value to dying value. Wounded 1 when you recover from dying; increases if already wounded.",
|
||||
iconName: "HeartCrack",
|
||||
color: "red",
|
||||
systems: ["pf2e"],
|
||||
valued: true,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const VALID_CONDITION_IDS: ReadonlySet<string> = new Set(
|
||||
@@ -213,6 +520,6 @@ export function getConditionsForEdition(
|
||||
edition: RulesEdition,
|
||||
): readonly ConditionDefinition[] {
|
||||
return CONDITION_DEFINITIONS.filter(
|
||||
(d) => d.edition === undefined || d.edition === edition,
|
||||
(d) => d.systems === undefined || d.systems.includes(edition),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user