@archivist-gg/dnd5e 0.3.11 → 0.3.17

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 (192) hide show
  1. package/LICENSES/SRD.md +38 -3
  2. package/dist/armor/armor.codec.js +3 -3
  3. package/dist/armor/armor.parser.js +2 -2
  4. package/dist/armor/armor.schema.d.ts +1 -0
  5. package/dist/armor/armor.schema.js +1 -1
  6. package/dist/armor/armor.types.d.ts +2 -0
  7. package/dist/background/background.codec.js +5 -5
  8. package/dist/background/background.parser.js +4 -4
  9. package/dist/background/background.schema.js +3 -3
  10. package/dist/{chunk-XTRDCSJB.js → chunk-2JSQE3DD.js} +15 -1
  11. package/dist/chunk-2LULMQTF.js +14 -0
  12. package/dist/{chunk-MAH6DCRI.js → chunk-2UDSN6VW.js} +1 -1
  13. package/dist/chunk-3LWMFYKS.js +57 -0
  14. package/dist/{chunk-JCEV7KYN.js → chunk-3MGQFFNE.js} +1 -1
  15. package/dist/chunk-3VZZDKRA.js +1014 -0
  16. package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
  17. package/dist/{chunk-2M34FLAY.js → chunk-5MXFW4O3.js} +9 -3
  18. package/dist/{chunk-4DOMDEBZ.js → chunk-6EI737IO.js} +1 -1
  19. package/dist/{chunk-G247QXWW.js → chunk-7ATNGKBS.js} +1 -1
  20. package/dist/{chunk-XY6X2APM.js → chunk-7Q2VPKCD.js} +17 -0
  21. package/dist/{chunk-T2SNEJOE.js → chunk-7QN7XSAK.js} +1 -1
  22. package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
  23. package/dist/{chunk-7YU4NPKR.js → chunk-AZRGFUSR.js} +1 -1
  24. package/dist/{chunk-PP2UHLBA.js → chunk-B3DP42OM.js} +5 -0
  25. package/dist/chunk-CM5CWO4K.js +735 -0
  26. package/dist/{chunk-MQ747UCR.js → chunk-DOXSFYLH.js} +70 -2
  27. package/dist/chunk-EJP263OP.js +186 -0
  28. package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
  29. package/dist/{chunk-V6LJFP4R.js → chunk-FANQVQ3D.js} +2 -2
  30. package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
  31. package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
  32. package/dist/{chunk-JANNRGJC.js → chunk-G6PBI2BU.js} +1 -1
  33. package/dist/chunk-H5PTKYXL.js +101 -0
  34. package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
  35. package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
  36. package/dist/chunk-HTYMW5CH.js +228 -0
  37. package/dist/chunk-IHE6KVC3.js +13 -0
  38. package/dist/{chunk-QHMWA3SZ.js → chunk-JCMUVZIK.js} +1 -1
  39. package/dist/{chunk-V373TRJE.js → chunk-JSM6JFZR.js} +198 -125
  40. package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
  41. package/dist/chunk-KR6JF3BF.js +14 -0
  42. package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
  43. package/dist/chunk-LBEXLN6I.js +91 -0
  44. package/dist/{chunk-BLRW2UU6.js → chunk-LF5AGJA4.js} +2 -2
  45. package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
  46. package/dist/{chunk-BIA32MQ5.js → chunk-MBX25B6D.js} +1 -1
  47. package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
  48. package/dist/{chunk-J77CKYV3.js → chunk-OFCSP6MT.js} +1 -1
  49. package/dist/{chunk-2INMRR3Q.js → chunk-ONTGZR5T.js} +326 -149
  50. package/dist/{chunk-MWCCGPG3.js → chunk-OOSRUJBI.js} +3 -2
  51. package/dist/{chunk-U3BABVJF.js → chunk-PKX6TGRE.js} +2 -2
  52. package/dist/{chunk-PJMG5XV3.js → chunk-PQZ4LM4Z.js} +1 -1
  53. package/dist/chunk-PXVNAY7T.js +84 -0
  54. package/dist/chunk-QH36K2PU.js +158 -0
  55. package/dist/{chunk-R747YKS7.js → chunk-QZSWN2KT.js} +1 -1
  56. package/dist/{chunk-CHUALUIX.js → chunk-RYLXAYIQ.js} +1 -1
  57. package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
  58. package/dist/{chunk-PZCE7DJM.js → chunk-T6QIF5XR.js} +31 -1
  59. package/dist/{chunk-CBEKVAX4.js → chunk-TULQ4FFX.js} +41 -13
  60. package/dist/{chunk-S56D6B6C.js → chunk-UUBJCNQU.js} +12 -3
  61. package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
  62. package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
  63. package/dist/{chunk-3HX5VLWP.js → chunk-VRV3NNTA.js} +2 -2
  64. package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
  65. package/dist/{chunk-BL3VELKP.js → chunk-Y5VVP73C.js} +1 -1
  66. package/dist/{chunk-PI4LLJG4.js → chunk-YD2VAHA6.js} +2 -2
  67. package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
  68. package/dist/{chunk-NWDF5HG3.js → chunk-YKL6SHRJ.js} +1 -1
  69. package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
  70. package/dist/chunk-ZUQW5VBZ.js +89 -0
  71. package/dist/class/class.codec.js +7 -7
  72. package/dist/class/class.parser.js +6 -6
  73. package/dist/class/class.schema.d.ts +18 -0
  74. package/dist/class/class.schema.js +5 -5
  75. package/dist/class/class.standard-array.d.ts +16 -0
  76. package/dist/class/class.standard-array.js +20 -0
  77. package/dist/class/class.types.d.ts +3 -0
  78. package/dist/dnd/amount-text.d.ts +38 -0
  79. package/dist/dnd/amount-text.js +13 -0
  80. package/dist/dnd/resource-words.d.ts +4 -0
  81. package/dist/dnd/resource-words.js +30 -0
  82. package/dist/entities/base-item-resolver.js +2 -2
  83. package/dist/entities/slug.d.ts +18 -8
  84. package/dist/entities/slug.js +3 -1
  85. package/dist/feat/feat.codec.js +5 -5
  86. package/dist/feat/feat.parser.js +4 -4
  87. package/dist/feat/feat.schema.d.ts +41 -3
  88. package/dist/feat/feat.schema.js +3 -3
  89. package/dist/index.js +7513 -4177
  90. package/dist/item/item.actions-map.d.ts +40 -5
  91. package/dist/item/item.actions-map.js +5 -84
  92. package/dist/item/item.attunement.js +3 -9
  93. package/dist/item/item.bonuses.js +5 -2
  94. package/dist/item/item.codec.js +3 -3
  95. package/dist/item/item.conditions.js +4 -1
  96. package/dist/item/item.conditions.types.d.ts +4 -0
  97. package/dist/item/item.cost.d.ts +3 -0
  98. package/dist/item/item.cost.js +29 -0
  99. package/dist/item/item.icon.d.ts +15 -0
  100. package/dist/item/item.icon.js +211 -0
  101. package/dist/item/item.parser.js +2 -2
  102. package/dist/item/item.schema.d.ts +16 -1
  103. package/dist/item/item.schema.js +3 -1
  104. package/dist/item/item.types.d.ts +9 -2
  105. package/dist/monster/monster.parser.js +5 -5
  106. package/dist/monster/monster.schema.js +4 -4
  107. package/dist/optional-feature/optional-feature.codec.js +5 -4
  108. package/dist/optional-feature/optional-feature.parser.js +4 -3
  109. package/dist/optional-feature/optional-feature.schema.d.ts +255 -3
  110. package/dist/optional-feature/optional-feature.schema.js +7 -2
  111. package/dist/pc/pc.additional-spells.js +3 -3
  112. package/dist/pc/pc.amount-bindings.d.ts +32 -0
  113. package/dist/pc/pc.amount-bindings.js +23 -0
  114. package/dist/pc/pc.asi-flatten.d.ts +62 -1
  115. package/dist/pc/pc.asi-flatten.js +16 -0
  116. package/dist/pc/pc.conditions.js +1 -1
  117. package/dist/pc/pc.containment.d.ts +45 -0
  118. package/dist/pc/pc.containment.js +24 -0
  119. package/dist/pc/pc.decision-engine.d.ts +24 -3
  120. package/dist/pc/pc.decision-engine.js +26 -16
  121. package/dist/pc/pc.entry-overrides.d.ts +79 -0
  122. package/dist/pc/pc.entry-overrides.js +40 -0
  123. package/dist/pc/pc.equipment.d.ts +2 -2
  124. package/dist/pc/pc.equipment.js +19 -7
  125. package/dist/pc/pc.feature-effects.d.ts +12 -0
  126. package/dist/pc/pc.feature-effects.js +2 -2
  127. package/dist/pc/pc.infusions.d.ts +228 -0
  128. package/dist/pc/pc.infusions.js +64 -0
  129. package/dist/pc/pc.member-choices.d.ts +90 -0
  130. package/dist/pc/pc.member-choices.js +32 -0
  131. package/dist/pc/pc.parser.js +18 -1
  132. package/dist/pc/pc.pools.d.ts +8 -1
  133. package/dist/pc/pc.pools.js +13 -3
  134. package/dist/pc/pc.proficiencies.js +23 -15
  135. package/dist/pc/pc.proficiency-query.js +6 -0
  136. package/dist/pc/pc.recalc.d.ts +39 -36
  137. package/dist/pc/pc.recalc.js +115 -70
  138. package/dist/pc/pc.resolver.d.ts +2 -1
  139. package/dist/pc/pc.resolver.js +22 -14
  140. package/dist/pc/pc.resource-seed.js +1 -1
  141. package/dist/pc/pc.resources.d.ts +6 -1
  142. package/dist/pc/pc.resources.js +3 -1
  143. package/dist/pc/pc.rest.d.ts +21 -1
  144. package/dist/pc/pc.rest.js +52 -19
  145. package/dist/pc/pc.schema.d.ts +43 -2
  146. package/dist/pc/pc.schema.js +1 -1
  147. package/dist/pc/pc.slotting.d.ts +36 -3
  148. package/dist/pc/pc.slotting.js +13 -5
  149. package/dist/pc/pc.tool-picks.d.ts +51 -0
  150. package/dist/pc/pc.tool-picks.js +18 -0
  151. package/dist/pc/pc.types.d.ts +115 -14
  152. package/dist/pc/pc.weapon-grant.d.ts +15 -0
  153. package/dist/pc/pool-layout.d.ts +8 -0
  154. package/dist/pc/pool-layout.js +5 -3
  155. package/dist/pc/resource-equivalents.d.ts +44 -0
  156. package/dist/pc/spell-source.js +4 -9
  157. package/dist/race/race.codec.js +6 -6
  158. package/dist/race/race.parser.js +5 -5
  159. package/dist/race/race.schema.js +4 -4
  160. package/dist/schemas/attack-schema.d.ts +1 -1
  161. package/dist/schemas/choice-schema.js +2 -2
  162. package/dist/schemas/feature-effect-schema.d.ts +41 -3
  163. package/dist/schemas/feature-effect-schema.js +1 -1
  164. package/dist/schemas/feature-schema.js +3 -3
  165. package/dist/schemas/selection-pool-schema.d.ts +10 -0
  166. package/dist/schemas/selection-pool-schema.js +1 -1
  167. package/dist/spell/spell.codec.js +2 -2
  168. package/dist/spell/spell.parser.d.ts +6 -1
  169. package/dist/spell/spell.parser.js +5 -3
  170. package/dist/spell/spell.types.d.ts +10 -0
  171. package/dist/srd/retired-items.d.ts +14 -0
  172. package/dist/srd/retired-items.js +11 -0
  173. package/dist/subclass/subclass.codec.js +7 -7
  174. package/dist/subclass/subclass.parser.js +6 -6
  175. package/dist/subclass/subclass.schema.d.ts +10 -0
  176. package/dist/subclass/subclass.schema.js +5 -5
  177. package/dist/types/choice.d.ts +13 -0
  178. package/dist/types/equipment-grant.d.ts +18 -1
  179. package/dist/types/equipment-grant.js +12 -0
  180. package/dist/types/feature-effect.d.ts +12 -1
  181. package/dist/types/optional-feature.types.d.ts +84 -1
  182. package/dist/types/selection-pool.d.ts +18 -3
  183. package/dist/weapon/weapon.classify.d.ts +10 -8
  184. package/dist/weapon/weapon.classify.js +2 -2
  185. package/dist/weapon/weapon.codec.js +3 -3
  186. package/dist/weapon/weapon.parser.js +2 -2
  187. package/dist/weapon/weapon.schema.d.ts +1 -0
  188. package/dist/weapon/weapon.schema.js +1 -1
  189. package/dist/weapon/weapon.types.d.ts +2 -0
  190. package/package.json +1 -1
  191. package/dist/chunk-O4SRD3J5.js +0 -165
  192. package/dist/chunk-WXWPK3LI.js +0 -55
@@ -0,0 +1,90 @@
1
+ /**
2
+ * D2b-A · nested choices on pool members (design §2.2, user rulings 2026-09-27: GENERAL and RECURSIVE).
3
+ *
4
+ * A pool member (an invocation, a maneuver, a fighting-style option, ...) may carry its own choices: Lessons of the First
5
+ * Ones' Origin feat, Superior Technique's maneuver, Blessed and Druidic Warrior's cantrips, Pact of the Tome's cantrips
6
+ * and rituals, the three blasts' cantrip. A nested pick lives in the pool's ANCHOR block under
7
+ * `<poolId>:<pickKey>:<choiceId>` (a nested feat's own children under `<poolId>:<pickKey>:feat:<childId>`, the decision
8
+ * engine's prefix chaining), keyed by the stored pick string, so reordering or adding picks never moves it.
9
+ *
10
+ * The choices are the member's authored `choices`; absent (every note in the vault today), they are DERIVED at read time
11
+ * from the raw keys the notes already carry (`feat_progression`, `optionalfeature_progression`, `additional_spells`
12
+ * with `choose`, a `spell-choose` prerequisite), so existing notes work with no re-import. Authored `choices` win.
13
+ */
14
+ import type { Character, ChoiceValue, FeatVia, ResolvedCharacter, ResolvedClass } from "./pc.types.js";
15
+ import type { Choice } from "@archivist-gg/dnd5e/types/choice";
16
+ import type { OptionalFeatureEntity } from "@archivist-gg/dnd5e/types/optional-feature.types";
17
+ import type { FeatEntity } from "@archivist-gg/dnd5e/feat/feat.types";
18
+ /** Whether `ch` names a target rather than granting what it picks (the data flag `target: true`, which the spell-choose
19
+ * derivation below writes and an authored note may carry). */
20
+ export declare function isTargetChoice(ch: Choice): boolean;
21
+ /**
22
+ * The member's choices: its authored `choices`, else the ones its raw keys ask for (see the module docblock). Pure; the
23
+ * derived rows carry the member's edition so a pick never offers the other edition's twin.
24
+ */
25
+ export declare function memberChoices(entity: OptionalFeatureEntity | null | undefined): Choice[];
26
+ /** One stored pool pick whose member carries choices, with the block its nested picks live in. */
27
+ export interface PoolMemberSite {
28
+ classIndex: number;
29
+ /** The pool's anchor level (the block's key in `choices`). */
30
+ level: number;
31
+ poolId: string;
32
+ /** The stored pick string (a copy of a repeatable note keeps its `slug#param`). */
33
+ pickKey: string;
34
+ member: OptionalFeatureEntity;
35
+ memberSlug: string;
36
+ choices: Choice[];
37
+ /** `<poolId>:<pickKey>:` */
38
+ prefix: string;
39
+ /** The nested pick stored for a member choice id. */
40
+ read: (choiceId: string) => ChoiceValue | undefined;
41
+ /** The anchor block, as stored. */
42
+ block: Record<string, ChoiceValue>;
43
+ }
44
+ /** Structural subset of the registry the raw enumerator reads. */
45
+ export interface MemberRegistry {
46
+ getByTypeAndSlug(entityType: string, slug: string): {
47
+ slug: string;
48
+ data: Record<string, unknown>;
49
+ } | undefined;
50
+ search(query: string, entityType: string, limit: number): Array<{
51
+ slug: string;
52
+ data: Record<string, unknown>;
53
+ }>;
54
+ }
55
+ /**
56
+ * Every pool member site from the RAW character (the resolver's view, before pools resolve): each class's and subclass's
57
+ * declared pools, their anchor levels (`poolAnchorLevel`, the one derivation `resolvePool` uses), the picks stored there,
58
+ * each resolved to its note (full slug, else bare). A pick with no note, or a note with no choices, yields no site, so an
59
+ * orphan nested key is inert.
60
+ */
61
+ export declare function poolMemberSites(classes: ResolvedClass[], registry: MemberRegistry): PoolMemberSite[];
62
+ /** The same sites read from a RESOLVED character's pools (the ledger's, the proficiency walk's and recalc's view). */
63
+ export declare function poolMemberSitesOf(resolved: Pick<ResolvedCharacter, "pools" | "classes">): PoolMemberSite[];
64
+ /** A feat the character picked, where it was picked, and how its own children are read. */
65
+ export interface FeatPickSite {
66
+ slug: string;
67
+ classIndex: number;
68
+ level: number | null;
69
+ via: FeatVia | null;
70
+ /** A child choice of THIS feat, as stored (`feat:<id>` in the slot's block, or `<prefix>feat:<id>` under a member). */
71
+ read: (childId: string) => ChoiceValue | undefined;
72
+ }
73
+ /**
74
+ * Every feat pick with its own read (design §2.2 step 4): the class-slot picks (`choices[<level>].feat`, children under
75
+ * `feat:<id>`) and the pool-member picks (a member choice of `entity_type: feat`, children under `<prefix>feat:<id>`).
76
+ * The ONE list the four feat readers walk (the resolver's feats and feat spells, the proficiency walk, ability points).
77
+ * `classSlugOf` names a class for the provenance. NOT de-duplicated: a feat taken twice (Magic Initiate, one spell list
78
+ * each) is two sites with two reads; a reader that lists feats de-duplicates by slug itself (first wins).
79
+ */
80
+ export declare function featPickSites(classEntries: ReadonlyArray<{
81
+ choices?: Character["class"][number]["choices"] | ResolvedClass["choices"];
82
+ }> | undefined, memberSites: PoolMemberSite[], classSlugOf: (classIndex: number) => string | null): FeatPickSite[];
83
+ /** Look a feat pick up in the resolved feats (by slug, then bare slug). */
84
+ export declare function featOfSite(site: FeatPickSite, feats: ReadonlyArray<FeatEntity>): FeatEntity | undefined;
85
+ /**
86
+ * The nested keys an array write to `key` orphans (design §2.2 step 8): every `<key>:<k>:*` whose `k` was stored before
87
+ * and is not in `next`. Pure; the writer deletes them in the same write, so a re-pick never resurrects an old answer.
88
+ * A key that is not a pool (no array stored) orphans nothing.
89
+ */
90
+ export declare function nestedPickKeysToPrune(block: Record<string, unknown> | undefined, key: string, next: readonly string[]): string[];
@@ -0,0 +1,32 @@
1
+ import {
2
+ featOfSite,
3
+ featPickSites,
4
+ isTargetChoice,
5
+ memberChoices,
6
+ nestedPickKeysToPrune,
7
+ poolMemberSites,
8
+ poolMemberSitesOf
9
+ } from "../chunk-HTYMW5CH.js";
10
+ import "../chunk-3VZZDKRA.js";
11
+ import "../chunk-W6GC6OKK.js";
12
+ import "../chunk-B3DP42OM.js";
13
+ import "../chunk-IUAAXXNO.js";
14
+ import "../chunk-IHE6KVC3.js";
15
+ import "../chunk-LHZXYFBU.js";
16
+ import "../chunk-YBLDE5CG.js";
17
+ import "../chunk-ZUQW5VBZ.js";
18
+ import "../chunk-LVQLWRCU.js";
19
+ import "../chunk-CM5CWO4K.js";
20
+ import "../chunk-ZCTUYGNV.js";
21
+ import "../chunk-3TM34RSJ.js";
22
+ import "../chunk-PDJSUH24.js";
23
+ import "../chunk-WELIKLZF.js";
24
+ export {
25
+ featOfSite,
26
+ featPickSites,
27
+ isTargetChoice,
28
+ memberChoices,
29
+ nestedPickKeysToPrune,
30
+ poolMemberSites,
31
+ poolMemberSitesOf
32
+ };
@@ -1,11 +1,16 @@
1
1
  import {
2
2
  characterSchema
3
- } from "../chunk-PZCE7DJM.js";
3
+ } from "../chunk-T6QIF5XR.js";
4
4
  import "../chunk-S7REMWW4.js";
5
+ import {
6
+ keptSlugForLink
7
+ } from "../chunk-CM5CWO4K.js";
8
+ import "../chunk-ZCTUYGNV.js";
5
9
 
6
10
  // src/pc/pc.parser.ts
7
11
  import * as yaml from "js-yaml";
8
12
  function parsePC(source) {
13
+ var _a;
9
14
  let raw;
10
15
  try {
11
16
  raw = yaml.load(source);
@@ -34,8 +39,20 @@ function parsePC(source) {
34
39
  if (legacyState.attuned_items) {
35
40
  delete legacyState.attuned_items;
36
41
  }
42
+ for (const entry of (_a = data.equipment) != null ? _a : []) {
43
+ if (typeof entry.item !== "string") continue;
44
+ const next = migrateRetiredItemLink(entry.item);
45
+ if (next !== null) entry.item = next;
46
+ }
37
47
  return { success: true, data };
38
48
  }
49
+ function migrateRetiredItemLink(item) {
50
+ var _a;
51
+ const m = /^\[\[([^\]|]+)(\|[^\]]*)?\]\]$/.exec(item.trim());
52
+ const kept = keptSlugForLink(m ? m[1] : item);
53
+ if (kept === void 0) return null;
54
+ return m ? `[[${kept}${(_a = m[2]) != null ? _a : ""}]]` : kept;
55
+ }
39
56
  export {
40
57
  parsePC
41
58
  };
@@ -9,7 +9,14 @@ export interface PoolRegistry {
9
9
  getByTypeAndSlug(entityType: string, slug: string): RegisteredEntity | undefined;
10
10
  }
11
11
  export declare function levelPrereqMax(d: OptionalFeatureEntity): number;
12
- export declare function resolvePool(rc: ResolvedClass, classIndex: number, pool: SelectionPool, registry: PoolRegistry, index: ResourceIndex): ResolvedPool;
12
+ /** The pool's ANCHOR level (its picks live in `choices[anchorLevel][pool.id]`): the first level whose count column
13
+ * carries a value of at least 1, else 1; `columnSeen` says whether any level carried the column at all. ONE derivation
14
+ * shared by `resolvePool` and the nested-choice enumerator (D2b-A, `pc.member-choices.ts`), so the two always agree. */
15
+ export declare function poolAnchorLevel(entity: Pick<NonNullable<ResolvedClass["entity"]>, "table">, pool: Pick<SelectionPool, "count">): {
16
+ anchorLevel: number;
17
+ columnSeen: boolean;
18
+ };
19
+ export declare function resolvePool(rc: ResolvedClass, classIndex: number, pool: SelectionPool, registry: PoolRegistry, index: ResourceIndex, edition?: string): ResolvedPool;
13
20
  export declare function resolveAllPools(resolved: ResolvedCharacter, registry: PoolRegistry, index: ResourceIndex): ResolvedPool[];
14
21
  /** The stored picks that survived resolution but are NOT in the collapsed `available` list, compared by FULL
15
22
  * slug: exactly the rule the plugin's `strandedSelections` used before T3 retires it (R4-G5 §3.2.3). Because
@@ -1,15 +1,25 @@
1
1
  import {
2
2
  levelPrereqMax,
3
+ poolAnchorLevel,
3
4
  resolveAllPools,
4
5
  resolvePool,
5
6
  strandedPicks
6
- } from "../chunk-O4SRD3J5.js";
7
- import "../chunk-PP2UHLBA.js";
7
+ } from "../chunk-3VZZDKRA.js";
8
+ import "../chunk-W6GC6OKK.js";
9
+ import "../chunk-B3DP42OM.js";
8
10
  import "../chunk-IUAAXXNO.js";
11
+ import "../chunk-IHE6KVC3.js";
12
+ import "../chunk-LHZXYFBU.js";
13
+ import "../chunk-ZUQW5VBZ.js";
9
14
  import "../chunk-LVQLWRCU.js";
10
- import "../chunk-6X4KUDMU.js";
15
+ import "../chunk-CM5CWO4K.js";
16
+ import "../chunk-ZCTUYGNV.js";
17
+ import "../chunk-3TM34RSJ.js";
18
+ import "../chunk-PDJSUH24.js";
19
+ import "../chunk-WELIKLZF.js";
11
20
  export {
12
21
  levelPrereqMax,
22
+ poolAnchorLevel,
13
23
  resolveAllPools,
14
24
  resolvePool,
15
25
  strandedPicks
@@ -2,31 +2,39 @@ import {
2
2
  collectChosenProficiencies,
3
3
  collectProficiencyGrants,
4
4
  computeEffectiveProficiencies
5
- } from "../chunk-2INMRR3Q.js";
6
- import "../chunk-4ISR76DH.js";
7
- import "../chunk-DPUJDOKV.js";
8
- import "../chunk-O4SRD3J5.js";
9
- import "../chunk-PP2UHLBA.js";
10
- import "../chunk-IUAAXXNO.js";
11
- import "../chunk-YHYTW5QA.js";
12
- import "../chunk-3HX5VLWP.js";
13
- import "../chunk-PVCEA4HZ.js";
14
- import "../chunk-UBBKSYBY.js";
15
- import "../chunk-CBEKVAX4.js";
5
+ } from "../chunk-ONTGZR5T.js";
6
+ import "../chunk-2LULMQTF.js";
7
+ import "../chunk-H5PTKYXL.js";
8
+ import "../chunk-TULQ4FFX.js";
16
9
  import "../chunk-TOM66P2P.js";
17
10
  import "../chunk-KU3YLF6D.js";
11
+ import "../chunk-HTYMW5CH.js";
12
+ import "../chunk-KSTV7J2U.js";
13
+ import "../chunk-DPUJDOKV.js";
14
+ import "../chunk-LBEXLN6I.js";
18
15
  import {
19
16
  proficiencyLabel,
20
17
  toProfSlug
21
18
  } from "../chunk-RLGQ5PZZ.js";
22
- import "../chunk-LVQLWRCU.js";
23
- import "../chunk-WXWPK3LI.js";
24
- import "../chunk-6X4KUDMU.js";
19
+ import "../chunk-3VZZDKRA.js";
20
+ import "../chunk-W6GC6OKK.js";
21
+ import "../chunk-B3DP42OM.js";
22
+ import "../chunk-IUAAXXNO.js";
23
+ import "../chunk-YHYTW5QA.js";
24
+ import "../chunk-VRV3NNTA.js";
25
+ import "../chunk-PVCEA4HZ.js";
26
+ import "../chunk-IHE6KVC3.js";
27
+ import "../chunk-LHZXYFBU.js";
25
28
  import "../chunk-YBLDE5CG.js";
29
+ import "../chunk-ZUQW5VBZ.js";
30
+ import "../chunk-LVQLWRCU.js";
31
+ import "../chunk-CM5CWO4K.js";
26
32
  import "../chunk-EVMUJYUD.js";
27
33
  import "../chunk-VTTA2ALZ.js";
28
- import "../chunk-XY6X2APM.js";
34
+ import "../chunk-ZCTUYGNV.js";
35
+ import "../chunk-7Q2VPKCD.js";
29
36
  import "../chunk-ZDAEGJH4.js";
37
+ import "../chunk-3TM34RSJ.js";
30
38
  import "../chunk-PDJSUH24.js";
31
39
  import "../chunk-WELIKLZF.js";
32
40
  import "../chunk-4U55VNC7.js";
@@ -1,10 +1,16 @@
1
+ import {
2
+ qualifiedGrantCovers
3
+ } from "../chunk-3LWMFYKS.js";
4
+ import "../chunk-YDGMBMYI.js";
1
5
  import {
2
6
  normKey
3
7
  } from "../chunk-RLGQ5PZZ.js";
8
+ import "../chunk-ZCTUYGNV.js";
4
9
 
5
10
  // src/pc/pc.proficiency-query.ts
6
11
  function isProficientWithWeapon(weapon, profs) {
7
12
  if (profs.weapons.specific.some((e) => e === weapon.slug || normKey(e) === normKey(weapon.name))) return true;
13
+ if (profs.weapons.specific.some((e) => qualifiedGrantCovers(e, weapon))) return true;
8
14
  const baseCategory = weapon.category.split("-")[0];
9
15
  return profs.weapons.categories.includes(baseCategory);
10
16
  }
@@ -4,7 +4,7 @@ import type { RaceEntity } from "@archivist-gg/dnd5e/race/race.types";
4
4
  import type { EntityRegistry } from "@archivist-gg/core";
5
5
  import { type UnarmedStrikeSpec } from "./pc.equipment.js";
6
6
  import { type FeatureEffectTotals } from "./pc.feature-effects.js";
7
- import type { ACTerm, DerivedStats, ProficiencySet, ResolvedCharacter, ResolvedClass, CharacterOverrides } from "./pc.types.js";
7
+ import type { ACTerm, AttackRow, DamageRider, DerivedStats, ProficiencySet, ResolvedCharacter, ResolvedClass, CharacterOverrides } from "./pc.types.js";
8
8
  /**
9
9
  * PHB "fixed average" value per hit die (per level beyond first). Called
10
10
  * "average" in the PHB but actually ceil((die + 1) / 2); equivalent to
@@ -23,19 +23,14 @@ export declare function parseDieSize(die: string | number | undefined | null): n
23
23
  */
24
24
  export declare function flattenRaceAsi(race: RaceEntity | null): Partial<Record<Ability, number>>;
25
25
  /**
26
- * Sums the LEGACY class-level ASI-BRANCH allocations (`choices[lvl].asi`) per
27
- * ability across every class. This is the path taken when an L4/L8-style
28
- * "Ability Score Increase or Feat" decision resolves to the plain +2 ASI branch
29
- * rather than a feat. Shared by both `computeAbilityScores`' fold and
30
- * `abilityBonusBreakdown`'s `class` bucket so the two reads can never drift.
26
+ * Sums the LEGACY class-level ASI-BRANCH allocations (`choices[lvl].asi`) per ability across every class: the path of an
27
+ * L4/L8-style "Ability Score Increase or Feat" decision saved on the plain +2 ASI branch rather than a feat. Shared by
28
+ * `computeAbilityScores`' fold and `abilityBonusBreakdown`'s `class` bucket so the two reads can never drift.
31
29
  *
32
- * Disjoint from chosen-feat ability-points (`choices[lvl]["feat:<id>"]`) and from
33
- * origin ability-points · no source double-counts.
34
- *
35
- * Since R4-P4 Decision B an `asi` that SHARES a level with a string `feat` key is
36
- * discarded as an orphan rather than folded: that level took the feat branch, and
37
- * the `asi` beside it is residue the picker never cleared on a branch switch.
38
- * Folding both paid the same slot twice (Volker.md drew FOUR points from one L4).
30
+ * The level gate is the ONE predicate `legacyAsiBranch` (pc.asi-flatten.ts, H234 H4(2)), shared with the Builder's ledger
31
+ * alias and write path: a level whose `feat` is a string took the feat branch, and its `asi` is an orphan discarded since
32
+ * R4-P4 Decision B (Volker.md drew FOUR points from one L4 when both folded). Disjoint from chosen-feat ability-points
33
+ * (`choices[lvl]["feat:<id>"]`, collectClassFeatAbilityPoints) and from origin ability-points: no source double-counts.
39
34
  */
40
35
  export declare function collectClassAsiBranch(resolved: ResolvedCharacter): Partial<Record<Ability, number>>;
41
36
  /** Per-ability bonus provenance for the builder's obelisk captions:
@@ -69,6 +64,10 @@ export declare function hpLevelCount(classes: ResolvedClass[]): number;
69
64
  * so a later popup can render the two components separately.
70
65
  */
71
66
  export declare function multiclassMaxHP(classes: ResolvedClass[], conMod: number): number;
67
+ /** Does a damage rider reach this attack row (ART-c1 Task 9b, controller ruling 8)? A rider with no `scope` reaches
68
+ * every row (today's reach); a scoped one reaches a row when ANY of its words matches it: `melee` / `ranged` the
69
+ * row's `weaponCategory`, `unarmed` the engine's Unarmed Strike row, `finesse` / `thrown` the row's properties. */
70
+ export declare function riderReachesRow(rider: DamageRider, row: AttackRow): boolean;
72
71
  /**
73
72
  * The BEST APPLICABLE unarmoured formula (R4-G7 T6a, spec §4): the plain 10 + DEX mod, against every
74
73
  * `unarmored-ac` effect that folds right now (its `base ?? 10` plus the modifier of every ability its
@@ -121,29 +120,33 @@ export declare function speedFromRace(resolved: ResolvedCharacter): number;
121
120
  * double-counts. The chosen feat entity is resolved from `resolved.feats`
122
121
  * (already looked up by the resolver) — no registry needed here.
123
122
  *
124
- * The L19 Epic Boon folds through this SAME path, but only as of R4-P4's
125
- * re-key (live in the SRD data from that phase's regeneration). This docblock
126
- * earlier cited it as an existing example, which it was not. EVERY reader OF THE
127
- * FEAT PICK keys on the LITERAL string `feat`, and there are THREE of them, not
128
- * the two the R4-P4 spec §2.3 and task brief enumerate: this function
129
- * (`block.feat`, below), `collectFeatPicks` (pc.resolver.ts) and
130
- * `PCResolver.resolve`'s feat-to-spell application pass, the two
131
- * `collectFeatGrantedSpells` calls (pc.resolver.ts), the one that
132
- * makes a SPELL-granting boon work. Note the qualifier: this is NOT a claim that
133
- * every reader of a saved class choice block keys on `feat`. Others read the very
134
- * same block by OTHER keys · `collectClassAsiBranch` (above) reads the literal
135
- * `.asi`, while `resolvePool` (pc.pools.ts) and `resolveChosenInline`
136
- * (pc.resolver.ts) read by a DYNAMIC pool/choice id. As of R4-P4 Decision B
137
- * `collectClassAsiBranch` also tests `block.feat`, but only to DETECT the feat
138
- * branch, not to consume the pick. pc.decision-engine.ts is NOT a fourth:
139
- * it reads generically by `choice.id`, which is exactly why re-keying works at
140
- * all. srd-2024.yaml authored the boon's pick `id: epic-boon`, so an L19
141
- * selection persisted under `choices[19]["epic-boon"]`, which no reader looks
142
- * at: the boon resolved to no feat, granted no spells, and contributed no
143
- * ability points at all. Re-keying the authored pick to `id: feat` is what
144
- * makes it fold. No persisted GRANDCHILD key moved with it ·
145
- * pc.decision-engine.ts builds `feat:<childId>` off a hardcoded prefix,
146
- * independent of the parent choice's own id.
123
+ * The L19 Epic Boon folds through this SAME path, but only as of R4-P4's re-key
124
+ * (live in the SRD data from that phase's regeneration). This docblock earlier
125
+ * cited it as an existing example, which it was not. EVERY reader OF THE FEAT
126
+ * PICK keys on the LITERAL string `feat`, and there are FOUR of them, not the two
127
+ * the R4-P4 spec §2.3 and task brief enumerate: this function (`block.feat`,
128
+ * below), `collectFeatPicks` (pc.resolver.ts), `PCResolver.resolve`'s
129
+ * feat-to-spell application pass, the two `collectFeatGrantedSpells` calls
130
+ * (pc.resolver.ts), the one that makes a SPELL-granting boon work, and
131
+ * `visitProficiencyChoices`' arm (A) (pc.decision-engine.ts, R4-G3b §8), which
132
+ * reads `block.feat` to walk the chosen feat's own proficiency choices. Note the
133
+ * qualifier: this is NOT a claim that every reader of a saved class choice block
134
+ * keys on `feat`. Others read the very same block by OTHER keys ·
135
+ * `collectClassAsiBranch` (above) reads the legacy `.asi` through
136
+ * `legacyAsiBranch` (pc.asi-flatten.ts), while `resolvePool` (pc.pools.ts) and
137
+ * `resolveChosenInline` (pc.resolver.ts) read by a DYNAMIC pool/choice id.
138
+ * `legacyAsiBranch` also tests `block.feat`, but only to DETECT the feat branch
139
+ * (R4-P4 Decision B), not to consume the pick. pc.decision-engine.ts's LEDGER
140
+ * (`buildItem`) is NOT a reader: it reads generically by `choice.id`, which is
141
+ * exactly why re-keying works at all; since H234 its class walk also SYNTHESIZES
142
+ * a `feat` answer, the read-only alias for a level saved in the older ASI shape
143
+ * (`legacyAsiReader`), which consumes no persisted `feat` key. srd-2024.yaml
144
+ * authored the boon's pick `id: epic-boon`, so an L19 selection persisted under
145
+ * `choices[19]["epic-boon"]`, which no reader looks at: the boon resolved to no
146
+ * feat, granted no spells, and contributed no ability points at all. Re-keying
147
+ * the authored pick to `id: feat` is what makes it fold. No persisted GRANDCHILD
148
+ * key moved with it · pc.decision-engine.ts builds `feat:<childId>` off a
149
+ * hardcoded prefix, independent of the parent choice's own id.
147
150
  *
148
151
  * Clamps defensively (per-ability max_per, then stops at the points total in
149
152
  * ABILITY_KEYS order), mirroring collectChosenAbilityPoints.