@archivist-gg/dnd5e 0.3.10 → 0.3.13

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 (174) 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-2LULMQTF.js +14 -0
  11. package/dist/{chunk-CBEKVAX4.js → chunk-4BZ47YJ4.js} +10 -3
  12. package/dist/{chunk-22MOUU2G.js → chunk-4SLOJXJ4.js} +1 -1
  13. package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
  14. package/dist/{chunk-J77CKYV3.js → chunk-5KGV6TF7.js} +1 -1
  15. package/dist/{chunk-3UNP3G4D.js → chunk-6ZY3U6BQ.js} +1 -1
  16. package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
  17. package/dist/{chunk-2M34FLAY.js → chunk-BRGLDWUP.js} +3 -1
  18. package/dist/chunk-CM5CWO4K.js +735 -0
  19. package/dist/{chunk-MI7P3NX3.js → chunk-DPM6V7YX.js} +2 -2
  20. package/dist/chunk-EJP263OP.js +186 -0
  21. package/dist/{chunk-G247QXWW.js → chunk-EL6QPF6I.js} +1 -1
  22. package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
  23. package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
  24. package/dist/{chunk-PI4LLJG4.js → chunk-FPGXFD2M.js} +2 -2
  25. package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
  26. package/dist/{chunk-NWDF5HG3.js → chunk-G7ED5H2G.js} +1 -1
  27. package/dist/chunk-H5PTKYXL.js +101 -0
  28. package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
  29. package/dist/{chunk-PP2UHLBA.js → chunk-HJQNK3J5.js} +8 -0
  30. package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
  31. package/dist/chunk-IHE6KVC3.js +13 -0
  32. package/dist/{chunk-BLRW2UU6.js → chunk-J53ERF6K.js} +2 -2
  33. package/dist/{chunk-MQ747UCR.js → chunk-JNNNBEUH.js} +65 -2
  34. package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
  35. package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
  36. package/dist/chunk-LBEXLN6I.js +91 -0
  37. package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
  38. package/dist/{chunk-OYUEUKKF.js → chunk-LVX6TQ3R.js} +12 -8
  39. package/dist/{chunk-R747YKS7.js → chunk-M2OWVAZG.js} +1 -1
  40. package/dist/{chunk-7YU4NPKR.js → chunk-MC5YJ4PB.js} +1 -1
  41. package/dist/{chunk-JCEV7KYN.js → chunk-MUIU7RZ3.js} +1 -1
  42. package/dist/{chunk-JSZ4H6AQ.js → chunk-MWCCGPG3.js} +1 -1
  43. package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
  44. package/dist/{chunk-S56D6B6C.js → chunk-PLOSP4XQ.js} +3 -3
  45. package/dist/{chunk-JANNRGJC.js → chunk-PX25R3DK.js} +1 -1
  46. package/dist/{chunk-V373TRJE.js → chunk-Q5XTEYHD.js} +191 -125
  47. package/dist/{chunk-MAH6DCRI.js → chunk-Q6UOHCCT.js} +1 -1
  48. package/dist/{chunk-HLQAFZKQ.js → chunk-QEO7LYTG.js} +216 -95
  49. package/dist/{chunk-PJMG5XV3.js → chunk-QSBJ6NEM.js} +1 -1
  50. package/dist/{chunk-BL3VELKP.js → chunk-R2V5LN3I.js} +1 -1
  51. package/dist/{chunk-4DOMDEBZ.js → chunk-RQNJXADQ.js} +1 -1
  52. package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
  53. package/dist/chunk-T5GZBKIQ.js +927 -0
  54. package/dist/{chunk-PZCE7DJM.js → chunk-UE6LKRXQ.js} +15 -1
  55. package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
  56. package/dist/{chunk-QHMWA3SZ.js → chunk-VDPRBUU5.js} +1 -1
  57. package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
  58. package/dist/{chunk-V6LJFP4R.js → chunk-X7VZY4ON.js} +2 -2
  59. package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
  60. package/dist/{chunk-BIA32MQ5.js → chunk-XJRNEQPD.js} +1 -1
  61. package/dist/{chunk-OZP6JFGT.js → chunk-XY6X2APM.js} +3 -1
  62. package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
  63. package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
  64. package/dist/{chunk-VQAXTIBW.js → chunk-ZDAEGJH4.js} +2 -0
  65. package/dist/{chunk-XTRDCSJB.js → chunk-ZMJQUZQH.js} +4 -1
  66. package/dist/chunk-ZUQW5VBZ.js +89 -0
  67. package/dist/class/class.codec.js +7 -7
  68. package/dist/class/class.parser.js +6 -6
  69. package/dist/class/class.schema.d.ts +10 -0
  70. package/dist/class/class.schema.js +5 -5
  71. package/dist/entities/base-item-resolver.js +2 -2
  72. package/dist/entities/slug.d.ts +18 -8
  73. package/dist/entities/slug.js +3 -1
  74. package/dist/feat/feat.codec.js +5 -5
  75. package/dist/feat/feat.parser.js +4 -4
  76. package/dist/feat/feat.schema.d.ts +16 -3
  77. package/dist/feat/feat.schema.js +3 -3
  78. package/dist/index.js +5277 -2017
  79. package/dist/item/item.actions-map.d.ts +40 -5
  80. package/dist/item/item.actions-map.js +5 -84
  81. package/dist/item/item.attunement.js +3 -9
  82. package/dist/item/item.bonuses.js +5 -2
  83. package/dist/item/item.codec.js +3 -3
  84. package/dist/item/item.conditions.js +4 -1
  85. package/dist/item/item.conditions.types.d.ts +4 -0
  86. package/dist/item/item.cost.d.ts +3 -0
  87. package/dist/item/item.cost.js +29 -0
  88. package/dist/item/item.icon.d.ts +15 -0
  89. package/dist/item/item.icon.js +211 -0
  90. package/dist/item/item.parser.js +2 -2
  91. package/dist/item/item.schema.d.ts +16 -1
  92. package/dist/item/item.schema.js +3 -1
  93. package/dist/item/item.types.d.ts +9 -2
  94. package/dist/monster/monster.parser.js +5 -5
  95. package/dist/monster/monster.schema.js +4 -4
  96. package/dist/optional-feature/optional-feature.codec.js +4 -4
  97. package/dist/optional-feature/optional-feature.parser.js +3 -3
  98. package/dist/optional-feature/optional-feature.schema.d.ts +229 -3
  99. package/dist/optional-feature/optional-feature.schema.js +6 -2
  100. package/dist/pc/pc.additional-spells.js +4 -4
  101. package/dist/pc/pc.asi-flatten.d.ts +62 -1
  102. package/dist/pc/pc.asi-flatten.js +16 -0
  103. package/dist/pc/pc.conditions.js +1 -1
  104. package/dist/pc/pc.containment.d.ts +45 -0
  105. package/dist/pc/pc.containment.js +24 -0
  106. package/dist/pc/pc.decision-engine.d.ts +21 -3
  107. package/dist/pc/pc.decision-engine.js +23 -14
  108. package/dist/pc/pc.entry-overrides.d.ts +79 -0
  109. package/dist/pc/pc.entry-overrides.js +40 -0
  110. package/dist/pc/pc.equipment.d.ts +2 -2
  111. package/dist/pc/pc.equipment.js +18 -7
  112. package/dist/pc/pc.feature-effects.js +2 -2
  113. package/dist/pc/pc.infusions.d.ts +220 -0
  114. package/dist/pc/pc.infusions.js +64 -0
  115. package/dist/pc/pc.parser.js +18 -1
  116. package/dist/pc/pc.pools.d.ts +1 -1
  117. package/dist/pc/pc.pools.js +11 -3
  118. package/dist/pc/pc.proficiencies.js +21 -14
  119. package/dist/pc/pc.recalc.d.ts +39 -36
  120. package/dist/pc/pc.recalc.js +60 -32
  121. package/dist/pc/pc.resolver.js +21 -14
  122. package/dist/pc/pc.resource-seed.js +1 -1
  123. package/dist/pc/pc.resources.d.ts +6 -1
  124. package/dist/pc/pc.resources.js +3 -1
  125. package/dist/pc/pc.rest.d.ts +21 -1
  126. package/dist/pc/pc.rest.js +52 -19
  127. package/dist/pc/pc.schema.d.ts +14 -0
  128. package/dist/pc/pc.schema.js +1 -1
  129. package/dist/pc/pc.slotting.d.ts +36 -3
  130. package/dist/pc/pc.slotting.js +13 -5
  131. package/dist/pc/pc.tool-picks.d.ts +51 -0
  132. package/dist/pc/pc.tool-picks.js +18 -0
  133. package/dist/pc/pc.types.d.ts +70 -12
  134. package/dist/pc/pool-layout.d.ts +14 -0
  135. package/dist/pc/pool-layout.js +7 -3
  136. package/dist/race/race.codec.js +6 -6
  137. package/dist/race/race.parser.js +5 -5
  138. package/dist/race/race.schema.js +4 -4
  139. package/dist/schemas/attack-schema.d.ts +1 -1
  140. package/dist/schemas/choice-schema.js +2 -2
  141. package/dist/schemas/feature-effect-schema.d.ts +16 -3
  142. package/dist/schemas/feature-effect-schema.js +1 -1
  143. package/dist/schemas/feature-schema.js +3 -3
  144. package/dist/schemas/selection-pool-schema.d.ts +10 -0
  145. package/dist/schemas/selection-pool-schema.js +1 -1
  146. package/dist/spell/spell.codec.js +3 -3
  147. package/dist/spell/spell.parser.js +2 -2
  148. package/dist/spell/spell.scaling.d.ts +34 -10
  149. package/dist/spell/spell.scaling.js +36 -4
  150. package/dist/spell/spell.schema.d.ts +1 -0
  151. package/dist/spell/spell.schema.js +1 -1
  152. package/dist/spell/spell.types.d.ts +4 -0
  153. package/dist/srd/retired-items.d.ts +14 -0
  154. package/dist/srd/retired-items.js +11 -0
  155. package/dist/subclass/subclass.codec.js +7 -7
  156. package/dist/subclass/subclass.parser.js +6 -6
  157. package/dist/subclass/subclass.schema.d.ts +10 -0
  158. package/dist/subclass/subclass.schema.js +5 -5
  159. package/dist/types/choice.d.ts +8 -0
  160. package/dist/types/equipment-grant.d.ts +18 -1
  161. package/dist/types/equipment-grant.js +12 -0
  162. package/dist/types/feature-effect.d.ts +6 -1
  163. package/dist/types/optional-feature.types.d.ts +79 -1
  164. package/dist/types/selection-pool.d.ts +16 -1
  165. package/dist/weapon/weapon.classify.d.ts +10 -8
  166. package/dist/weapon/weapon.classify.js +2 -2
  167. package/dist/weapon/weapon.codec.js +3 -3
  168. package/dist/weapon/weapon.parser.js +2 -2
  169. package/dist/weapon/weapon.schema.d.ts +1 -0
  170. package/dist/weapon/weapon.schema.js +1 -1
  171. package/dist/weapon/weapon.types.d.ts +2 -0
  172. package/package.json +1 -1
  173. package/dist/chunk-O4SRD3J5.js +0 -165
  174. package/dist/chunk-WXWPK3LI.js +0 -55
@@ -1,20 +1,28 @@
1
1
  import {
2
+ armorAcTerm,
2
3
  defaultSlotForType,
3
4
  effectiveArmor,
5
+ effectiveWeapon,
4
6
  isArmorEntity,
5
7
  isItemEntity,
6
8
  isShieldArmor,
9
+ isTwoHandedWeapon,
7
10
  isWeaponEntity,
8
- resolveEntityForEntry
9
- } from "../chunk-UBBKSYBY.js";
10
- import "../chunk-WXWPK3LI.js";
11
- import "../chunk-6X4KUDMU.js";
11
+ resolveEntityForEntry,
12
+ slotAcTerms
13
+ } from "../chunk-LHZXYFBU.js";
14
+ import "../chunk-CM5CWO4K.js";
15
+ import "../chunk-ZCTUYGNV.js";
12
16
  export {
17
+ armorAcTerm,
13
18
  defaultSlotForType,
14
19
  effectiveArmor,
20
+ effectiveWeapon,
15
21
  isArmorEntity,
16
22
  isItemEntity,
17
23
  isShieldArmor,
24
+ isTwoHandedWeapon,
18
25
  isWeaponEntity,
19
- resolveEntityForEntry
26
+ resolveEntityForEntry,
27
+ slotAcTerms
20
28
  };
@@ -0,0 +1,51 @@
1
+ import type { Choice } from "@archivist-gg/dnd5e/types/choice";
2
+ /** The three tool CATEGORIES the rules name ("one type of Artisan's Tools", "a Musical Instrument", "a Gaming
3
+ * Set"). The key is the category token the data writes. */
4
+ export type ToolCategory = "musical-instrument" | "artisan's-tools" | "gaming-set";
5
+ interface ToolCategoryDef {
6
+ /** The category's members in the ONE tool list (`types/choice.ts`), never a second copy. */
7
+ pool: readonly string[];
8
+ /** The item entity `type` its members carry (SRD 5e, SRD 2024, PHB 2024 and XGE item notes all write these). */
9
+ itemType: string;
10
+ /** The noun phrase a pick label reads ("Choose a musical instrument"). */
11
+ label: string;
12
+ }
13
+ export declare const TOOL_CATEGORIES: Readonly<Record<ToolCategory, ToolCategoryDef>>;
14
+ /** A category token read as WORDS: camelCase split (`weaponSimple`), lower-cased, apostrophes dropped (ASCII,
15
+ * U+2019 and U+02BC), any run of space, hyphen or underscore a separator, and each word singularised by ONE
16
+ * trailing "s". So `artisan's-tools`, `Artisans Tools` and `artisan-tool` all read `["artisan", "tool"]`, and
17
+ * `Musical Instruments` reads `["musical", "instrument"]`. Used for category tokens and item `type` values alike. */
18
+ export declare function categoryWords(token: string): string[];
19
+ /** The tool categories a token names: one (`gaming-set`), or several for an `X-or-Y` union
20
+ * (`musical-instrument-or-artisan's-tools`, the PHB 2024 Monk's kit). `undefined` unless EVERY part of the token
21
+ * is a tool category, so a slug (`dice-set`, `smith's-tools`) or a weapon class is never read as one. */
22
+ export declare function toolCategoriesOf(token: string): ToolCategory[] | undefined;
23
+ /** A tool pool with every category token expanded to its members, in authored order, deduplicated on the
24
+ * canonical slug (first spelling wins). A plain tool slug passes through verbatim: the pick canonicalises it
25
+ * downstream exactly as before. */
26
+ export declare function expandToolPool(from: readonly string[]): string[];
27
+ /** What a tool pick authored OUTSIDE `choices` becomes. A pick whose count covers its whole pool AND that names its
28
+ * tools outright ({@link namesToolsOutright}) has no alternatives, so it is a GRANT (the importer writes the PHB 2024
29
+ * Druid's Herbalism Kit, the Rogue's Thieves' Tools and the TCE/EFA Artificer's two granted tools this way); any
30
+ * other pick is a `select-proficiency` decision over the expanded pool. */
31
+ export interface ToolPicks {
32
+ decisions: Choice[];
33
+ grants: string[];
34
+ }
35
+ /** A CLASS's `proficiencies.tools.choice` (`{count, from}`, admitted by `ToolProficiency`, written by the importer
36
+ * and by hand, e.g. the Captain Lugen Bard's three instruments). The decision is a level-1 class pick with id
37
+ * `tool`, the id the SRD overlay gives the same pick in `choices`, so a later re-import into `choices` keeps a
38
+ * persisted pick. An AUTHORED tool `select-proficiency` in the class's own `choices` wins: no second decision. */
39
+ export declare function classToolPicks(entity: {
40
+ choices?: unknown;
41
+ proficiencies?: unknown;
42
+ } | null | undefined): ToolPicks;
43
+ /** A BACKGROUND's `tool_proficiencies` entries of `kind: "choice"` (`{count, from}`, admitted by
44
+ * `BackgroundToolProficiency`; the PHB 2024, EFA and FRHoF imports carry a category token, e.g. `[gaming-set]`).
45
+ * Ids `tool`, then `tool-2`, `tool-3`: `tool` is the SRD overlay's id for the Soldier's authored pick. An AUTHORED
46
+ * tool `select-proficiency` in the background's `choices` wins, as on the class. */
47
+ export declare function backgroundToolPicks(bg: {
48
+ choices?: unknown;
49
+ tool_proficiencies?: unknown;
50
+ } | null | undefined): ToolPicks;
51
+ export {};
@@ -0,0 +1,18 @@
1
+ import {
2
+ TOOL_CATEGORIES,
3
+ backgroundToolPicks,
4
+ categoryWords,
5
+ classToolPicks,
6
+ expandToolPool,
7
+ toolCategoriesOf
8
+ } from "../chunk-H5PTKYXL.js";
9
+ import "../chunk-KU3YLF6D.js";
10
+ import "../chunk-RLGQ5PZZ.js";
11
+ export {
12
+ TOOL_CATEGORIES,
13
+ backgroundToolPicks,
14
+ categoryWords,
15
+ classToolPicks,
16
+ expandToolPool,
17
+ toolCategoriesOf
18
+ };
@@ -1,6 +1,7 @@
1
1
  import type { Ability } from "../types/choice.js";
2
2
  import type { ArmorEntity } from "../armor/armor.types.js";
3
3
  import type { WeaponEntity } from "../weapon/weapon.types.js";
4
+ import type { WeaponScope } from "../types/feature-effect.js";
4
5
  import type { ItemEntity } from "../item/item.types.js";
5
6
  import type { SkillSlug, Feature, Choice } from "@archivist-gg/dnd5e";
6
7
  import type { ClassEntity } from "@archivist-gg/dnd5e/class/class.types";
@@ -11,7 +12,7 @@ import type { BackgroundEntity } from "@archivist-gg/dnd5e/background/background
11
12
  import type { FeatEntity } from "@archivist-gg/dnd5e/feat/feat.types";
12
13
  import type { Spell } from "@archivist-gg/dnd5e/spell/spell.types";
13
14
  import type { OptionalFeatureEntity } from "@archivist-gg/dnd5e/types/optional-feature.types";
14
- import type { PoolLayout } from "../types/selection-pool.js";
15
+ import type { PoolLayout, PoolActive } from "../types/selection-pool.js";
15
16
  import type { ConditionSlug } from "./conditions.constants.js";
16
17
  import type { ResourceIndex } from "./pc.resources.js";
17
18
  /** A persisted decision value: entity slug / inline value (string), multi-select
@@ -59,6 +60,16 @@ export interface EquipmentEntryState {
59
60
  effect: string;
60
61
  };
61
62
  }
63
+ /** ART-a (spec §4.3): the infusion marker on an equipment entry; see `infusionMarkerSchema` in pc.schema.ts. */
64
+ export interface InfusionMarker {
65
+ kind: "infused" | "created";
66
+ by: string;
67
+ seq: number;
68
+ choice?: string;
69
+ charges?: {
70
+ current: number;
71
+ };
72
+ }
62
73
  export type EquipmentEntry = {
63
74
  item: string;
64
75
  equipped?: boolean;
@@ -74,6 +85,12 @@ export type EquipmentEntry = {
74
85
  * touching hand-managed entries. Stripped by finishBuild — absent on every
75
86
  * finished file. */
76
87
  granted_by?: string;
88
+ /** I2a · this entry's stable identity; minted only when something is moved INTO it. */
89
+ id?: string;
90
+ /** I2a · the `id` of the container entry holding this one; ignored while the entry is equipped (C7). */
91
+ in?: string;
92
+ /** ART-a · the infusion marker (spec §4.3): a top-level key, never under `state` or `overrides` (both strict). */
93
+ infusion?: InfusionMarker;
77
94
  };
78
95
  export interface ResolvedEquipped {
79
96
  index: number;
@@ -398,14 +415,28 @@ export interface ResolvedClass {
398
415
  subclass: SubclassEntity | null;
399
416
  choices: Record<number, LevelChoices>;
400
417
  }
418
+ /** One pool member as resolved for a character: a stored PICK (`selected`), a candidate (`available`) or a subclass
419
+ * grant (`grants`). `slug` is always the NOTE's registry slug. A pick is KEYED (ART-a, spec §4.4, §5.1): a COPY of a
420
+ * repeatable note is keyed by its stored `<note slug>#<param>`, so two copies of one note are two entries with one `slug`;
421
+ * a plain pick's `key` is its resolved `slug` (the stored string, or the survivor of a stored twin), unless it was stored
422
+ * with a '#', which is kept; candidates and grants carry `key === slug` and `param: null`. */
401
423
  export interface ResolvedPoolEntry {
402
424
  slug: string;
403
425
  entity: OptionalFeatureEntity;
404
- /** The compendium NAME the REGISTERED entity carries (R4-G5 §9.2.1), stamped at resolve time because `entity`
405
- * is `e.data`, which carries none: MEASURED 2026-09-07 over the WHOLE converter output (226 documents under
406
- * its `OptionalFeatures` folders) and the 7 bundle ones, 0 of 226 and 0 of 7 declare a `compendium` key
407
- * INSIDE the fenced entity body, while 226 of 226 and 7 of 7 declare one in the note's FRONTMATTER, which
408
- * core keeps on `RegisteredEntity`.
426
+ /** ART-a (spec §4.6): the pick key the writers compare (see above); the slug for candidates and grants. */
427
+ key: string;
428
+ /** ART-a: a copy's parameter (a full item slug for `learn`, a row key for `create`); null for any other entry, and for a
429
+ * repeatable note stored without `#` (a copy whose option is `needs-choice`). */
430
+ param: string | null;
431
+ /** ART-a (spec §4.1, §5.2): derived by `isItemBound`. Its subject is an item: no character tracker, no boon fold. */
432
+ itemBound: boolean;
433
+ /** ART-a (spec §5.8): present on every selected copy of a repeatable note. */
434
+ option?: import("./pc.infusions.js").CopyOption;
435
+ /** The compendium NAME the REGISTERED entity carries (R4-G5 §9.2.1), stamped at resolve time because `entity` is
436
+ * `e.data` (an H3-rebound member's is a copy of it), which carries none: MEASURED 2026-09-07 over the WHOLE
437
+ * converter output (226 documents under its `OptionalFeatures` folders) and the 7 bundle ones, 0 of 226 and 0 of 7
438
+ * declare a `compendium` key INSIDE the fenced entity body, while 226 of 226 and 7 of 7 declare one in the note's
439
+ * FRONTMATTER, which core keeps on `RegisteredEntity`.
409
440
  * The plugin's ONE visibility predicate reads it on BOTH surfaces (§3.2.2). Absent when the registry entry
410
441
  * carries none, which in practice means a test double. The COLLAPSE does not read it: its identity is the
411
442
  * slug PREFIX (§9.2.2). */
@@ -435,6 +466,12 @@ export interface ResolvedPool {
435
466
  /** The OWNED resource id the members spend (majority of `consumes.resource` among the ids the
436
467
  * character owns); undefined when no member consumes an owned id (R4-G4 §4.2.3, Gate 0 B1). */
437
468
  resource?: string;
469
+ /** ART-a (spec §4.5): the declaration's `count.label`, copied raw; read through `poolCountLabel` (absent reads "Known"). */
470
+ countLabel?: string;
471
+ /** ART-a (spec §4.5): the declaration's `active`, copied raw; read through `poolActiveWords`. */
472
+ active?: PoolActive;
473
+ /** ART-a (spec §4.5): the declaration's `head_resource`. */
474
+ headResource?: string;
438
475
  }
439
476
  export interface ResolvedCharacter {
440
477
  definition: Character;
@@ -483,6 +520,10 @@ export interface ResolvedCharacter {
483
520
  * such pick. Populated by the resolver's collectChosenWeaponMasteries pass. */
484
521
  weaponMasteries: string[];
485
522
  state: CharacterState;
523
+ /** ART-a (spec §4.6, §5.4): the entry views, counters and flags `buildInfusionContext` derives after the resource
524
+ * index. Absent (no cost) for a character with no item-bound pool and no marker; every fold reads it through
525
+ * `resolveEntryEntity`. */
526
+ infusions?: import("./pc.infusions.js").InfusionContext;
486
527
  }
487
528
  export interface ProficiencySet {
488
529
  categories: string[];
@@ -526,20 +567,24 @@ export interface HPBreakdown {
526
567
  * is a human label for the expand/tooltip. `condition` is the source's own
527
568
  * qualifier ("for a 1st-level spell slot"), CARRIED verbatim and never evaluated,
528
569
  * from a feature effect (R4-G7 T8 RIDER-12) and from an item's `damage_riders`
529
- * entry alike; absent when the source authors none. How the sheet prints a rider
530
- * (a damage chip, or the row's caption) is the plugin renderer's policy, stated
531
- * once at `weapons-table.ts` `renderWeaponRow`. */
570
+ * entry alike; absent when the source authors none. `scope` is a feature effect's
571
+ * structured weapon scope (its `applies_to` words, ART-c1 Task 9b): the merge in
572
+ * `pc.recalc.ts` keeps the rider only on the rows it reaches (`riderReachesRow`);
573
+ * absent = every row. How the sheet prints a rider (always inside the DAMAGE cell,
574
+ * controller ruling 8) is the plugin renderer's policy, stated once at
575
+ * `weapons-table.ts` `renderWeaponRow`. */
532
576
  export interface DamageRider {
533
577
  amount: string;
534
578
  damage_type?: string;
535
579
  source?: string;
536
580
  condition?: string;
581
+ scope?: WeaponScope[];
537
582
  }
538
583
  export interface AttackRow {
539
584
  id: string;
540
585
  name: string;
541
586
  range?: string;
542
- /** Secondary thrown-mode range ("20/60 ft") for a throwable melee weapon.
587
+ /** Secondary thrown-mode range ("20/60 ft.") for a throwable melee weapon.
543
588
  * Display-only; rendered as a stacked muted second line in the Range cell.
544
589
  * Absent otherwise. */
545
590
  thrownRange?: string;
@@ -550,6 +595,10 @@ export interface AttackRow {
550
595
  * the migrated manual override), rendered as extra damage chips. Absent when
551
596
  * none apply (so untouched rows are unchanged). */
552
597
  damageRiders?: DamageRider[];
598
+ /** The weapon's CATEGORY as the attack modes read it (`classifyWeaponRange`): `melee` for a weapon with a melee
599
+ * mode (a thrown melee weapon stays melee), `ranged` for a pure ranged one. A rider's `melee` / `ranged` scope
600
+ * reads it (ART-c1 Task 9b). Absent on the unarmed row. */
601
+ weaponCategory?: "melee" | "ranged";
553
602
  properties: string[];
554
603
  proficient: boolean;
555
604
  breakdown: {
@@ -557,8 +606,9 @@ export interface AttackRow {
557
606
  damage: ACTerm[];
558
607
  };
559
608
  informational?: import("@archivist-gg/dnd5e/item/item.conditions.types").InformationalBonus[];
560
- /** Hand slot the attack came from. Used by Actions tab to find the
561
- * originating equipment entry for the row-expand panel. */
609
+ /** Hand slot the attack came from. Absent on an equipped weapon that holds no hand slot (H234 H5: both hands full, an
610
+ * explicit-slot conflict loser, a non-hand slot) and on the unarmed row. The Actions tab finds the originating
611
+ * equipment entry by the index in the row's `id` (`<index>:standard`), never by this field. */
562
612
  slotKey?: "mainhand" | "offhand";
563
613
  /** Short caption under the weapon name in the Actions tab table.
564
614
  * e.g. "martial · versatile". Display-only. */
@@ -743,6 +793,14 @@ export interface DerivedStats {
743
793
  bonus: number;
744
794
  proficiency: "none" | "proficient" | "expertise";
745
795
  ability: Ability;
796
+ /** The winning half-proficiency term (Jack of All Trades, Remarkable Athlete) on a skill whose tri is `none`;
797
+ * absent otherwise. Additive: the tri never gains a half value, it is also the `overrides.skills.*.proficiency`
798
+ * enum. Set under an `overrides.skills.<s>.bonus` too (the marker states the rule, the bonus is the number).
799
+ * `source` is the owning feature's name. */
800
+ halfProficiency?: {
801
+ source: string;
802
+ amount: number;
803
+ };
746
804
  }>;
747
805
  /** Numeric terms behind the sheet's skill, save, speed and initiative hovers. */
748
806
  statBreakdowns?: {
@@ -17,6 +17,20 @@ export declare const RENDERING_HINT_LAYOUT: Readonly<Record<string, PoolLayout>>
17
17
  * function as the layout, and one junk member beside genuine `dice-pool` members collapsed a
18
18
  * correct majority into a phantom tie. */
19
19
  export declare function derivePoolLayout(entries: ReadonlyArray<ResolvedPoolEntry>): PoolLayout | undefined;
20
+ /** ART-D (spec §7.2): the rows every pool tab draws unless its declaration authors `spell-like`. Applied AT READ by
21
+ * {@link poolPresentation}, never as a zod `.default()`, so a parsed note gains no key (the importer's round trip). */
22
+ export declare const DEFAULT_POOL_ROWS: "blocks";
23
+ export type PoolHead = "dice" | "points";
24
+ export type PoolRows = "blocks" | "spell-like";
25
+ export interface PoolPresentation {
26
+ head: PoolHead;
27
+ rows: PoolRows;
28
+ }
29
+ /** ART-D (spec §7.2, Gate 1 C1): a pool tab's two data axes.
30
+ * - HEAD: an authored `dice-pool` / `point-pool` wins; otherwise the DERIVED layout decides (points for `point-pool`,
31
+ * dice for anything else).
32
+ * - ROWS: `spell-like` only when the declaration AUTHORS it; otherwise {@link DEFAULT_POOL_ROWS}. */
33
+ export declare function poolPresentation(authored?: PoolLayout, derived?: PoolLayout): PoolPresentation;
20
34
  /** The ONE `rendering_hint` to `EntryAffordance` table (R4-G5 §4.2.1, invariant 3): the PER-ENTRY sibling of
21
35
  * `RENDERING_HINT_LAYOUT`. `granted-die-to-ally` is its only key, and the four documents carrying it
22
36
  * (Commander's Strike x2, Rally x2) are field-identical to the other 39 maneuvers except that hint, so a
@@ -1,16 +1,20 @@
1
1
  import {
2
2
  AFFORDANCE_CAPTIONS,
3
+ DEFAULT_POOL_ROWS,
3
4
  RENDERING_HINT_AFFORDANCE,
4
5
  RENDERING_HINT_LAYOUT,
5
6
  deriveEntryAffordance,
6
7
  derivePoolLayout,
7
- formatAffordanceCaption
8
- } from "../chunk-PP2UHLBA.js";
8
+ formatAffordanceCaption,
9
+ poolPresentation
10
+ } from "../chunk-HJQNK3J5.js";
9
11
  export {
10
12
  AFFORDANCE_CAPTIONS,
13
+ DEFAULT_POOL_ROWS,
11
14
  RENDERING_HINT_AFFORDANCE,
12
15
  RENDERING_HINT_LAYOUT,
13
16
  deriveEntryAffordance,
14
17
  derivePoolLayout,
15
- formatAffordanceCaption
18
+ formatAffordanceCaption,
19
+ poolPresentation
16
20
  };
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  raceCodec
3
- } from "../chunk-7YU4NPKR.js";
4
- import "../chunk-BL3VELKP.js";
5
- import "../chunk-V6LJFP4R.js";
3
+ } from "../chunk-MC5YJ4PB.js";
4
+ import "../chunk-R2V5LN3I.js";
5
+ import "../chunk-X7VZY4ON.js";
6
6
  import "../chunk-4U55VNC7.js";
7
- import "../chunk-PI4LLJG4.js";
7
+ import "../chunk-FPGXFD2M.js";
8
8
  import "../chunk-WYGD2UGN.js";
9
9
  import "../chunk-ZJXSXVFP.js";
10
- import "../chunk-2M34FLAY.js";
11
- import "../chunk-XTRDCSJB.js";
10
+ import "../chunk-BRGLDWUP.js";
11
+ import "../chunk-ZMJQUZQH.js";
12
12
  import "../chunk-UA5KS2PL.js";
13
13
  export {
14
14
  raceCodec
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  parseRace
3
- } from "../chunk-BL3VELKP.js";
4
- import "../chunk-V6LJFP4R.js";
3
+ } from "../chunk-R2V5LN3I.js";
4
+ import "../chunk-X7VZY4ON.js";
5
5
  import "../chunk-4U55VNC7.js";
6
- import "../chunk-PI4LLJG4.js";
6
+ import "../chunk-FPGXFD2M.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
8
  import "../chunk-ZJXSXVFP.js";
9
- import "../chunk-2M34FLAY.js";
10
- import "../chunk-XTRDCSJB.js";
9
+ import "../chunk-BRGLDWUP.js";
10
+ import "../chunk-ZMJQUZQH.js";
11
11
  import "../chunk-UA5KS2PL.js";
12
12
  export {
13
13
  parseRace
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  fixedAsiSchema,
3
3
  raceEntitySchema
4
- } from "../chunk-V6LJFP4R.js";
5
- import "../chunk-PI4LLJG4.js";
4
+ } from "../chunk-X7VZY4ON.js";
5
+ import "../chunk-FPGXFD2M.js";
6
6
  import "../chunk-WYGD2UGN.js";
7
7
  import "../chunk-ZJXSXVFP.js";
8
- import "../chunk-2M34FLAY.js";
9
- import "../chunk-XTRDCSJB.js";
8
+ import "../chunk-BRGLDWUP.js";
9
+ import "../chunk-ZMJQUZQH.js";
10
10
  import "../chunk-UA5KS2PL.js";
11
11
  export {
12
12
  fixedAsiSchema,
@@ -2,9 +2,9 @@ import { z } from "zod";
2
2
  export declare const attackSchema: z.ZodObject<{
3
3
  name: z.ZodString;
4
4
  type: z.ZodEnum<{
5
- spell: "spell";
6
5
  melee: "melee";
7
6
  ranged: "ranged";
7
+ spell: "spell";
8
8
  }>;
9
9
  ability: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
10
10
  str: "str";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  choiceSchema
3
- } from "../chunk-2M34FLAY.js";
4
- import "../chunk-XTRDCSJB.js";
3
+ } from "../chunk-BRGLDWUP.js";
4
+ import "../chunk-ZMJQUZQH.js";
5
5
  export {
6
6
  choiceSchema
7
7
  };
@@ -93,11 +93,24 @@ export declare const featureEffectSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
93
93
  kind: z.ZodLiteral<"damage-bonus">;
94
94
  damage_type: z.ZodString;
95
95
  amount: z.ZodString;
96
- applies_to: z.ZodOptional<z.ZodEnum<{
97
- weapon: "weapon";
96
+ applies_to: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
98
97
  spell: "spell";
99
98
  all: "all";
100
- }>>;
99
+ }>, z.ZodEnum<{
100
+ weapon: "weapon";
101
+ melee: "melee";
102
+ ranged: "ranged";
103
+ unarmed: "unarmed";
104
+ finesse: "finesse";
105
+ thrown: "thrown";
106
+ }>, z.ZodArray<z.ZodEnum<{
107
+ weapon: "weapon";
108
+ melee: "melee";
109
+ ranged: "ranged";
110
+ unarmed: "unarmed";
111
+ finesse: "finesse";
112
+ thrown: "thrown";
113
+ }>>]>>;
101
114
  condition: z.ZodOptional<z.ZodString>;
102
115
  subject: z.ZodOptional<z.ZodString>;
103
116
  }, z.core.$strip>, z.ZodObject<{
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  featureEffectSchema
3
- } from "../chunk-XTRDCSJB.js";
3
+ } from "../chunk-ZMJQUZQH.js";
4
4
  export {
5
5
  featureEffectSchema
6
6
  };
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  featureObjectSchema,
3
3
  featureSchema
4
- } from "../chunk-PI4LLJG4.js";
4
+ } from "../chunk-FPGXFD2M.js";
5
5
  import "../chunk-WYGD2UGN.js";
6
6
  import "../chunk-ZJXSXVFP.js";
7
- import "../chunk-2M34FLAY.js";
8
- import "../chunk-XTRDCSJB.js";
7
+ import "../chunk-BRGLDWUP.js";
8
+ import "../chunk-ZMJQUZQH.js";
9
9
  export {
10
10
  featureObjectSchema,
11
11
  featureSchema
@@ -11,8 +11,18 @@ export declare const selectionPoolSchema: z.ZodObject<{
11
11
  }, z.core.$strip>;
12
12
  count: z.ZodObject<{
13
13
  column: z.ZodString;
14
+ label: z.ZodOptional<z.ZodString>;
14
15
  }, z.core.$strip>;
15
16
  replaceable: z.ZodOptional<z.ZodBoolean>;
17
+ active: z.ZodOptional<z.ZodObject<{
18
+ column: z.ZodString;
19
+ label: z.ZodString;
20
+ verb: z.ZodString;
21
+ counter_label: z.ZodOptional<z.ZodString>;
22
+ create_label: z.ZodOptional<z.ZodString>;
23
+ create_verb: z.ZodOptional<z.ZodString>;
24
+ }, z.core.$strip>>;
25
+ head_resource: z.ZodOptional<z.ZodString>;
16
26
  }, z.core.$strip>;
17
27
  export declare const poolGrantSchema: z.ZodObject<{
18
28
  pool: z.ZodString;
@@ -2,7 +2,7 @@ import {
2
2
  poolGrantSchema,
3
3
  selectionPoolSchema,
4
4
  tabDeclSchema
5
- } from "../chunk-23LZLBJK.js";
5
+ } from "../chunk-G6MHJDVT.js";
6
6
  export {
7
7
  poolGrantSchema,
8
8
  selectionPoolSchema,
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  spellCodec
3
- } from "../chunk-JSZ4H6AQ.js";
4
- import "../chunk-OZP6JFGT.js";
5
- import "../chunk-VQAXTIBW.js";
3
+ } from "../chunk-MWCCGPG3.js";
4
+ import "../chunk-XY6X2APM.js";
5
+ import "../chunk-ZDAEGJH4.js";
6
6
  import "../chunk-UA5KS2PL.js";
7
7
  export {
8
8
  spellCodec
@@ -3,8 +3,8 @@ import {
3
3
  normalizeSpellComponents,
4
4
  normalizeSpellDuration,
5
5
  parseSpell
6
- } from "../chunk-OZP6JFGT.js";
7
- import "../chunk-VQAXTIBW.js";
6
+ } from "../chunk-XY6X2APM.js";
7
+ import "../chunk-ZDAEGJH4.js";
8
8
  import "../chunk-UA5KS2PL.js";
9
9
  export {
10
10
  mirrorSpellShapes,
@@ -9,16 +9,39 @@ export interface SpellEffectParts {
9
9
  /** As printed: the roll, `"<N> targets"`, the duration, or the authored sentence verbatim. */
10
10
  value: string;
11
11
  }
12
+ /** The spell's base roll (`damage_roll`), trimmed, or null when absent, empty or whitespace-only. The ONE base-roll
13
+ * check: every reader of `damage_roll` (the scaling readers here, the spell card) goes through it. */
14
+ export declare function spellBaseRoll(spell: Spell): string | null;
12
15
  /**
13
- * At-a-glance scaled effect for casting a LEVELLED `spell` with a slot of `slotLevel`,
14
- * read from structured `casting_options` (`type: "slot_level_<N>"`), WITH the field it
15
- * came from. Returns null when absent or untrustworthy. The FIRST present field wins, in
16
- * this order: `damage_roll`, `target_count`, `duration`, `desc` (so an option carrying a
17
- * roll AND a sentence yields the roll). A `target_count` that equals the slot level is
18
- * the known SRD-2014 bad encoding (e.g. Magic Missile 2nd->2 instead of 4) and is
19
- * suppressed. This errs toward showing nothing rather than a wrong number.
16
+ * At-a-glance effect for casting a LEVELLED `spell` with a slot of `slotLevel`, WITH the field
17
+ * it came from. Returns null when absent or untrustworthy.
18
+ *
19
+ * A structured `casting_options` entry for that slot (`type: "slot_level_<N>"`) wins: the FIRST
20
+ * present field, in this order: `damage_roll`, `target_count`, `duration`, `desc` (so an option
21
+ * carrying a roll AND a sentence yields the roll). A `target_count` that equals the slot level is
22
+ * the known SRD-2014 bad encoding (e.g. Magic Missile 2nd->2 instead of 4) and is suppressed.
23
+ *
24
+ * With no option for the slot, the spell's BASE roll (`damage_roll`) answers at the spell's OWN
25
+ * level only. Above it, whether the base roll is still the roll dealt is `spellBaseRollAtSlot`'s
26
+ * question (it is when the damage does not scale); a SCALING spell missing its option above base
27
+ * stays null here. A CANTRIP is never read by slot (null): its roll follows the character's level,
28
+ * `spellEffectAtCharacterLevel`, even when it is cast from a scroll. This errs toward showing
29
+ * nothing rather than a wrong number.
20
30
  */
21
31
  export declare function spellEffectPartsAtSlot(spell: Spell, slotLevel: number): SpellEffectParts | null;
32
+ /**
33
+ * The spell's BASE roll at a slot of `slotLevel` when the data PROVES its damage does not scale, so every slot at or
34
+ * above the spell's level deals the base roll. Two proofs, and only these:
35
+ * (a) it has `slot_level_<N>` options and every one carries only a `duration` and / or a `target_count` (plus the
36
+ * `concentration` flag a duration carries): 2024 Hex and Hunter's Mark scale their duration, Magic Missile and
37
+ * Scorching Ray their target count;
38
+ * (b) it has no slot options AND no `at_higher_levels` text (Finger of Death).
39
+ * Anything else is NOT proof: prose-only scaling (2014 Cure Wounds' "increases by 1d8 for each slot level above
40
+ * 1st", with no options) would print the unscaled base on every upcast row, so it stays null there. The companion of
41
+ * `spellEffectPartsAtSlot`: a row prints this roll beside a target count, and the duration a slot option carries
42
+ * prints in its own cell. Null for a cantrip, below the spell's level, and when the spell has no base roll.
43
+ */
44
+ export declare function spellBaseRollAtSlot(spell: Spell, slotLevel: number): string | null;
22
45
  /** The value of `spellEffectPartsAtSlot`, without its field. */
23
46
  export declare function spellEffectAtSlot(spell: Spell, slotLevel: number): string | null;
24
47
  /**
@@ -26,9 +49,10 @@ export declare function spellEffectAtSlot(spell: Spell, slotLevel: number): stri
26
49
  * `casting_options` (`type: "player_level_<N>"`). The roll of the HIGHEST `N <= characterLevel` wins: SRD 5e authors
27
50
  * one option per level from 5 to 20, SRD 2024 and the converter author only 5 / 11 / 17. An option with no roll or an
28
51
  * EMPTY one never qualifies (SRD 5e Acid Splash and Poison Spray open with `player_level_2..4` carrying
29
- * `damage_roll: ''`; Eldritch Blast 2024 authors `target_count` only). Null for a levelled spell, for a level that is
30
- * not a finite number (a fixture-built `derived` omits `totalLevel`), and when nothing qualifies: no corpus authors
31
- * `player_level_1`, so a cantrip's base roll below level 5 is not in the data and nothing is invented here.
52
+ * `damage_roll: ''`; Eldritch Blast 2024 authors `target_count` only). When no tier qualifies (below the first tier,
53
+ * or tiers that carry no roll) the spell's BASE roll `damage_roll` answers: the tier-1 roll (Fire Bolt `1d10` at 4,
54
+ * Eldritch Blast's per-beam `1d10` at any level). Null for a levelled spell, for a level that is not a finite number
55
+ * (a fixture-built `derived` omits `totalLevel`), and when neither a tier nor a non-empty base roll exists.
32
56
  */
33
57
  export declare function spellEffectAtCharacterLevel(spell: Spell, characterLevel: number): string | null;
34
58
  /** Owned slot levels strictly above the spell's base level (scaling spells only). */