@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
@@ -275,6 +275,20 @@ export declare const characterSchema: z.ZodObject<{
275
275
  }, z.core.$strip>>;
276
276
  }, z.core.$strict>>;
277
277
  granted_by: z.ZodOptional<z.ZodString>;
278
+ id: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
279
+ in: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
280
+ infusion: z.ZodOptional<z.ZodObject<{
281
+ kind: z.ZodEnum<{
282
+ infused: "infused";
283
+ created: "created";
284
+ }>;
285
+ by: z.ZodString;
286
+ seq: z.ZodNumber;
287
+ choice: z.ZodOptional<z.ZodString>;
288
+ charges: z.ZodOptional<z.ZodObject<{
289
+ current: z.ZodNumber;
290
+ }, z.core.$strip>>;
291
+ }, z.core.$strip>>;
278
292
  }, z.core.$strip>>>;
279
293
  overrides: z.ZodDefault<z.ZodObject<{
280
294
  scores: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
@@ -397,6 +411,33 @@ export declare const characterSchema: z.ZodObject<{
397
411
  vulnerabilities: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
398
412
  condition_immunities: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodString>>>;
399
413
  }, z.core.$strip>>;
414
+ sheet: z.ZodOptional<z.ZodObject<{
415
+ layout: z.ZodOptional<z.ZodObject<{
416
+ saves: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
417
+ section: "section";
418
+ }>>>;
419
+ }, z.core.$strip>>;
420
+ favorites: z.ZodOptional<z.ZodArray<z.ZodString>>;
421
+ filters: z.ZodOptional<z.ZodObject<{
422
+ actions: z.ZodOptional<z.ZodObject<{
423
+ show: z.ZodOptional<z.ZodArray<z.ZodString>>;
424
+ hide: z.ZodOptional<z.ZodArray<z.ZodString>>;
425
+ }, z.core.$strip>>;
426
+ passive: z.ZodOptional<z.ZodObject<{
427
+ show: z.ZodOptional<z.ZodArray<z.ZodString>>;
428
+ hide: z.ZodOptional<z.ZodArray<z.ZodString>>;
429
+ }, z.core.$strip>>;
430
+ }, z.core.$strip>>;
431
+ pools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
432
+ show: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
433
+ known: "known";
434
+ granted: "granted";
435
+ "not-known": "not-known";
436
+ }>>>;
437
+ off: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
438
+ folded: z.ZodOptional<z.ZodArray<z.ZodString>>;
439
+ }, z.core.$strip>>>;
440
+ }, z.core.$strip>>;
400
441
  state: z.ZodObject<{
401
442
  hp: z.ZodObject<{
402
443
  current: z.ZodNumber;
@@ -418,19 +459,19 @@ export declare const characterSchema: z.ZodObject<{
418
459
  }, z.core.$strip>>;
419
460
  concentration: z.ZodDefault<z.ZodNullable<z.ZodString>>;
420
461
  conditions: z.ZodDefault<z.ZodArray<z.ZodEnum<{
462
+ incapacitated: "incapacitated";
463
+ unconscious: "unconscious";
421
464
  poisoned: "poisoned";
422
465
  grappled: "grappled";
423
466
  paralyzed: "paralyzed";
424
467
  petrified: "petrified";
425
468
  prone: "prone";
426
469
  restrained: "restrained";
427
- unconscious: "unconscious";
428
470
  charmed: "charmed";
429
471
  frightened: "frightened";
430
472
  blinded: "blinded";
431
473
  deafened: "deafened";
432
474
  stunned: "stunned";
433
- incapacitated: "incapacitated";
434
475
  invisible: "invisible";
435
476
  }>>>;
436
477
  exhaustion: z.ZodDefault<z.ZodNumber>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  characterOverridesShape,
3
3
  characterSchema
4
- } from "../chunk-PZCE7DJM.js";
4
+ } from "../chunk-T6QIF5XR.js";
5
5
  import "../chunk-S7REMWW4.js";
6
6
  export {
7
7
  characterOverridesShape,
@@ -2,7 +2,7 @@ import type { EntityRegistry } from "@archivist-gg/core";
2
2
  import type { ItemEntity } from "@archivist-gg/dnd5e/item/item.types";
3
3
  import type { ArmorEntity } from "@archivist-gg/dnd5e/armor/armor.types";
4
4
  import type { WeaponEntity } from "@archivist-gg/dnd5e/weapon/weapon.types";
5
- import type { SlotKey } from "./pc.types.js";
5
+ import type { EquipmentEntry, SlotKey } from "./pc.types.js";
6
6
  export declare function isItemEntity(e: unknown): e is ItemEntity;
7
7
  export declare function isWeaponEntity(e: unknown): e is WeaponEntity;
8
8
  export declare function isArmorEntity(e: unknown): e is ArmorEntity;
@@ -13,10 +13,43 @@ export declare function resolveEntityForEntry(item: string, registry: EntityRegi
13
13
  entity: ArmorEntity | WeaponEntity | ItemEntity | null;
14
14
  entityType: string | null;
15
15
  };
16
- /** Is this armor a shield? Robust to SRD-2024 data where the Shield entity
17
- * carries `category: "heavy"` rather than `"shield"`. */
16
+ /** Is this armor a shield? By category, slug or name: the SRD Shield is category "shield" (dnd5e 0.3.13), but
17
+ * imported or hand-authored data (and the SRD bundle before 0.3.13) may carry category "heavy". */
18
18
  export declare function isShieldArmor(armor: ArmorEntity): boolean;
19
19
  /** The ArmorEntity whose `ac` block governs a slot: the entity itself when armor,
20
20
  * or — for a magic item whose `base_item` points at armor — the resolved base. */
21
21
  export declare function effectiveArmor(entity: ArmorEntity | WeaponEntity | ItemEntity | null | undefined, registry: EntityRegistry): ArmorEntity | null;
22
+ /** The WeaponEntity whose attack and two-handed rules govern a slot (H234 H2, spec §3.2): the entity itself when it is a
23
+ * weapon, or, for a magic item whose `base_item` resolves to a weapon, that base. ONE hop, exactly like
24
+ * {@link effectiveArmor}: a base that is itself an item is not followed (measured at Gate 0: 108 item-to-item bases, 0
25
+ * cycles, 0 ending at a two-handed weapon; a later multi-hop needs a visited set). Null for armor, a wondrous item, an
26
+ * unresolved slug, or a base that does not resolve to a weapon. */
27
+ export declare function effectiveWeapon(entity: ArmorEntity | WeaponEntity | ItemEntity | null | undefined, registry: EntityRegistry): WeaponEntity | null;
28
+ /** THE two-handed rule (H234 H2, spec §3.2), read by `computeAC`'s shield gate, the `wielding_two_handed` condition and
29
+ * the plugin's equip conflicts:
30
+ * 1-2. an entity whose OWN `properties` is a non-empty list: that list decides, whatever its base (resolved, unresolved or
31
+ * absent). The same precedence as the attack row, whose magic `propertiesOverride` replaces the base list, so the
32
+ * Weapons table's property chips and the two-handed rules cannot disagree;
33
+ * 3. an item with no own properties: its base weapon's, through {@link effectiveWeapon} (needs a registry);
34
+ * 4-6. anything else (no base, an unresolved or non-weapon base, no registry, null): not two-handed, as before.
35
+ * A property entry may be a conditional object; the test is the literal "two_handed". */
36
+ export declare function isTwoHandedWeapon(entity: ArmorEntity | WeaponEntity | ItemEntity | null | undefined, registry?: EntityRegistry | null): boolean;
37
+ /** An armour's own Armor Class term: its `base` plus its `flat` (raw vault data omits `flat`, so it reads 0). ONE rule
38
+ * for the armour and shield terms `computeAC` adds (pc.equipment.ts) and for the AC an entry shows
39
+ * (`effectiveItemArmorClass`, pc.entry-overrides.ts), both read through {@link slotAcTerms}. */
40
+ export declare function armorAcTerm(armor: ArmorEntity): number;
41
+ /** The Armor Class ONE worn armour or shield entry adds by itself, as the two terms a breakdown lists apart: its armour's
42
+ * own term ({@link armorAcTerm}; null when the entry resolves to no armour) and the entry's `overrides.ac_bonus` (0 when
43
+ * absent, or not a number in raw vault data). ONE rule for `computeAC`'s armour and shield slots (pc.equipment.ts) and
44
+ * the AC an entry shows (`effectiveItemArmorClass`, pc.entry-overrides.ts), which wrote "armour term + entry ac_bonus"
45
+ * three times, held equal only by a test (T17, carried from rider EF's review). The item's own `bonuses.ac` is not a
46
+ * slot term: the engine reads it attunement-gated and per condition, so it stays with each consumer. */
47
+ export declare function slotAcTerms(armor: ArmorEntity, entry: EquipmentEntry | undefined): {
48
+ armor: number;
49
+ override: number;
50
+ };
51
+ export declare function slotAcTerms(armor: ArmorEntity | null, entry: EquipmentEntry | undefined): {
52
+ armor: number | null;
53
+ override: number;
54
+ };
22
55
  export declare function defaultSlotForType(entityType: string | null, entity: ArmorEntity | WeaponEntity | ItemEntity | null, registry: EntityRegistry): SlotKey | null;
@@ -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;
@@ -234,6 +251,28 @@ export interface CharacterState {
234
251
  /** @deprecated SP5: removed; per-entry attuned flag is canonical. Tolerated until Task 4 parser migration strips it. */
235
252
  attuned_items?: string[];
236
253
  }
254
+ /** Per-character sheet state (phases AF and SL): layout and Actions/Passive view choices. Mirrors `sheetStateSchema`. */
255
+ export interface SheetViewFilter {
256
+ show?: string[];
257
+ hide?: string[];
258
+ }
259
+ /** PT (spec §7): one pool tab's view: what Show keeps, the facet values un-ticked (by facet id), the folded groups. */
260
+ export interface SheetPoolView {
261
+ show?: "known" | "granted" | "not-known";
262
+ off?: Record<string, string[]>;
263
+ folded?: string[];
264
+ }
265
+ export interface CharacterSheetState {
266
+ layout?: {
267
+ saves?: "section";
268
+ };
269
+ favorites?: string[];
270
+ filters?: {
271
+ actions?: SheetViewFilter;
272
+ passive?: SheetViewFilter;
273
+ };
274
+ pools?: Record<string, SheetPoolView>;
275
+ }
237
276
  export interface Character {
238
277
  name: string;
239
278
  edition: Edition;
@@ -292,6 +331,7 @@ export interface Character {
292
331
  vulnerabilities?: string[];
293
332
  condition_immunities?: string[];
294
333
  };
334
+ sheet?: CharacterSheetState;
295
335
  state: CharacterState;
296
336
  }
297
337
  /** R4-G7 T8 RIDER-23 (F-FEATSRC) · the slot that granted a feat: a class's `choices[<level>].feat` pick, or a 2024
@@ -304,6 +344,15 @@ export type FeatVia = {
304
344
  } | {
305
345
  kind: "background";
306
346
  slug: string;
347
+ }
348
+ /** D2b-A (design §2.2 step 6): a feat a POOL MEMBER grants (Lessons of the First Ones' Origin feat). `slug` is the
349
+ * member's note slug and `name` its display name; `classSlug` / `level` are the pool's class and anchor level. */
350
+ | {
351
+ kind: "pool";
352
+ slug: string;
353
+ name: string;
354
+ classSlug: string;
355
+ level: number;
307
356
  };
308
357
  export type FeatureSource = {
309
358
  kind: "class";
@@ -398,14 +447,28 @@ export interface ResolvedClass {
398
447
  subclass: SubclassEntity | null;
399
448
  choices: Record<number, LevelChoices>;
400
449
  }
450
+ /** One pool member as resolved for a character: a stored PICK (`selected`), a candidate (`available`) or a subclass
451
+ * 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
452
+ * repeatable note is keyed by its stored `<note slug>#<param>`, so two copies of one note are two entries with one `slug`;
453
+ * a plain pick's `key` is its resolved `slug` (the stored string, or the survivor of a stored twin), unless it was stored
454
+ * with a '#', which is kept; candidates and grants carry `key === slug` and `param: null`. */
401
455
  export interface ResolvedPoolEntry {
402
456
  slug: string;
403
457
  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`.
458
+ /** ART-a (spec §4.6): the pick key the writers compare (see above); the slug for candidates and grants. */
459
+ key: string;
460
+ /** 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
461
+ * repeatable note stored without `#` (a copy whose option is `needs-choice`). */
462
+ param: string | null;
463
+ /** ART-a (spec §4.1, §5.2): derived by `isItemBound`. Its subject is an item: no character tracker, no boon fold. */
464
+ itemBound: boolean;
465
+ /** ART-a (spec §5.8): present on every selected copy of a repeatable note. */
466
+ option?: import("./pc.infusions.js").CopyOption;
467
+ /** The compendium NAME the REGISTERED entity carries (R4-G5 §9.2.1), stamped at resolve time because `entity` is
468
+ * `e.data` (an H3-rebound member's is a copy of it), which carries none: MEASURED 2026-09-07 over the WHOLE
469
+ * converter output (226 documents under its `OptionalFeatures` folders) and the 7 bundle ones, 0 of 226 and 0 of 7
470
+ * declare a `compendium` key INSIDE the fenced entity body, while 226 of 226 and 7 of 7 declare one in the note's
471
+ * FRONTMATTER, which core keeps on `RegisteredEntity`.
409
472
  * The plugin's ONE visibility predicate reads it on BOTH surfaces (§3.2.2). Absent when the registry entry
410
473
  * carries none, which in practice means a test double. The COLLAPSE does not read it: its identity is the
411
474
  * slug PREFIX (§9.2.2). */
@@ -432,9 +495,16 @@ export interface ResolvedPool {
432
495
  * 2026-09-05 with `grep -rn "pool\.layout" packages/obsidian/src`, one line) and reads
433
496
  * authored-then-derived-then-default before handing the string to the `PoolTab` constructor. */
434
497
  layout?: PoolLayout;
435
- /** The OWNED resource id the members spend (majority of `consumes.resource` among the ids the
436
- * character owns); undefined when no member consumes an owned id (R4-G4 §4.2.3, Gate 0 B1). */
498
+ /** The OWNED resource id the members spend: the majority of the members' PAYERS (H3b `payingResourceId`: the named id
499
+ * when owned, else its owned declared equivalent, the pool's class first); undefined when no member has an owned payer
500
+ * (R4-G4 §4.2.3, Gate 0 B1; H3b spec §4). */
437
501
  resource?: string;
502
+ /** ART-a (spec §4.5): the declaration's `count.label`, copied raw; read through `poolCountLabel` (absent reads "Known"). */
503
+ countLabel?: string;
504
+ /** ART-a (spec §4.5): the declaration's `active`, copied raw; read through `poolActiveWords`. */
505
+ active?: PoolActive;
506
+ /** ART-a (spec §4.5): the declaration's `head_resource`. */
507
+ headResource?: string;
438
508
  }
439
509
  export interface ResolvedCharacter {
440
510
  definition: Character;
@@ -483,6 +553,10 @@ export interface ResolvedCharacter {
483
553
  * such pick. Populated by the resolver's collectChosenWeaponMasteries pass. */
484
554
  weaponMasteries: string[];
485
555
  state: CharacterState;
556
+ /** ART-a (spec §4.6, §5.4): the entry views, counters and flags `buildInfusionContext` derives after the resource
557
+ * index. Absent (no cost) for a character with no item-bound pool and no marker; every fold reads it through
558
+ * `resolveEntryEntity`. */
559
+ infusions?: import("./pc.infusions.js").InfusionContext;
486
560
  }
487
561
  export interface ProficiencySet {
488
562
  categories: string[];
@@ -526,20 +600,28 @@ export interface HPBreakdown {
526
600
  * is a human label for the expand/tooltip. `condition` is the source's own
527
601
  * qualifier ("for a 1st-level spell slot"), CARRIED verbatim and never evaluated,
528
602
  * 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`. */
603
+ * entry alike; absent when the source authors none. `scope` is a feature effect's
604
+ * structured weapon scope (its `applies_to` words, ART-c1 Task 9b): the merge in
605
+ * `pc.recalc.ts` keeps the rider only on the rows it reaches (`riderReachesRow`);
606
+ * absent = every row. How the sheet prints a rider (always inside the DAMAGE cell,
607
+ * controller ruling 8) is the plugin renderer's policy, stated once at
608
+ * `weapons-table.ts` `renderWeaponRow`. */
532
609
  export interface DamageRider {
533
610
  amount: string;
534
611
  damage_type?: string;
535
612
  source?: string;
536
613
  condition?: string;
614
+ scope?: WeaponScope[];
615
+ /** D2b-A: the source of the feature the rider comes from, so its amount resolves against the OWNING class's level
616
+ * and spellcasting modifier (a multiclass character's Guided Precision reads the Artificer's INT). Set by
617
+ * `computeFeatureEffects`; consumed and DROPPED by recalc's rider resolution (an attack row never carries it). */
618
+ owner?: FeatureSource;
537
619
  }
538
620
  export interface AttackRow {
539
621
  id: string;
540
622
  name: string;
541
623
  range?: string;
542
- /** Secondary thrown-mode range ("20/60 ft") for a throwable melee weapon.
624
+ /** Secondary thrown-mode range ("20/60 ft.") for a throwable melee weapon.
543
625
  * Display-only; rendered as a stacked muted second line in the Range cell.
544
626
  * Absent otherwise. */
545
627
  thrownRange?: string;
@@ -550,6 +632,10 @@ export interface AttackRow {
550
632
  * the migrated manual override), rendered as extra damage chips. Absent when
551
633
  * none apply (so untouched rows are unchanged). */
552
634
  damageRiders?: DamageRider[];
635
+ /** The weapon's CATEGORY as the attack modes read it (`classifyWeaponRange`): `melee` for a weapon with a melee
636
+ * mode (a thrown melee weapon stays melee), `ranged` for a pure ranged one. A rider's `melee` / `ranged` scope
637
+ * reads it (ART-c1 Task 9b). Absent on the unarmed row. */
638
+ weaponCategory?: "melee" | "ranged";
553
639
  properties: string[];
554
640
  proficient: boolean;
555
641
  breakdown: {
@@ -557,8 +643,9 @@ export interface AttackRow {
557
643
  damage: ACTerm[];
558
644
  };
559
645
  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. */
646
+ /** Hand slot the attack came from. Absent on an equipped weapon that holds no hand slot (H234 H5: both hands full, an
647
+ * explicit-slot conflict loser, a non-hand slot) and on the unarmed row. The Actions tab finds the originating
648
+ * equipment entry by the index in the row's `id` (`<index>:standard`), never by this field. */
562
649
  slotKey?: "mainhand" | "offhand";
563
650
  /** Short caption under the weapon name in the Actions tab table.
564
651
  * e.g. "martial · versatile". Display-only. */
@@ -610,6 +697,12 @@ export interface AppliedBonuses {
610
697
  ability_bonuses: Partial<Record<Ability, number>>;
611
698
  ability_statics: Partial<Record<Ability, number>>;
612
699
  save_bonus: number;
700
+ /** SL (spec §11.3): `save_bonus` term by term, one per item, each named by the entry's display name (`overrides.name`, else
701
+ * the item's). The saves breakdown lists these, never a lumped "Equipment" term. */
702
+ save_terms: {
703
+ source: string;
704
+ amount: number;
705
+ }[];
613
706
  speed_bonuses: {
614
707
  walk: number;
615
708
  fly: number | "walk" | null;
@@ -743,6 +836,14 @@ export interface DerivedStats {
743
836
  bonus: number;
744
837
  proficiency: "none" | "proficient" | "expertise";
745
838
  ability: Ability;
839
+ /** The winning half-proficiency term (Jack of All Trades, Remarkable Athlete) on a skill whose tri is `none`;
840
+ * absent otherwise. Additive: the tri never gains a half value, it is also the `overrides.skills.*.proficiency`
841
+ * enum. Set under an `overrides.skills.<s>.bonus` too (the marker states the rule, the bonus is the number).
842
+ * `source` is the owning feature's name. */
843
+ halfProficiency?: {
844
+ source: string;
845
+ amount: number;
846
+ };
746
847
  }>;
747
848
  /** Numeric terms behind the sheet's skill, save, speed and initiative hovers. */
748
849
  statBreakdowns?: {
@@ -0,0 +1,15 @@
1
+ import type { WeaponEntity } from "@archivist-gg/dnd5e/weapon/weapon.types";
2
+ export interface QualifiedWeaponGrant {
3
+ category: "simple" | "martial";
4
+ /** Absent: melee and ranged alike. */
5
+ range?: "melee" | "ranged";
6
+ /** Weapon property keys as the weapon notes carry them (`two_handed`, `finesse`). */
7
+ properties: string[];
8
+ /** true: the weapon has NONE of `properties` ("that don't have"); false: it has ANY of them ("that have"). */
9
+ without: boolean;
10
+ }
11
+ /** The grant a phrase states, or null when it is not a property-qualified category phrase (a weapon name, "simple"). */
12
+ export declare function parseQualifiedWeaponGrant(text: string): QualifiedWeaponGrant | null;
13
+ /** Does the qualified grant `text` cover `weapon`? False for any text that is not such a grant. Melee / ranged is the attack
14
+ * mode the classifier reconstructs, not the category suffix (a thrown melee weapon may be filed `*-ranged`). */
15
+ export declare function qualifiedGrantCovers(text: string, weapon: Pick<WeaponEntity, "category" | "properties" | "range" | "slug">): boolean;
@@ -17,6 +17,14 @@ 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
+ export type PoolHead = "dice" | "points";
21
+ export interface PoolPresentation {
22
+ head: PoolHead;
23
+ }
24
+ /** A pool tab's ONE data axis (PT spec §9; ART-D's rows axis is retired: every pool tab draws the table).
25
+ * HEAD: an authored `dice-pool` / `point-pool` wins; otherwise the DERIVED layout decides (points for `point-pool`,
26
+ * dice for anything else). An authored `blocks` or `spell-like` still parses and is ignored. */
27
+ export declare function poolPresentation(authored?: PoolLayout, derived?: PoolLayout): PoolPresentation;
20
28
  /** The ONE `rendering_hint` to `EntryAffordance` table (R4-G5 §4.2.1, invariant 3): the PER-ENTRY sibling of
21
29
  * `RENDERING_HINT_LAYOUT`. `granted-die-to-ally` is its only key, and the four documents carrying it
22
30
  * (Commander's Strike x2, Rally x2) are field-identical to the other 39 maneuvers except that hint, so a
@@ -4,13 +4,15 @@ import {
4
4
  RENDERING_HINT_LAYOUT,
5
5
  deriveEntryAffordance,
6
6
  derivePoolLayout,
7
- formatAffordanceCaption
8
- } from "../chunk-PP2UHLBA.js";
7
+ formatAffordanceCaption,
8
+ poolPresentation
9
+ } from "../chunk-B3DP42OM.js";
9
10
  export {
10
11
  AFFORDANCE_CAPTIONS,
11
12
  RENDERING_HINT_AFFORDANCE,
12
13
  RENDERING_HINT_LAYOUT,
13
14
  deriveEntryAffordance,
14
15
  derivePoolLayout,
15
- formatAffordanceCaption
16
+ formatAffordanceCaption,
17
+ poolPresentation
16
18
  };
@@ -0,0 +1,44 @@
1
+ import type { ResourceIndex } from "./pc.resources.js";
2
+ import type { FeatureSource, ResolvedClass, ResolvedFeature } from "./pc.types.js";
3
+ /**
4
+ * H3b (spec `2026-09-28-h3b-resource-equivalents-design.md` §2): DECLARED equivalent resource ids. Each group says "these
5
+ * ids name ONE resource": the books and the SRD data mint different ids for the same pool (edition twins such as
6
+ * `fighter:superiority-dice` / `fighter-2024:superiority-dice`, book drift such as `monk:ki` / `monk:focus-point`,
7
+ * singular / plural such as `sorcerer:sorcery-point(s)`). Nothing is ever derived from an id's shape: an id in no group
8
+ * has no equivalent. The order inside a group is the fallback preference ({@link payingResourceId} step 4).
9
+ *
10
+ * The groups were measured over the installed vault (every class paired with every subclass of the same class, census in
11
+ * `.superpowers/sdd/h3b-evidence/`) and each checked against its declaring notes. The bare `channel-divinity` is the SRD
12
+ * 2024 id of BOTH the Cleric and the Paladin, so it sits in both Channel Divinity groups. Equivalence is read as "shares a
13
+ * group with", never transitively: `cleric:` / `cleric-2024:` never answer for `paladin:` / `paladin-2024:`. The bare id
14
+ * does answer for both, so a paladin consumer whose own class owns no Channel Divinity pays from a bare id another class
15
+ * (an SRD 2024 Cleric) declares: the one Channel Divinity pool of the 2014 multiclass rule (review m1, H3b).
16
+ */
17
+ export interface ResourceEquivalentGroup {
18
+ readonly name: string;
19
+ readonly ids: readonly string[];
20
+ }
21
+ export declare const RESOURCE_EQUIVALENTS: readonly ResourceEquivalentGroup[];
22
+ /** Every id that shares a group with `id`, in declared order (group order, then the order inside the group), `id` itself
23
+ * excluded, each once. Empty for an id in no group. */
24
+ export declare function equivalentResourceIds(id: string, groups?: readonly ResourceEquivalentGroup[]): string[];
25
+ /**
26
+ * THE rule (spec §3): which OWNED resource pays for a consumption naming `id`.
27
+ * 1. the candidates are `id`, then its declared equivalents in declared order, kept only when the character owns them;
28
+ * 2. none: `undefined` (the caller keeps the raw id: no control, never a spend from nothing);
29
+ * 3. the first candidate the consumer's OWN class entry declares (`owner`, its class or subclass) pays, so a class's
30
+ * feature or pool member spends its class's pool even when a feat owns a twin id (TCE Metamagic Adept on a 2014
31
+ * Sorcerer declares `sorcerer-2024:sorcery-point`);
32
+ * 4. else the first candidate: the named id itself when it is owned.
33
+ * Exactly one id per consumer, so a spend writes one `feature_uses` key.
34
+ */
35
+ export declare function payingResourceId(id: string, index: ResourceIndex, owner?: ResolvedClass | null, groups?: readonly ResourceEquivalentGroup[]): string | undefined;
36
+ /** The class entry a feature belongs to: a class feature's class, a subclass feature's class; none for a race,
37
+ * background, feat or campaign feature. */
38
+ export declare function classOfSource(source: FeatureSource, classes: readonly ResolvedClass[]): ResolvedClass | null;
39
+ /**
40
+ * Spec §4: every resolved feature whose `consumes.resource` has a different payer becomes a COPY (wrapper, feature and
41
+ * consumes; only `resource` changes). The registry `Feature` is shared by every open sheet and is never written; a
42
+ * feature with no `consumes.resource`, one paid by the id it names, or one with no owned candidate keeps its identity.
43
+ */
44
+ export declare function bindFeatureConsumers(features: ResolvedFeature[], index: ResourceIndex, classes: readonly ResolvedClass[]): ResolvedFeature[];
@@ -1,12 +1,7 @@
1
- // src/pc/spell-source.ts
2
- var SPELL_SOURCE = {
3
- class: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false },
4
- feat: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
5
- item: { ownAbility: false, section: "consumable", freeCastWhenNoSlot: false, showInPrepare: false, countsAsGranted: true },
6
- race: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
7
- domain: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false }
8
- };
9
- var spellSource = (s) => SPELL_SOURCE[s.source];
1
+ import {
2
+ SPELL_SOURCE,
3
+ spellSource
4
+ } from "../chunk-KR6JF3BF.js";
10
5
  export {
11
6
  SPELL_SOURCE,
12
7
  spellSource
@@ -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-AZRGFUSR.js";
4
+ import "../chunk-Y5VVP73C.js";
5
+ import "../chunk-FANQVQ3D.js";
6
6
  import "../chunk-4U55VNC7.js";
7
- import "../chunk-PI4LLJG4.js";
7
+ import "../chunk-YD2VAHA6.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-5MXFW4O3.js";
11
+ import "../chunk-2JSQE3DD.js";
12
12
  import "../chunk-UA5KS2PL.js";
13
13
  export {
14
14
  raceCodec