@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
@@ -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.
@@ -1,28 +1,18 @@
1
- import {
2
- computeConditionEffects
3
- } from "../chunk-R2ZV233X.js";
4
1
  import {
5
2
  collectChosenAbilityPoints,
6
3
  collectChosenProficiencies
7
- } from "../chunk-HLQAFZKQ.js";
4
+ } from "../chunk-QEO7LYTG.js";
5
+ import "../chunk-2LULMQTF.js";
6
+ import "../chunk-H5PTKYXL.js";
8
7
  import {
9
8
  resourceLevelFor
10
- } from "../chunk-4ISR76DH.js";
9
+ } from "../chunk-KSTV7J2U.js";
11
10
  import {
12
11
  computeSpellLimits,
13
12
  deriveSpellSlots,
14
13
  effectiveSpellcastingAbility,
15
14
  resolveSpellcasting
16
15
  } from "../chunk-DPUJDOKV.js";
17
- import "../chunk-O4SRD3J5.js";
18
- import "../chunk-PP2UHLBA.js";
19
- import {
20
- diceColumnAt,
21
- unarmedDieColumnFor
22
- } from "../chunk-IUAAXXNO.js";
23
- import "../chunk-YHYTW5QA.js";
24
- import "../chunk-MI7P3NX3.js";
25
- import "../chunk-PVCEA4HZ.js";
26
16
  import {
27
17
  toDefenseSlug
28
18
  } from "../chunk-XJ2F2WO6.js";
@@ -31,31 +21,51 @@ import {
31
21
  computeAppliedBonuses,
32
22
  computeSlotsAndAttacks,
33
23
  emptyAppliedBonuses
34
- } from "../chunk-V373TRJE.js";
35
- import "../chunk-UIRMA5KM.js";
36
- import "../chunk-UBBKSYBY.js";
24
+ } from "../chunk-Q5XTEYHD.js";
25
+ import "../chunk-YDGMBMYI.js";
37
26
  import {
38
27
  assembleEffectFeatures,
39
28
  computeFeatureEffects,
40
29
  foldsNow,
41
30
  selfEffectsOf
42
- } from "../chunk-CBEKVAX4.js";
31
+ } from "../chunk-4BZ47YJ4.js";
43
32
  import "../chunk-TOM66P2P.js";
44
33
  import "../chunk-KU3YLF6D.js";
45
34
  import "../chunk-RLGQ5PZZ.js";
46
- import "../chunk-LWFTHJIE.js";
47
- import "../chunk-DNAJRMNN.js";
35
+ import "../chunk-T5GZBKIQ.js";
36
+ import "../chunk-W6GC6OKK.js";
37
+ import "../chunk-HJQNK3J5.js";
38
+ import {
39
+ diceColumnAt,
40
+ unarmedDieColumnFor
41
+ } from "../chunk-IUAAXXNO.js";
42
+ import "../chunk-YHYTW5QA.js";
43
+ import "../chunk-DPM6V7YX.js";
44
+ import "../chunk-PVCEA4HZ.js";
45
+ import {
46
+ legacyAsiBranch
47
+ } from "../chunk-LBEXLN6I.js";
48
+ import {
49
+ computeConditionEffects
50
+ } from "../chunk-MYY2C5MB.js";
51
+ import "../chunk-EJP263OP.js";
52
+ import "../chunk-ZUQW5VBZ.js";
53
+ import "../chunk-IHE6KVC3.js";
54
+ import "../chunk-HHBD4SQ6.js";
55
+ import "../chunk-A54HHCWW.js";
56
+ import "../chunk-LHZXYFBU.js";
48
57
  import "../chunk-LVQLWRCU.js";
49
- import "../chunk-WXWPK3LI.js";
50
- import "../chunk-6X4KUDMU.js";
58
+ import "../chunk-CM5CWO4K.js";
59
+ import "../chunk-ZCTUYGNV.js";
51
60
  import "../chunk-YBLDE5CG.js";
52
61
  import {
53
62
  evaluateMaxFormula,
54
63
  isValidMaxFormula
55
64
  } from "../chunk-EVMUJYUD.js";
56
65
  import "../chunk-VTTA2ALZ.js";
57
- import "../chunk-OZP6JFGT.js";
58
- import "../chunk-VQAXTIBW.js";
66
+ import "../chunk-XY6X2APM.js";
67
+ import "../chunk-ZDAEGJH4.js";
68
+ import "../chunk-3TM34RSJ.js";
59
69
  import {
60
70
  abilityModifier,
61
71
  attackBonus,
@@ -124,13 +134,11 @@ function collectClassAsiBranch(resolved) {
124
134
  var _a;
125
135
  const out = {};
126
136
  for (const c of resolved.classes) {
127
- for (const [, choice] of Object.entries(c.choices)) {
128
- const block = choice;
129
- if (typeof (block == null ? void 0 : block.feat) === "string") continue;
130
- const asi = block == null ? void 0 : block.asi;
131
- if (!asi) continue;
137
+ for (const choice of Object.values(c.choices)) {
138
+ const alloc = legacyAsiBranch(choice);
139
+ if (!alloc) continue;
132
140
  for (const ab of ABILITY_KEYS) {
133
- const v = asi[ab];
141
+ const v = alloc[ab];
134
142
  if (typeof v === "number") out[ab] = ((_a = out[ab]) != null ? _a : 0) + v;
135
143
  }
136
144
  }
@@ -205,6 +213,24 @@ function resolveDamageRider(rider, rowDamageType, bindings) {
205
213
  }
206
214
  return out;
207
215
  }
216
+ function riderReachesRow(rider, row) {
217
+ var _a;
218
+ if (!((_a = rider.scope) == null ? void 0 : _a.length)) return true;
219
+ return rider.scope.some((word) => {
220
+ switch (word) {
221
+ case "weapon":
222
+ return true;
223
+ case "unarmed":
224
+ return row.unarmed === true;
225
+ case "melee":
226
+ case "ranged":
227
+ return row.weaponCategory === word;
228
+ case "finesse":
229
+ case "thrown":
230
+ return row.properties.includes(word);
231
+ }
232
+ });
233
+ }
208
234
  function unarmoredAC(resolved, mods, warnings) {
209
235
  return unarmoredACBreakdown(resolved, mods, warnings).total;
210
236
  }
@@ -634,7 +660,8 @@ function recalc(resolved, registry) {
634
660
  skills[skillKey] = {
635
661
  bonus,
636
662
  proficiency: tri,
637
- ability: ab
663
+ ability: ab,
664
+ ...halfProfBest ? { halfProficiency: { source: halfProfBest.source, amount: halfProfBest.amount } } : {}
638
665
  };
639
666
  }
640
667
  const passives = {
@@ -862,7 +889,7 @@ function recalc(resolved, registry) {
862
889
  // attackNotes: reroll-damage / attack-rule captions, only when non-empty.
863
890
  attacks: attackRows.map((a) => {
864
891
  var _a2;
865
- const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses].map((r) => resolveDamageRider(r, a.damageType, riderBindings));
892
+ const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses.filter((r) => riderReachesRow(r, a))].map((r) => resolveDamageRider(r, a.damageType, riderBindings));
866
893
  return {
867
894
  ...a,
868
895
  toHit: a.toHit + conditionEffects.d20_test_penalty,
@@ -895,6 +922,7 @@ export {
895
922
  phbAverageForDie,
896
923
  recalc,
897
924
  resolveUnarmedStrike,
925
+ riderReachesRow,
898
926
  speedFromRace,
899
927
  unarmoredAC,
900
928
  unarmoredACBreakdown
@@ -10,28 +10,35 @@ import {
10
10
  dedupeResolvedSpells,
11
11
  resolveOriginFeat,
12
12
  stripSlug
13
- } from "../chunk-HLQAFZKQ.js";
14
- import "../chunk-4ISR76DH.js";
13
+ } from "../chunk-QEO7LYTG.js";
14
+ import "../chunk-2LULMQTF.js";
15
+ import "../chunk-H5PTKYXL.js";
16
+ import "../chunk-KSTV7J2U.js";
15
17
  import "../chunk-DPUJDOKV.js";
16
- import "../chunk-O4SRD3J5.js";
17
- import "../chunk-PP2UHLBA.js";
18
- import "../chunk-IUAAXXNO.js";
19
- import "../chunk-YHYTW5QA.js";
20
- import "../chunk-MI7P3NX3.js";
21
- import "../chunk-PVCEA4HZ.js";
22
- import "../chunk-UBBKSYBY.js";
23
- import "../chunk-CBEKVAX4.js";
18
+ import "../chunk-4BZ47YJ4.js";
24
19
  import "../chunk-TOM66P2P.js";
25
20
  import "../chunk-KU3YLF6D.js";
26
21
  import "../chunk-RLGQ5PZZ.js";
22
+ import "../chunk-T5GZBKIQ.js";
23
+ import "../chunk-W6GC6OKK.js";
24
+ import "../chunk-HJQNK3J5.js";
25
+ import "../chunk-IUAAXXNO.js";
26
+ import "../chunk-YHYTW5QA.js";
27
+ import "../chunk-DPM6V7YX.js";
28
+ import "../chunk-PVCEA4HZ.js";
29
+ import "../chunk-LBEXLN6I.js";
30
+ import "../chunk-ZUQW5VBZ.js";
31
+ import "../chunk-IHE6KVC3.js";
32
+ import "../chunk-LHZXYFBU.js";
27
33
  import "../chunk-LVQLWRCU.js";
28
- import "../chunk-WXWPK3LI.js";
29
- import "../chunk-6X4KUDMU.js";
34
+ import "../chunk-CM5CWO4K.js";
35
+ import "../chunk-ZCTUYGNV.js";
30
36
  import "../chunk-YBLDE5CG.js";
31
37
  import "../chunk-EVMUJYUD.js";
32
38
  import "../chunk-VTTA2ALZ.js";
33
- import "../chunk-OZP6JFGT.js";
34
- import "../chunk-VQAXTIBW.js";
39
+ import "../chunk-XY6X2APM.js";
40
+ import "../chunk-ZDAEGJH4.js";
41
+ import "../chunk-3TM34RSJ.js";
35
42
  import "../chunk-PDJSUH24.js";
36
43
  import "../chunk-WELIKLZF.js";
37
44
  import "../chunk-4U55VNC7.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resourceLevelFor
3
- } from "../chunk-4ISR76DH.js";
3
+ } from "../chunk-KSTV7J2U.js";
4
4
  import "../chunk-DPUJDOKV.js";
5
5
  import {
6
6
  numericColumnsAt
@@ -1,4 +1,4 @@
1
- import type { FeatureSource, ResolvedCharacter, ResolvedFeature, ResolvedPool, DerivedStats } from "./pc.types.js";
1
+ import type { FeatureSource, ResolvedCharacter, ResolvedFeature, ResolvedPool, ResolvedPoolEntry, DerivedStats } from "./pc.types.js";
2
2
  import type { ResourceRecovery, ResourceDie, ResourceScaleStep, ResetTrigger } from "../types/resource.js";
3
3
  /** The level a resource granted via `source` scales against (R4-G4 §6.2.4, ONE derivation): the
4
4
  * character's level in the granting class; for a `subclass` source the level in the class that OWNS
@@ -80,6 +80,11 @@ export declare function resolveRecovery(entry: ResourceRecovery): ResolvedRecove
80
80
  * max-of-maxes merge). Reads the features array ONLY. `name` falls back to the owning feature's name,
81
81
  * the rule `findResourceById` carried, for resources synthesised from older fixtures that omit it. */
82
82
  export declare function resolveFeatureResources(features: ReadonlyArray<ResolvedFeature>): ResourceIndex;
83
+ /** The resource id a pool pick's own tracker uses (spec §5.2): a repeatable copy keys by its pick key, every other pick by its slug.
84
+ * A repeatable (non-item-bound) copy keys its tracker by its KEY, so two copies are two trackers; `param != null` keeps a cast
85
+ * fixture without the field on the slug. ONE rule for both sides: dnd5e seeds by it and the plugin's pick tracker reads by it
86
+ * (ART-c1, R-3 c). */
87
+ export declare function pickResourceId(entry: Pick<ResolvedPoolEntry, "slug" | "key" | "param">): string;
83
88
  /** The full index: the feature resources (`resolveFeatureResources`) plus the pool picks' own
84
89
  * `uses` (R4-G4 §12, LANDED at T7b). A pure function of `resolved.features` and `resolved.pools`,
85
90
  * each guarded `?? []` because the cast fixtures behind the rest suites in both repos carry
@@ -1,10 +1,11 @@
1
1
  import {
2
+ pickResourceId,
2
3
  poolSaveDC,
3
4
  resolveFeatureResources,
4
5
  resolveRecovery,
5
6
  resolveResourceIndex,
6
7
  resourceLevelFor
7
- } from "../chunk-4ISR76DH.js";
8
+ } from "../chunk-KSTV7J2U.js";
8
9
  import "../chunk-DPUJDOKV.js";
9
10
  import "../chunk-IUAAXXNO.js";
10
11
  import "../chunk-LVQLWRCU.js";
@@ -13,6 +14,7 @@ import "../chunk-VTTA2ALZ.js";
13
14
  import "../chunk-PDJSUH24.js";
14
15
  import "../chunk-WELIKLZF.js";
15
16
  export {
17
+ pickResourceId,
16
18
  poolSaveDC,
17
19
  resolveFeatureResources,
18
20
  resolveRecovery,
@@ -1,5 +1,6 @@
1
1
  import type { EntityRegistry } from "@archivist-gg/core";
2
- import type { Character, DerivedStats, ResolvedCharacter } from "./pc.types.js";
2
+ import type { ResetTrigger } from "../types/resource.js";
3
+ import type { Character, DerivedStats, EquipmentEntryState, ResolvedCharacter } from "./pc.types.js";
3
4
  export type RestType = "short" | "long";
4
5
  export type RestCategoryId = "hp-to-max" | "hd-regain" | "spell-slots" | "pact-slots" | "exhaustion" | "hp-modifier-reset" | `feature:${string}` | `item:${number}`
5
6
  /** R4-G5 §4.4.2: END an active buff whose carrier declares a structured `duration`. The tail is the STORED
@@ -15,6 +16,14 @@ export interface RestCategory {
15
16
  /** R4-G4 §7.2.2: a PARTIAL restore from a `recovery[]` entry of kind `uses` and flavour `rest` (N uses, or "all"),
16
17
  * emitted only when the resource's own `reset` does not already fire at this rest. Absent = the own reset (to 0). */
17
18
  restore?: number | "all";
19
+ /** ART-c1 Task 9c (S-4, controller ruling 10): an `item:` category's recharge, the amount its rule restores ("1d6+1",
20
+ * "3", "all") and the charges before the rest. The sheet's rest dialog rolls a DICE amount once when it opens and the
21
+ * rest applies `min(max, current + n)`; this plan stays pure and rolls nothing. */
22
+ recharge?: {
23
+ amount: string;
24
+ current: number;
25
+ max: number;
26
+ };
18
27
  }
19
28
  export interface RestPlan {
20
29
  type: RestType;
@@ -29,4 +38,15 @@ export interface RestPlan {
29
38
  targetUsed: number;
30
39
  }>;
31
40
  }
41
+ /** The persisted item-charge recovery vocabulary (`pc.schema.ts` `equipmentEntryStateSchema.recovery.reset`). */
42
+ export type ItemRecoveryReset = NonNullable<EquipmentEntryState["recovery"]>["reset"];
43
+ /** Every reset a counter can carry: a feature resource's `ResetTrigger` or an item's recovery reset. The two
44
+ * vocabularies share only `dawn`, which means the same thing in both. */
45
+ export type AnyReset = ResetTrigger | ItemRecoveryReset;
46
+ /** The earliest rest that restores `reset` in full, or `null` when none does. A value outside both vocabularies (raw
47
+ * note data reaches here unvalidated) is restored by no rest: an OWN-property lookup, so a prototype key such as
48
+ * `constructor` is not a reset either. */
49
+ export declare function earliestRestoringRest(reset: AnyReset): RestType | null;
50
+ /** Whether a rest of `type` restores `reset` in full: the earliest rest that restores it is no longer than `type`. */
51
+ export declare function restRestores(type: RestType, reset: AnyReset): boolean;
32
52
  export declare function computeRestPlan(character: Character, resolved: ResolvedCharacter, derived: DerivedStats, registry: EntityRegistry | null, type: RestType): RestPlan;
@@ -1,11 +1,23 @@
1
1
  import {
2
2
  resolveResourceIndex
3
- } from "../chunk-4ISR76DH.js";
3
+ } from "../chunk-KSTV7J2U.js";
4
4
  import "../chunk-DPUJDOKV.js";
5
+ import {
6
+ effectiveItemCharges,
7
+ effectiveItemRecovery
8
+ } from "../chunk-T5GZBKIQ.js";
9
+ import "../chunk-W6GC6OKK.js";
10
+ import "../chunk-HJQNK3J5.js";
5
11
  import "../chunk-IUAAXXNO.js";
12
+ import "../chunk-ZUQW5VBZ.js";
13
+ import "../chunk-IHE6KVC3.js";
14
+ import "../chunk-LHZXYFBU.js";
6
15
  import "../chunk-LVQLWRCU.js";
16
+ import "../chunk-CM5CWO4K.js";
17
+ import "../chunk-ZCTUYGNV.js";
7
18
  import "../chunk-EVMUJYUD.js";
8
19
  import "../chunk-VTTA2ALZ.js";
20
+ import "../chunk-3TM34RSJ.js";
9
21
  import "../chunk-PDJSUH24.js";
10
22
  import "../chunk-WELIKLZF.js";
11
23
 
@@ -17,18 +29,35 @@ function resolveItemName(entry, registry) {
17
29
  const slug = ref ? ref[1] : entry.item;
18
30
  return (_a = registry.getBySlug(slug)) == null ? void 0 : _a.name;
19
31
  }
20
- var FIRES_AT = {
21
- long: /* @__PURE__ */ new Set(["short-rest", "long-rest", "either", "dawn", "dusk"]),
22
- short: /* @__PURE__ */ new Set(["short-rest", "either"])
32
+ var RESTORED_BY = {
33
+ "short-rest": "short",
34
+ either: "short",
35
+ short: "short",
36
+ "long-rest": "long",
37
+ long: "long",
38
+ dawn: "long",
39
+ dusk: "long",
40
+ turn: null,
41
+ round: null,
42
+ custom: null,
43
+ special: null
23
44
  };
45
+ var REST_SPAN = { short: 1, long: 2 };
46
+ function earliestRestoringRest(reset) {
47
+ return Object.prototype.hasOwnProperty.call(RESTORED_BY, reset) ? RESTORED_BY[reset] : null;
48
+ }
49
+ function restRestores(type, reset) {
50
+ const earliest = earliestRestoringRest(reset);
51
+ return earliest !== null && REST_SPAN[earliest] <= REST_SPAN[type];
52
+ }
24
53
  function pushPartialRecoveries(cats, character, index, type) {
25
54
  var _a, _b;
26
55
  for (const [key, fu] of Object.entries((_a = character.state.feature_uses) != null ? _a : {})) {
27
56
  if (fu.used <= 0) continue;
28
57
  const res = index.get(key);
29
58
  if (!((_b = res == null ? void 0 : res.recovery) == null ? void 0 : _b.length)) continue;
30
- if (FIRES_AT[type].has(res.reset)) continue;
31
- const entry = res.recovery.find((r) => r.kind === "uses" && r.flavour === "rest" && FIRES_AT[type].has(r.entry.reset));
59
+ if (restRestores(type, res.reset)) continue;
60
+ const entry = res.recovery.find((r) => r.kind === "uses" && r.flavour === "rest" && restRestores(type, r.entry.reset));
32
61
  if (!entry) continue;
33
62
  const amount = entry.entry.amount;
34
63
  const restore = amount === "all" ? "all" : typeof amount === "number" ? amount : Number(amount);
@@ -132,8 +161,7 @@ function computeRestPlan(character, resolved, derived, registry, type) {
132
161
  const bankedRolls = banked ? banked.filter((v) => v > 0).length : 0;
133
162
  if (fu.used <= 0 && bankedRolls <= 0) continue;
134
163
  const res = index.get(key);
135
- const reset = (_h = res == null ? void 0 : res.reset) != null ? _h : "long-rest";
136
- if (reset !== "short-rest" && reset !== "long-rest" && reset !== "either" && reset !== "dawn" && reset !== "dusk") continue;
164
+ if (!restRestores("long", (_h = res == null ? void 0 : res.reset) != null ? _h : "long-rest")) continue;
137
165
  const rollsNote = bankedRolls > 0 ? ` \xB7 ${bankedRolls} roll${bankedRolls === 1 ? "" : "s"} cleared` : "";
138
166
  cats.push({
139
167
  id: `feature:${key}`,
@@ -144,16 +172,18 @@ function computeRestPlan(character, resolved, derived, registry, type) {
144
172
  pushPartialRecoveries(cats, character, index, "long");
145
173
  character.equipment.forEach((entry, idx) => {
146
174
  var _a2, _b2, _c2, _d2, _e2;
147
- const rec = (_a2 = entry.state) == null ? void 0 : _a2.recovery;
148
- const charges = (_b2 = entry.state) == null ? void 0 : _b2.charges;
175
+ const view = (_b2 = (_a2 = resolved.infusions) == null ? void 0 : _a2.views.get(idx)) != null ? _b2 : null;
176
+ const rec = effectiveItemRecovery(entry, registry, view);
177
+ const charges = effectiveItemCharges(entry, registry, view);
149
178
  if (!rec || !charges) return;
150
179
  if (charges.current >= charges.max) return;
151
- if (rec.reset !== "short" && rec.reset !== "long" && rec.reset !== "dawn") return;
180
+ if (!restRestores("long", rec.reset)) return;
152
181
  const label = (_e2 = (_d2 = (_c2 = entry.overrides) == null ? void 0 : _c2.name) != null ? _d2 : resolveItemName(entry, registry)) != null ? _e2 : entry.item;
153
182
  cats.push({
154
183
  id: `item:${idx}`,
155
184
  label,
156
- preview: `${charges.current} \u2192 ${charges.max}`
185
+ preview: `${charges.current} \u2192 ${charges.max}`,
186
+ recharge: { amount: rec.amount, current: charges.current, max: charges.max }
157
187
  });
158
188
  });
159
189
  }
@@ -163,8 +193,7 @@ function computeRestPlan(character, resolved, derived, registry, type) {
163
193
  const bankedRolls = banked ? banked.filter((v) => v > 0).length : 0;
164
194
  if (fu.used <= 0 && bankedRolls <= 0) continue;
165
195
  const res = index.get(key);
166
- const r = (_l = res == null ? void 0 : res.reset) != null ? _l : "long-rest";
167
- if (r !== "short-rest" && r !== "either") continue;
196
+ if (!restRestores("short", (_l = res == null ? void 0 : res.reset) != null ? _l : "long-rest")) continue;
168
197
  const rollsNote = bankedRolls > 0 ? ` \xB7 ${bankedRolls} roll${bankedRolls === 1 ? "" : "s"} cleared` : "";
169
198
  cats.push({
170
199
  id: `feature:${key}`,
@@ -175,16 +204,18 @@ function computeRestPlan(character, resolved, derived, registry, type) {
175
204
  pushPartialRecoveries(cats, character, index, "short");
176
205
  character.equipment.forEach((entry, idx) => {
177
206
  var _a2, _b2, _c2, _d2, _e2;
178
- const rec = (_a2 = entry.state) == null ? void 0 : _a2.recovery;
179
- const charges = (_b2 = entry.state) == null ? void 0 : _b2.charges;
207
+ const view = (_b2 = (_a2 = resolved.infusions) == null ? void 0 : _a2.views.get(idx)) != null ? _b2 : null;
208
+ const rec = effectiveItemRecovery(entry, registry, view);
209
+ const charges = effectiveItemCharges(entry, registry, view);
180
210
  if (!rec || !charges) return;
181
211
  if (charges.current >= charges.max) return;
182
- if (rec.reset !== "short") return;
212
+ if (!restRestores("short", rec.reset)) return;
183
213
  const label = (_e2 = (_d2 = (_c2 = entry.overrides) == null ? void 0 : _c2.name) != null ? _d2 : resolveItemName(entry, registry)) != null ? _e2 : entry.item;
184
214
  cats.push({
185
215
  id: `item:${idx}`,
186
216
  label,
187
- preview: `${charges.current} \u2192 ${charges.max}`
217
+ preview: `${charges.current} \u2192 ${charges.max}`,
218
+ recharge: { amount: rec.amount, current: charges.current, max: charges.max }
188
219
  });
189
220
  });
190
221
  }
@@ -193,5 +224,7 @@ function computeRestPlan(character, resolved, derived, registry, type) {
193
224
  return { type, categories: cats, hdAvailable, hdRegainDist };
194
225
  }
195
226
  export {
196
- computeRestPlan
227
+ computeRestPlan,
228
+ earliestRestoringRest,
229
+ restRestores
197
230
  };
@@ -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<{
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  characterOverridesShape,
3
3
  characterSchema
4
- } from "../chunk-PZCE7DJM.js";
4
+ } from "../chunk-UE6LKRXQ.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;