@archivist-gg/dnd5e 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/background/background.codec.js +4 -4
  2. package/dist/background/background.parser.js +3 -3
  3. package/dist/background/background.schema.js +2 -2
  4. package/dist/{chunk-FFULAF2P.js → chunk-2BWAID3Y.js} +2 -2
  5. package/dist/chunk-353WXS6S.js +25 -0
  6. package/dist/{chunk-FUK7QSN5.js → chunk-42Y5IJKT.js} +1 -1
  7. package/dist/{chunk-TPZSPU4L.js → chunk-4JHOHWBI.js} +1 -1
  8. package/dist/{chunk-DC74TZNA.js → chunk-4LZJXJJS.js} +7 -2
  9. package/dist/chunk-5MZSB6OM.js +1089 -0
  10. package/dist/{chunk-FEOB24KP.js → chunk-73HOFQQ5.js} +1 -1
  11. package/dist/{chunk-YDPWD2T7.js → chunk-7VJ6BOA5.js} +4 -1
  12. package/dist/{chunk-ZLG6FQFB.js → chunk-A4WENOUQ.js} +21 -2
  13. package/dist/{chunk-GEJSJP6E.js → chunk-AIRFC5NQ.js} +3 -1
  14. package/dist/{chunk-DABBCYTT.js → chunk-CZPMTQOY.js} +1 -1
  15. package/dist/{chunk-DRNZJNJP.js → chunk-DZXSWSBP.js} +1 -1
  16. package/dist/{chunk-ADLTSHOR.js → chunk-EMOORSQ7.js} +59 -30
  17. package/dist/{chunk-RVYYKYFL.js → chunk-GE4TLPWM.js} +1 -1
  18. package/dist/{chunk-VLKIB33F.js → chunk-K6Q5OUGK.js} +6 -0
  19. package/dist/{chunk-PMADYMUI.js → chunk-L7E2UT5A.js} +1 -1
  20. package/dist/{chunk-3TRGRSCH.js → chunk-LV4SNWZQ.js} +7 -1
  21. package/dist/{chunk-IXZXFFFW.js → chunk-M2EMFD6S.js} +1 -1
  22. package/dist/{chunk-UC4FE5X3.js → chunk-N6N74K6X.js} +1 -1
  23. package/dist/{chunk-CDW7R2QT.js → chunk-NXSWH3AE.js} +4 -1
  24. package/dist/{chunk-IDTDACM6.js → chunk-PHQRGDRQ.js} +1 -1
  25. package/dist/{chunk-BAXWWGFJ.js → chunk-Q5K6LWBZ.js} +1 -1
  26. package/dist/{chunk-Z6GXV2GO.js → chunk-TLYDBT5F.js} +1 -1
  27. package/dist/{chunk-A7T5L7SS.js → chunk-TUIFSVLI.js} +1 -1
  28. package/dist/{chunk-J2RYSZMQ.js → chunk-VTTA2ALZ.js} +2 -2
  29. package/dist/{chunk-Z4TL2V7S.js → chunk-VTYUBINW.js} +1 -1
  30. package/dist/{chunk-B7UXKNLD.js → chunk-W7HWMMBF.js} +1 -1
  31. package/dist/{chunk-SSXBYF3P.js → chunk-XLSVNUTK.js} +1 -1
  32. package/dist/{chunk-GIOH5JB5.js → chunk-XTIQWSFM.js} +1 -1
  33. package/dist/{chunk-PKC77VZP.js → chunk-ZZGEVJKX.js} +1 -1
  34. package/dist/class/class.codec.js +5 -5
  35. package/dist/class/class.parser.js +4 -4
  36. package/dist/class/class.schema.js +3 -3
  37. package/dist/class/class.slug.d.ts +7 -5
  38. package/dist/class/class.slug.js +1 -1
  39. package/dist/entities/base-item-resolver.d.ts +9 -0
  40. package/dist/entities/base-item-resolver.js +6 -4
  41. package/dist/entities/slug.d.ts +7 -0
  42. package/dist/entities/slug.js +3 -1
  43. package/dist/feat/feat.codec.js +4 -4
  44. package/dist/feat/feat.parser.js +3 -3
  45. package/dist/feat/feat.schema.js +2 -2
  46. package/dist/index.js +4116 -3662
  47. package/dist/item/item.actions-map.d.ts +18 -10
  48. package/dist/item/item.actions-map.js +16 -12
  49. package/dist/item/item.codec.js +3 -3
  50. package/dist/item/item.parser.js +2 -2
  51. package/dist/item/item.schema.d.ts +3 -0
  52. package/dist/item/item.schema.js +1 -1
  53. package/dist/item/item.types.d.ts +8 -0
  54. package/dist/pc/pc.decision-engine.d.ts +0 -3
  55. package/dist/pc/pc.decision-engine.js +8 -3
  56. package/dist/pc/pc.equipment.js +5 -8
  57. package/dist/pc/pc.feature-effects.d.ts +5 -0
  58. package/dist/pc/pc.feature-effects.js +2 -4
  59. package/dist/pc/pc.parser.js +1 -1
  60. package/dist/pc/pc.pools.js +8 -3
  61. package/dist/pc/pc.recalc.d.ts +7 -0
  62. package/dist/pc/pc.recalc.js +94 -40
  63. package/dist/pc/pc.resolver.d.ts +59 -1
  64. package/dist/pc/pc.resolver.js +21 -343
  65. package/dist/pc/pc.rest.d.ts +1 -1
  66. package/dist/pc/pc.rest.js +20 -11
  67. package/dist/pc/pc.schema.d.ts +23 -0
  68. package/dist/pc/pc.schema.js +1 -1
  69. package/dist/pc/pc.slotting.js +3 -3
  70. package/dist/pc/pc.spellcasting.js +2 -2
  71. package/dist/pc/pc.types.d.ts +65 -5
  72. package/dist/race/race.codec.js +5 -5
  73. package/dist/race/race.parser.js +4 -4
  74. package/dist/race/race.schema.js +3 -3
  75. package/dist/schemas/choice-schema.js +1 -1
  76. package/dist/schemas/feature-schema.js +2 -2
  77. package/dist/spell/spell.access.js +1 -1
  78. package/dist/subclass/subclass.codec.js +5 -5
  79. package/dist/subclass/subclass.parser.js +4 -4
  80. package/dist/subclass/subclass.schema.js +3 -3
  81. package/dist/types/choice.d.ts +5 -0
  82. package/dist/weapon/weapon-mastery.d.ts +3 -0
  83. package/dist/weapon/weapon.classify.d.ts +21 -0
  84. package/dist/weapon/weapon.classify.js +7 -0
  85. package/package.json +1 -1
  86. package/dist/chunk-6PXE7T7C.js +0 -79
  87. package/dist/chunk-TJCNX6UZ.js +0 -521
@@ -35,6 +35,10 @@ export interface EquipmentEntryOverrides {
35
35
  immune?: string[];
36
36
  vulnerable?: string[];
37
37
  condition_immune?: string[];
38
+ /** Per-instance spell payload (e.g. the spell a Spell Scroll casts). */
39
+ spell?: string;
40
+ /** Ability governing this instance's spell save DC / attack when cast. */
41
+ spell_ability?: Ability;
38
42
  }
39
43
  export interface EquipmentEntryState {
40
44
  charges?: {
@@ -92,6 +96,10 @@ export interface KnownSpellObject {
92
96
  source?: "class" | "feat" | "item" | "race" | "domain";
93
97
  prepared?: boolean;
94
98
  always_prepared?: boolean;
99
+ /** The spell's own spellcasting ability (e.g. WIS for a Magic Initiate (Cleric)
100
+ * pick). Belongs on the persisted shape for symmetry with ResolvedSpell.ability;
101
+ * feat spells arrive via origin_choices, but a known-spell entry may carry it. */
102
+ ability?: Ability;
95
103
  }
96
104
  export type KnownSpellEntry = string | KnownSpellObject;
97
105
  export type PassiveKind = "perception" | "investigation" | "insight";
@@ -112,6 +120,8 @@ export interface CharacterOverrides {
112
120
  }>;
113
121
  hp?: {
114
122
  max?: number;
123
+ rolled?: number;
124
+ modifier?: number;
115
125
  };
116
126
  ac?: number;
117
127
  speed?: number;
@@ -120,6 +130,10 @@ export interface CharacterOverrides {
120
130
  saveDC?: number;
121
131
  attackBonus?: number;
122
132
  };
133
+ /** Character-level spellcasting ability for spells that carry no ability of
134
+ * their own (e.g. a Spell Scroll cast by a non-caster): the DC-ability fallback
135
+ * after a per-instance override and the character's own class ability. */
136
+ spellcasting_ability?: Ability;
123
137
  spell_slots?: Record<number, number>;
124
138
  attunement_limit?: number;
125
139
  }
@@ -267,6 +281,14 @@ export interface ResolvedSpell {
267
281
  source: "class" | "feat" | "item" | "race" | "domain";
268
282
  prepared: boolean;
269
283
  alwaysPrepared: boolean;
284
+ /** The spell's OWN spellcasting ability. For a feat spell this carries the
285
+ * chosen ability (e.g. WIS for Magic Initiate (Cleric)) while classSlug stays
286
+ * null (a feat spell is not owned by a class for DC/ability). Absent/undefined
287
+ * for class spells, which derive their ability from classSlug. */
288
+ ability?: Ability | null;
289
+ /** Index of the originating equipment entry when this spell was granted by a
290
+ * per-instance item (e.g. a Spell Scroll). Absent for class/feat/race spells. */
291
+ entryIndex?: number;
270
292
  }
271
293
  export interface ResolvedClass {
272
294
  entity: ClassEntity | null;
@@ -319,6 +341,27 @@ export interface ACTerm {
319
341
  amount: number;
320
342
  kind: "armor" | "shield" | "item" | "unarmored" | "override" | "dex" | "ability" | "feature";
321
343
  }
344
+ /** Structured max-HP math for the Max HP modal. Spec: P5 2026-07-21. */
345
+ export interface HPBreakdown {
346
+ diceSum: number;
347
+ diceSource: "rolled" | "average";
348
+ averageDiceSum: number;
349
+ conMod: number;
350
+ conLevels: number;
351
+ clampApplied: boolean;
352
+ perLevelTerms: {
353
+ label: string;
354
+ perLevel: number;
355
+ levels: number;
356
+ total: number;
357
+ }[];
358
+ modifier: number | null;
359
+ exhaustionMultiplier: number;
360
+ exhaustionLevel: number;
361
+ derivedMax: number;
362
+ override: number | null;
363
+ final: number;
364
+ }
322
365
  /** An additive on-hit damage rider (dice or flat) applied to an attack, from a
323
366
  * feature (global — all weapon attacks) or a magic item (that weapon only).
324
367
  * `amount` is a dice/flat string ("2d6", "1d8", "2"); `damage_type` optional
@@ -333,6 +376,10 @@ export interface AttackRow {
333
376
  id: string;
334
377
  name: string;
335
378
  range?: string;
379
+ /** Secondary thrown-mode range ("20/60 ft") for a throwable melee weapon.
380
+ * Display-only; rendered as a stacked muted second line in the Range cell.
381
+ * Absent otherwise. */
382
+ thrownRange?: string;
336
383
  toHit: number;
337
384
  damageDice: string;
338
385
  damageType: string;
@@ -376,15 +423,17 @@ export interface AttackRow {
376
423
  attackNotes?: string[];
377
424
  /** 2024 Weapon Mastery for this attack, present only when the character has
378
425
  * chosen mastery of this weapon AND is proficient with it AND the weapon
379
- * declares a mastery property. `slug`/`label`/`description` come from the
380
- * mastery glossary; `derived` carries the computed number for the two
381
- * numeric masteries (topple → Save DC, graze → On-miss damage) and is absent
382
- * for the rest. Additive + display-only — absent (undefined) on untouched
383
- * rows so nothing else changes. */
426
+ * declares a mastery property. `slug`/`label`/`description`/`gist` come from
427
+ * the mastery glossary (`gist` = a one-line effect summary for the Actions-tab
428
+ * mastery column, e.g. "on fail: Prone"); `derived` carries the computed
429
+ * number for the two numeric masteries (topple → Save DC, graze → On-miss
430
+ * damage) and is absent for the rest. Additive + display-only, absent
431
+ * (undefined) on untouched rows so nothing else changes. */
384
432
  mastery?: {
385
433
  slug: string;
386
434
  label: string;
387
435
  description: string;
436
+ gist?: string;
388
437
  derived?: {
389
438
  label: string;
390
439
  value: number;
@@ -480,6 +529,16 @@ export interface DerivedStats {
480
529
  } | null;
481
530
  /** One entry per casting class (multiclass-aware). Empty for non-casters. */
482
531
  spellcastingClasses: SpellcastingClassInfo[];
532
+ /** Save DC / attack bonus for spells that carry their OWN spellcasting
533
+ * ability rather than a class (feat-granted spells, e.g. Magic Initiate).
534
+ * Keyed by that ability; populated for every ability a feat spell uses.
535
+ * Computed independently of class casters, so a NON-caster (empty
536
+ * spellcastingClasses / null spellcasting) still gets a real DC/attack.
537
+ * Empty object when the character has no such spell. */
538
+ abilitySpellcasting: Partial<Record<Ability, {
539
+ saveDC: number;
540
+ attackBonus: number;
541
+ }>>;
483
542
  /** Derived standard slot totals by spell level (before user override). */
484
543
  derivedSpellSlots: Record<number, number>;
485
544
  /** Warlock Pact Magic, or null. */
@@ -497,6 +556,7 @@ export interface DerivedStats {
497
556
  condition_immunities: string[];
498
557
  };
499
558
  acBreakdown: ACTerm[];
559
+ hpBreakdown: HPBreakdown;
500
560
  acInformational: import("@archivist-gg/dnd5e/item/item.conditions.types").InformationalBonus[];
501
561
  /** Situational saving-throw bonuses (e.g. +1 vs spells) for save tooltips. */
502
562
  savesInformational: import("@archivist-gg/dnd5e/item/item.conditions.types").InformationalBonus[];
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  raceCodec
3
- } from "../chunk-PKC77VZP.js";
4
- import "../chunk-IDTDACM6.js";
5
- import "../chunk-FFULAF2P.js";
6
- import "../chunk-DABBCYTT.js";
3
+ } from "../chunk-ZZGEVJKX.js";
4
+ import "../chunk-PHQRGDRQ.js";
5
+ import "../chunk-2BWAID3Y.js";
6
+ import "../chunk-CZPMTQOY.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
8
  import "../chunk-PZOWBI3B.js";
9
- import "../chunk-CDW7R2QT.js";
9
+ import "../chunk-NXSWH3AE.js";
10
10
  import "../chunk-NXR3BD2V.js";
11
11
  export {
12
12
  raceCodec
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  parseRace
3
- } from "../chunk-IDTDACM6.js";
4
- import "../chunk-FFULAF2P.js";
5
- import "../chunk-DABBCYTT.js";
3
+ } from "../chunk-PHQRGDRQ.js";
4
+ import "../chunk-2BWAID3Y.js";
5
+ import "../chunk-CZPMTQOY.js";
6
6
  import "../chunk-WYGD2UGN.js";
7
7
  import "../chunk-PZOWBI3B.js";
8
- import "../chunk-CDW7R2QT.js";
8
+ import "../chunk-NXSWH3AE.js";
9
9
  import "../chunk-NXR3BD2V.js";
10
10
  export {
11
11
  parseRace
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  raceEntitySchema
3
- } from "../chunk-FFULAF2P.js";
4
- import "../chunk-DABBCYTT.js";
3
+ } from "../chunk-2BWAID3Y.js";
4
+ import "../chunk-CZPMTQOY.js";
5
5
  import "../chunk-WYGD2UGN.js";
6
6
  import "../chunk-PZOWBI3B.js";
7
- import "../chunk-CDW7R2QT.js";
7
+ import "../chunk-NXSWH3AE.js";
8
8
  import "../chunk-NXR3BD2V.js";
9
9
  export {
10
10
  raceEntitySchema
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  choiceSchema
3
- } from "../chunk-CDW7R2QT.js";
3
+ } from "../chunk-NXSWH3AE.js";
4
4
  import "../chunk-NXR3BD2V.js";
5
5
  export {
6
6
  choiceSchema
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  featureSchema
3
- } from "../chunk-DABBCYTT.js";
3
+ } from "../chunk-CZPMTQOY.js";
4
4
  import "../chunk-WYGD2UGN.js";
5
5
  import "../chunk-PZOWBI3B.js";
6
- import "../chunk-CDW7R2QT.js";
6
+ import "../chunk-NXSWH3AE.js";
7
7
  import "../chunk-NXR3BD2V.js";
8
8
  export {
9
9
  featureSchema
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  baseClassName
3
- } from "../chunk-J2RYSZMQ.js";
3
+ } from "../chunk-VTTA2ALZ.js";
4
4
 
5
5
  // src/spell/spell.access.ts
6
6
  function classSpellCandidates(registry, classSlugs, maxLevel, knownSlugs, showAll = false, query = "") {
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  subclassCodec
3
- } from "../chunk-SSXBYF3P.js";
4
- import "../chunk-PMADYMUI.js";
5
- import "../chunk-B7UXKNLD.js";
3
+ } from "../chunk-XLSVNUTK.js";
4
+ import "../chunk-L7E2UT5A.js";
5
+ import "../chunk-W7HWMMBF.js";
6
6
  import "../chunk-4TIJKN6O.js";
7
- import "../chunk-DABBCYTT.js";
7
+ import "../chunk-CZPMTQOY.js";
8
8
  import "../chunk-WYGD2UGN.js";
9
9
  import "../chunk-PZOWBI3B.js";
10
- import "../chunk-CDW7R2QT.js";
10
+ import "../chunk-NXSWH3AE.js";
11
11
  import "../chunk-NXR3BD2V.js";
12
12
  export {
13
13
  subclassCodec
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  parseSubclass
3
- } from "../chunk-PMADYMUI.js";
4
- import "../chunk-B7UXKNLD.js";
3
+ } from "../chunk-L7E2UT5A.js";
4
+ import "../chunk-W7HWMMBF.js";
5
5
  import "../chunk-4TIJKN6O.js";
6
- import "../chunk-DABBCYTT.js";
6
+ import "../chunk-CZPMTQOY.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
8
  import "../chunk-PZOWBI3B.js";
9
- import "../chunk-CDW7R2QT.js";
9
+ import "../chunk-NXSWH3AE.js";
10
10
  import "../chunk-NXR3BD2V.js";
11
11
  export {
12
12
  parseSubclass
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  subclassEntitySchema
3
- } from "../chunk-B7UXKNLD.js";
3
+ } from "../chunk-W7HWMMBF.js";
4
4
  import "../chunk-4TIJKN6O.js";
5
- import "../chunk-DABBCYTT.js";
5
+ import "../chunk-CZPMTQOY.js";
6
6
  import "../chunk-WYGD2UGN.js";
7
7
  import "../chunk-PZOWBI3B.js";
8
- import "../chunk-CDW7R2QT.js";
8
+ import "../chunk-NXSWH3AE.js";
9
9
  import "../chunk-NXR3BD2V.js";
10
10
  export {
11
11
  subclassEntitySchema
@@ -19,6 +19,11 @@ export interface EntityFilter {
19
19
  /** Armor proficiency class. Matched against an armor entity's `category`
20
20
  * field exactly; "shield" selects shields. */
21
21
  armor_category?: "light" | "medium" | "heavy" | "shield";
22
+ /** Spell axis: filter spells by class list, level, and edition. Set together on a
23
+ * select-entity{entity_type:"spell"} choice (e.g. Magic Initiate). */
24
+ list?: string;
25
+ level?: number;
26
+ edition?: string;
22
27
  }
23
28
  export interface InlineOption {
24
29
  value: string;
@@ -1,8 +1,11 @@
1
1
  export declare const MASTERY: Record<string, {
2
2
  label: string;
3
3
  description: string;
4
+ gist: string;
4
5
  }>;
5
6
  export declare function masteryLabel(slug: string): string | undefined;
7
+ /** One-line effect gist for a mastery slug (or undefined for an unknown slug). */
8
+ export declare function masteryGist(slug: string): string | undefined;
6
9
  export declare function masteryDerived(slug: string, abilityMod: number, proficiencyBonus: number): {
7
10
  label: string;
8
11
  value: number;
@@ -0,0 +1,21 @@
1
+ import type { WeaponEntity } from "./weapon.types.js";
2
+ /** The two attack modes a weapon supports, derived from data the SRD pipeline
3
+ * actually preserves. The SRD runtime data miscategorizes throwable MELEE
4
+ * weapons (dagger/spear/handaxe/javelin/light hammer/trident) as `*-ranged`,
5
+ * so the melee/ranged split is reconstructed here instead of trusted:
6
+ * a category-ranged weapon is PURE ranged only when it needs ammunition or
7
+ * loading, or is one of the two genuinely-ranged thrown weapons (dart, net —
8
+ * a closed SRD set; a homebrew weapon whose bare slug is exactly "dart"/"net"
9
+ * is force-classified pure ranged). Everything else category-ranged is a
10
+ * throwable melee weapon. `reach` is 5 ft, +5 with the reach property. */
11
+ export interface WeaponRangeModes {
12
+ melee: {
13
+ reach: number;
14
+ } | null;
15
+ ranged: {
16
+ normal: number;
17
+ long: number;
18
+ thrown: boolean;
19
+ } | null;
20
+ }
21
+ export declare function classifyWeaponRange(weapon: Pick<WeaponEntity, "category" | "properties" | "range" | "slug">): WeaponRangeModes;
@@ -0,0 +1,7 @@
1
+ import {
2
+ classifyWeaponRange
3
+ } from "../chunk-353WXS6S.js";
4
+ import "../chunk-LV4SNWZQ.js";
5
+ export {
6
+ classifyWeaponRange
7
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archivist-gg/dnd5e",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,79 +0,0 @@
1
- import {
2
- readTableColumn
3
- } from "./chunk-5XUXXAQJ.js";
4
- import {
5
- bareEntitySlug,
6
- wikilinkTailSlug
7
- } from "./chunk-TJCNX6UZ.js";
8
-
9
- // src/pc/pc.pools.ts
10
- function levelPrereqMax(d) {
11
- var _a;
12
- return ((_a = d.prerequisites) != null ? _a : []).filter((p) => p.kind === "level").reduce((m, p) => Math.max(m, p.min), 0);
13
- }
14
- function resolvePool(rc, classIndex, pool, registry) {
15
- var _a, _b, _c, _d, _e, _f, _g;
16
- const entity = rc.entity;
17
- const level = rc.level;
18
- const ownerBare = bareEntitySlug(entity.slug);
19
- const col = pool.count.column;
20
- const count = (_a = readTableColumn(entity.table, level, [col])) != null ? _a : 0;
21
- let anchorLevel = 1;
22
- for (let l = 1; l <= 20; l++) {
23
- const c = readTableColumn(entity.table, l, [col]);
24
- if (c != null && c >= 1) {
25
- anchorLevel = l;
26
- break;
27
- }
28
- }
29
- const ft = pool.source.where.feature_type;
30
- const all = registry.search("", "optional-feature", Number.POSITIVE_INFINITY);
31
- const byBare = /* @__PURE__ */ new Map();
32
- const available = [];
33
- for (const e of all) {
34
- const d = e.data;
35
- const entry = { slug: e.slug, entity: d };
36
- byBare.set(bareEntitySlug(e.slug), entry);
37
- if (d.feature_type !== ft) continue;
38
- if (!((_b = d.available_to) != null ? _b : []).some((l) => wikilinkTailSlug(l) === ownerBare)) continue;
39
- if (levelPrereqMax(d) > level) continue;
40
- available.push(entry);
41
- }
42
- const grantDecls = [
43
- ...(_d = (_c = rc.entity) == null ? void 0 : _c.pool_grants) != null ? _d : [],
44
- ...(_f = (_e = rc.subclass) == null ? void 0 : _e.pool_grants) != null ? _f : []
45
- ];
46
- const grantsRaw = grantDecls.filter((g) => g.pool === pool.id).flatMap((g) => g.grants).filter((g) => g.at_level <= level).map((g) => byBare.get(wikilinkTailSlug(g.feature))).filter((e) => e != null);
47
- const grantedBare = /* @__PURE__ */ new Set();
48
- const grants = grantsRaw.filter((e) => {
49
- const key = bareEntitySlug(e.slug);
50
- if (grantedBare.has(key)) return false;
51
- grantedBare.add(key);
52
- return true;
53
- });
54
- const raw = (_g = rc.choices[anchorLevel]) == null ? void 0 : _g[pool.id];
55
- const selectedSlugs = Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
56
- const selected = selectedSlugs.map((s) => byBare.get(bareEntitySlug(s))).filter((e) => e != null).filter((e) => !grantedBare.has(bareEntitySlug(e.slug)));
57
- return { id: pool.id, label: pool.label, classIndex, count, anchorLevel, selected, available, grants };
58
- }
59
- function resolveAllPools(resolved, registry) {
60
- const out = [];
61
- resolved.classes.forEach((rc, classIndex) => {
62
- var _a, _b, _c;
63
- if (!rc.entity) return;
64
- const decls = [...(_a = rc.entity.selection_pools) != null ? _a : [], ...(_c = (_b = rc.subclass) == null ? void 0 : _b.selection_pools) != null ? _c : []];
65
- const seen = /* @__PURE__ */ new Set();
66
- for (const pool of decls) {
67
- if (seen.has(pool.id)) continue;
68
- seen.add(pool.id);
69
- out.push(resolvePool(rc, classIndex, pool, registry));
70
- }
71
- });
72
- return out;
73
- }
74
-
75
- export {
76
- levelPrereqMax,
77
- resolvePool,
78
- resolveAllPools
79
- };