import type { BestiaryIndexEntry, Creature } from "@initiative/domain"; import { creatureId } from "@initiative/domain"; import rawBundled from "../../../../data/bestiary/dnd-bundled.json"; type RawBundledCreature = Omit & { id: string }; const SIZE_TO_CODE: Record = { Tiny: "T", Small: "S", Medium: "M", Large: "L", Huge: "H", Gargantuan: "G", }; /** Full normalized stat blocks for bundled D&D creatures. */ export function loadBundledDndCreatures(): Creature[] { return (rawBundled as RawBundledCreature[]).map((c) => ({ ...c, id: creatureId(c.id), })); } /** Index entries derived from the bundled creatures, in the compact shape * used by the search index. */ export function loadBundledDndIndexEntries(): BestiaryIndexEntry[] { return (rawBundled as RawBundledCreature[]).map((c) => ({ name: c.name, source: c.source, ac: c.ac, hp: c.hp.average, dex: c.abilities.dex, cr: c.cr, initiativeProficiency: c.initiativeProficiency, size: SIZE_TO_CODE[c.size.split(" ")[0]] ?? "M", type: c.type.split(" ")[0].toLowerCase(), })); } /** Source codes → display names, derived from the bundled creatures' own * `source` and `sourceDisplayName` fields. Adding a new book just means * appending creatures with the right `source` field to dnd-bundled.json; * no code change is required here. */ export function getBundledDndSources(): ReadonlyMap { const map = new Map(); for (const c of rawBundled as RawBundledCreature[]) { if (!map.has(c.source)) { map.set(c.source, c.sourceDisplayName); } } return map; }