No attacks defined.
diff --git a/src/features/characters/sheet/FeatPickerModal.tsx b/src/features/characters/sheet/FeatPickerModal.tsx new file mode 100644 index 0000000..6a30d53 --- /dev/null +++ b/src/features/characters/sheet/FeatPickerModal.tsx @@ -0,0 +1,54 @@ +import { useEffect, useMemo, useState } from 'react'; +import { loadFeats5e } from '@/lib/compendium'; +import type { Feat5e } from '@/lib/compendium/types'; +import { sourceLabel } from '@/lib/compendium/mpmb'; +import { newId } from '@/lib/ids'; +import type { Feat } from '@/lib/schemas'; +import { Modal } from '@/components/ui/Modal'; +import { Button } from '@/components/ui/Button'; +import { Input } from '@/components/ui/Input'; + +/** Browse the 5e feat compendium (PHB/XGtE/TCE) and add one as a tracked feat. */ +export function FeatPickerModal({ onPick, onClose }: { onPick: (f: Feat) => void; onClose: () => void }) { + const [feats, setFeats] = useStateLoading…
} + {results.map((f) => ( + + ))} +No feats or features tracked yet.
diff --git a/src/features/characters/sheet/WeaponPickerModal.tsx b/src/features/characters/sheet/WeaponPickerModal.tsx new file mode 100644 index 0000000..bde476b --- /dev/null +++ b/src/features/characters/sheet/WeaponPickerModal.tsx @@ -0,0 +1,61 @@ +import { useEffect, useMemo, useState } from 'react'; +import { loadWeapons5e } from '@/lib/compendium'; +import type { Weapon5e } from '@/lib/compendium/types'; +import { newId } from '@/lib/ids'; +import type { Attack } from '@/lib/schemas'; +import { Modal } from '@/components/ui/Modal'; +import { Button } from '@/components/ui/Button'; +import { Input } from '@/components/ui/Input'; + +/** Default attack ability for a weapon: ranged/finesse → DEX, else STR. */ +function defaultAbility(w: Weapon5e): Attack['ability'] { + const props = (w.properties ?? []).map((p) => p.toLowerCase()); + const ranged = /ranged/i.test(w.category ?? '') || props.some((p) => p.startsWith('ammunition') || p.startsWith('thrown')); + if (ranged || props.some((p) => p.startsWith('finesse'))) return 'dex'; + return 'str'; +} + +function toAttack(w: Weapon5e): Attack { + return { + id: newId(), + name: w.name, + ability: defaultAbility(w), + rank: 'trained', + damageDice: w.damage_dice ?? '1d4', + damageType: w.damage_type ?? '', + itemBonus: 0, + addAbilityToDamage: true, + }; +} + +/** Pick a 5e weapon from the compendium; creates a ready-to-roll attack with correct dice. */ +export function WeaponPickerModal({ onPick, onClose }: { onPick: (a: Attack) => void; onClose: () => void }) { + const [weapons, setWeapons] = useStateLoading…
} + {results.map((w) => ( + + ))} +