@archivist-gg/dnd5e 0.3.1 → 0.3.5

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 (259) hide show
  1. package/LICENSES/SRD.md +25 -6
  2. package/dist/armor/armor.codec.js +4 -3
  3. package/dist/armor/armor.parser.js +3 -2
  4. package/dist/armor/armor.schema.d.ts +4 -0
  5. package/dist/armor/armor.schema.js +2 -1
  6. package/dist/armor/armor.types.d.ts +8 -0
  7. package/dist/background/background.codec.js +7 -6
  8. package/dist/background/background.parser.js +6 -5
  9. package/dist/background/background.schema.d.ts +26 -0
  10. package/dist/background/background.schema.js +5 -4
  11. package/dist/background/background.types.d.ts +22 -0
  12. package/dist/{chunk-4TIJKN6O.js → chunk-23LZLBJK.js} +1 -1
  13. package/dist/{chunk-AFKTJXRA.js → chunk-2DFENQIJ.js} +18 -0
  14. package/dist/chunk-2FRUSVZS.js +489 -0
  15. package/dist/chunk-2VDTW7QO.js +1580 -0
  16. package/dist/{chunk-ZZGEVJKX.js → chunk-3JOTQW7A.js} +1 -1
  17. package/dist/{chunk-5ZBE4CWV.js → chunk-3PZHBLFG.js} +1 -1
  18. package/dist/chunk-4U55VNC7.js +22 -0
  19. package/dist/{chunk-4JHOHWBI.js → chunk-4XTNPNQB.js} +1 -1
  20. package/dist/{chunk-HCP3GMHS.js → chunk-5N2GW72F.js} +15 -2
  21. package/dist/{chunk-42Y5IJKT.js → chunk-5RKLL2AD.js} +5 -1
  22. package/dist/{chunk-SE7AZDR3.js → chunk-63XQXPZL.js} +29 -3
  23. package/dist/{chunk-4F6AIZ36.js → chunk-6BFWZW6T.js} +1 -1
  24. package/dist/{chunk-GJOI2GHP.js → chunk-6GNXYAYP.js} +1 -1
  25. package/dist/{chunk-66XXW2Z2.js → chunk-6PXTNCBP.js} +2 -2
  26. package/dist/chunk-6X2NV665.js +33 -0
  27. package/dist/{chunk-LV4SNWZQ.js → chunk-6X4KUDMU.js} +8 -1
  28. package/dist/{chunk-ZMR77DDL.js → chunk-AW3EHF3L.js} +1 -1
  29. package/dist/{chunk-TLYDBT5F.js → chunk-CGRLQ34U.js} +64 -7
  30. package/dist/chunk-CJYCVNW2.js +7 -0
  31. package/dist/{chunk-XLSVNUTK.js → chunk-CV5XDJKU.js} +1 -1
  32. package/dist/{chunk-RAWJTA45.js → chunk-DEEHHLAP.js} +1 -1
  33. package/dist/{chunk-6IRYTM5V.js → chunk-DPUJDOKV.js} +119 -28
  34. package/dist/{chunk-GE4TLPWM.js → chunk-EHDATXP7.js} +1 -1
  35. package/dist/chunk-EVMUJYUD.js +195 -0
  36. package/dist/{chunk-K6Q5OUGK.js → chunk-GFZ7PITJ.js} +86 -10
  37. package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
  38. package/dist/{chunk-TN6ZLTNU.js → chunk-I2NDWFDD.js} +51 -4
  39. package/dist/{chunk-3DZ74AKK.js → chunk-IN4M4X7P.js} +8 -2
  40. package/dist/chunk-IUAAXXNO.js +58 -0
  41. package/dist/{chunk-NXSWH3AE.js → chunk-IWRVOCT5.js} +1 -1
  42. package/dist/{chunk-XJNECUPT.js → chunk-JC5UNIVM.js} +19 -0
  43. package/dist/{chunk-24GFQU7T.js → chunk-JSZ4H6AQ.js} +1 -1
  44. package/dist/{chunk-XTIQWSFM.js → chunk-KADJZGZY.js} +1 -1
  45. package/dist/{chunk-L7E2UT5A.js → chunk-KK33PIDN.js} +5 -1
  46. package/dist/chunk-KPEJMNRD.js +302 -0
  47. package/dist/chunk-KU3YLF6D.js +106 -0
  48. package/dist/{chunk-5INR4NSL.js → chunk-LDDCNPHD.js} +1 -1
  49. package/dist/chunk-LVQLWRCU.js +15 -0
  50. package/dist/chunk-MI7P3NX3.js +161 -0
  51. package/dist/{chunk-PHQRGDRQ.js → chunk-N3A5ICBO.js} +5 -1
  52. package/dist/chunk-O4SRD3J5.js +165 -0
  53. package/dist/chunk-OAXWSVJB.js +81 -0
  54. package/dist/chunk-OZP6JFGT.js +162 -0
  55. package/dist/{chunk-NAEPSZAM.js → chunk-PDJSUH24.js} +24 -2
  56. package/dist/chunk-PP2UHLBA.js +50 -0
  57. package/dist/chunk-PVCEA4HZ.js +6 -0
  58. package/dist/{chunk-RSDRMH54.js → chunk-RF4TYCA2.js} +1 -1
  59. package/dist/chunk-RLGQ5PZZ.js +16 -0
  60. package/dist/chunk-RVXC6ZHY.js +89 -0
  61. package/dist/chunk-S7REMWW4.js +21 -0
  62. package/dist/{chunk-7VJ6BOA5.js → chunk-SMLXZUBH.js} +9 -1
  63. package/dist/chunk-TOM66P2P.js +38 -0
  64. package/dist/chunk-UA5KS2PL.js +26 -0
  65. package/dist/{chunk-N6N74K6X.js → chunk-UBBKSYBY.js} +1 -1
  66. package/dist/{chunk-353WXS6S.js → chunk-UIRMA5KM.js} +1 -1
  67. package/dist/{chunk-BIK4DFWK.js → chunk-ULCQ73LA.js} +1 -1
  68. package/dist/{chunk-2BWAID3Y.js → chunk-UMWIPLLM.js} +29 -3
  69. package/dist/chunk-UQ3ZFCWD.js +178 -0
  70. package/dist/chunk-UXPGW4TI.js +101 -0
  71. package/dist/chunk-V2MJE6NC.js +133 -0
  72. package/dist/{chunk-D3CLOBE3.js → chunk-V373TRJE.js} +48 -10
  73. package/dist/chunk-VQAXTIBW.js +100 -0
  74. package/dist/chunk-W74BCA7V.js +159 -0
  75. package/dist/{chunk-WP2CX2JO.js → chunk-WELIKLZF.js} +22 -1
  76. package/dist/{chunk-MDEJHMKK.js → chunk-WHVLNFTG.js} +26 -5
  77. package/dist/{chunk-GZ46OVGZ.js → chunk-WSVMLNTO.js} +1 -1
  78. package/dist/{chunk-4LZJXJJS.js → chunk-WXWPK3LI.js} +6 -2
  79. package/dist/chunk-X3D6LXUU.js +185 -0
  80. package/dist/chunk-XJ2F2WO6.js +8 -0
  81. package/dist/{chunk-73HOFQQ5.js → chunk-Y4AGLCY6.js} +1 -1
  82. package/dist/chunk-YBLDE5CG.js +42 -0
  83. package/dist/{chunk-JEYQU3JT.js → chunk-YHYTW5QA.js} +2 -18
  84. package/dist/{chunk-PZOWBI3B.js → chunk-YLL2QXY2.js} +7 -2
  85. package/dist/class/class.codec.js +12 -9
  86. package/dist/class/class.parser.js +11 -8
  87. package/dist/class/class.schema.d.ts +55 -3
  88. package/dist/class/class.schema.js +9 -7
  89. package/dist/class/class.types.d.ts +48 -3
  90. package/dist/condition/condition.codec.d.ts +9 -0
  91. package/dist/condition/condition.entity-type.d.ts +2 -0
  92. package/dist/condition/condition.parser.d.ts +13 -0
  93. package/dist/condition/condition.parser.js +7 -0
  94. package/dist/condition/condition.schema.d.ts +29 -0
  95. package/dist/condition/condition.types.d.ts +15 -0
  96. package/dist/condition/condition.types.js +0 -0
  97. package/dist/dnd/constants.d.ts +22 -0
  98. package/dist/dnd/constants.js +9 -3
  99. package/dist/dnd/formula-tags.js +2 -2
  100. package/dist/dnd/math.d.ts +26 -0
  101. package/dist/dnd/math.js +12 -2
  102. package/dist/dnd/prose-tags.js +1 -1
  103. package/dist/dnd/resource-formula.d.ts +36 -10
  104. package/dist/dnd/resource-formula.js +10 -155
  105. package/dist/dnd/srd-tag-converter.js +3 -3
  106. package/dist/dnd/tag-grammar.js +1 -1
  107. package/dist/dnd/warn-once.d.ts +2 -0
  108. package/dist/dnd/warn-once.js +8 -0
  109. package/dist/entities/base-item-resolver.js +2 -2
  110. package/dist/entities/slug.d.ts +13 -0
  111. package/dist/entities/slug.js +5 -3
  112. package/dist/entities/wikilink-display.d.ts +3 -0
  113. package/dist/entities/wikilink-display.js +10 -0
  114. package/dist/feat/feat.category-codes.d.ts +32 -0
  115. package/dist/feat/feat.category-codes.js +14 -0
  116. package/dist/feat/feat.codec.js +7 -5
  117. package/dist/feat/feat.parser.js +6 -4
  118. package/dist/feat/feat.schema.d.ts +239 -0
  119. package/dist/feat/feat.schema.js +5 -3
  120. package/dist/feat/feat.types.d.ts +37 -1
  121. package/dist/index.js +2033 -6907
  122. package/dist/item/item.codec.js +4 -3
  123. package/dist/item/item.enrichment.js +4 -4
  124. package/dist/item/item.parser.js +3 -2
  125. package/dist/item/item.schema.d.ts +69 -3
  126. package/dist/item/item.schema.js +2 -1
  127. package/dist/item/item.types.d.ts +69 -3
  128. package/dist/monster/monster.codec.d.ts +7 -6
  129. package/dist/monster/monster.enrichment.js +4 -4
  130. package/dist/monster/monster.format.d.ts +135 -0
  131. package/dist/monster/monster.format.js +78 -0
  132. package/dist/monster/monster.parser.d.ts +6 -1
  133. package/dist/monster/monster.parser.js +10 -1
  134. package/dist/monster/monster.schema.d.ts +369 -0
  135. package/dist/monster/monster.schema.js +34 -0
  136. package/dist/monster/monster.types.d.ts +200 -14
  137. package/dist/optional-feature/optional-feature.codec.js +6 -5
  138. package/dist/optional-feature/optional-feature.parser.js +5 -4
  139. package/dist/optional-feature/optional-feature.schema.d.ts +185 -0
  140. package/dist/optional-feature/optional-feature.schema.js +4 -3
  141. package/dist/pack.d.ts +1 -1
  142. package/dist/pc/conditions.constants.d.ts +0 -1
  143. package/dist/pc/conditions.constants.js +1 -3
  144. package/dist/pc/decision-recognizer.js +1 -1
  145. package/dist/pc/pc.additional-spells.d.ts +47 -0
  146. package/dist/pc/pc.additional-spells.js +23 -0
  147. package/dist/pc/pc.asi-flatten.d.ts +18 -0
  148. package/dist/pc/pc.decision-engine.d.ts +105 -17
  149. package/dist/pc/pc.decision-engine.js +28 -12
  150. package/dist/pc/pc.defense-normalize.d.ts +11 -0
  151. package/dist/pc/pc.defense-normalize.js +6 -0
  152. package/dist/pc/pc.equipment.d.ts +31 -2
  153. package/dist/pc/pc.equipment.js +12 -8
  154. package/dist/pc/pc.feature-effects.d.ts +234 -11
  155. package/dist/pc/pc.feature-effects.js +21 -5
  156. package/dist/pc/pc.parser.js +2 -2
  157. package/dist/pc/pc.pools.d.ts +11 -3
  158. package/dist/pc/pc.pools.js +9 -13
  159. package/dist/pc/pc.proficiencies.d.ts +54 -29
  160. package/dist/pc/pc.proficiencies.js +74 -95
  161. package/dist/pc/pc.proficiency-grants.d.ts +58 -0
  162. package/dist/pc/pc.proficiency-normalize.d.ts +24 -0
  163. package/dist/pc/pc.proficiency-normalize.js +12 -0
  164. package/dist/pc/pc.proficiency-query.d.ts +13 -0
  165. package/dist/pc/pc.proficiency-query.js +1 -1
  166. package/dist/pc/pc.recalc.d.ts +69 -14
  167. package/dist/pc/pc.recalc.js +261 -122
  168. package/dist/pc/pc.resolver.d.ts +34 -8
  169. package/dist/pc/pc.resolver.js +27 -12
  170. package/dist/pc/pc.resource-seed.d.ts +3 -2
  171. package/dist/pc/pc.resource-seed.js +19 -17
  172. package/dist/pc/pc.resources.d.ts +87 -0
  173. package/dist/pc/pc.resources.js +21 -0
  174. package/dist/pc/pc.rest.d.ts +10 -1
  175. package/dist/pc/pc.rest.js +66 -12
  176. package/dist/pc/pc.schema.d.ts +139 -3
  177. package/dist/pc/pc.schema.js +4 -2
  178. package/dist/pc/pc.slotting.js +3 -3
  179. package/dist/pc/pc.spellcasting.d.ts +75 -6
  180. package/dist/pc/pc.spellcasting.js +16 -6
  181. package/dist/pc/pc.table-column.d.ts +23 -0
  182. package/dist/pc/pc.table-column.js +13 -3
  183. package/dist/pc/pc.types.d.ts +251 -12
  184. package/dist/pc/pool-layout.d.ts +47 -0
  185. package/dist/pc/pool-layout.js +16 -0
  186. package/dist/pc/roll-scope.d.ts +2 -0
  187. package/dist/pc/roll-scope.js +8 -0
  188. package/dist/pc/roll-tag-labels.d.ts +40 -0
  189. package/dist/pc/roll-tag-labels.js +17 -0
  190. package/dist/pc/spell-source.d.ts +21 -0
  191. package/dist/pc/spell-source.js +13 -0
  192. package/dist/race/race.codec.js +9 -7
  193. package/dist/race/race.parser.js +8 -6
  194. package/dist/race/race.schema.d.ts +51 -1
  195. package/dist/race/race.schema.js +8 -5
  196. package/dist/race/race.structural.d.ts +7 -0
  197. package/dist/race/race.structural.js +6 -0
  198. package/dist/race/race.types.d.ts +20 -0
  199. package/dist/schemas/attack-schema.d.ts +5 -0
  200. package/dist/schemas/caster-type-schema.d.ts +14 -0
  201. package/dist/schemas/caster-type-schema.js +6 -0
  202. package/dist/schemas/choice-schema.js +2 -2
  203. package/dist/schemas/entity-extras-schema.d.ts +53 -0
  204. package/dist/schemas/entity-extras-schema.js +10 -0
  205. package/dist/schemas/equipment-grant-schema.d.ts +2 -0
  206. package/dist/schemas/equipment-grant-schema.js +1 -1
  207. package/dist/schemas/feature-alias.d.ts +34 -0
  208. package/dist/schemas/feature-effect-schema.d.ts +133 -0
  209. package/dist/schemas/feature-effect-schema.js +1 -1
  210. package/dist/schemas/feature-schema.d.ts +8 -0
  211. package/dist/schemas/feature-schema.js +6 -4
  212. package/dist/schemas/resource-schema.d.ts +43 -0
  213. package/dist/schemas/resource-schema.js +1 -1
  214. package/dist/schemas/selection-pool-schema.d.ts +2 -0
  215. package/dist/schemas/selection-pool-schema.js +1 -1
  216. package/dist/spell/spell.access.js +23 -3
  217. package/dist/spell/spell.codec.js +4 -3
  218. package/dist/spell/spell.enrichment.js +4 -4
  219. package/dist/spell/spell.parser.d.ts +30 -0
  220. package/dist/spell/spell.parser.js +9 -2
  221. package/dist/spell/spell.scaling.d.ts +27 -6
  222. package/dist/spell/spell.scaling.js +25 -6
  223. package/dist/spell/spell.schema.d.ts +44 -2
  224. package/dist/spell/spell.schema.js +2 -1
  225. package/dist/spell/spell.types.d.ts +14 -0
  226. package/dist/subclass/subclass.codec.d.ts +1 -1
  227. package/dist/subclass/subclass.codec.js +11 -8
  228. package/dist/subclass/subclass.parser.js +10 -7
  229. package/dist/subclass/subclass.schema.d.ts +54 -7
  230. package/dist/subclass/subclass.schema.js +8 -6
  231. package/dist/subclass/subclass.types.d.ts +20 -2
  232. package/dist/types/choice.d.ts +53 -2
  233. package/dist/types/choice.js +13 -1
  234. package/dist/types/equipment-grant.d.ts +8 -1
  235. package/dist/types/feature-effect.d.ts +85 -23
  236. package/dist/types/feature.d.ts +70 -1
  237. package/dist/types/optional-feature.types.d.ts +28 -0
  238. package/dist/types/resource.d.ts +21 -1
  239. package/dist/types/selection-pool.d.ts +17 -2
  240. package/dist/weapon/weapon.classify.js +2 -2
  241. package/dist/weapon/weapon.codec.js +4 -3
  242. package/dist/weapon/weapon.parser.js +3 -2
  243. package/dist/weapon/weapon.schema.d.ts +4 -0
  244. package/dist/weapon/weapon.schema.js +2 -1
  245. package/dist/weapon/weapon.types.d.ts +8 -0
  246. package/package.json +2 -2
  247. package/dist/chunk-5XUXXAQJ.js +0 -30
  248. package/dist/chunk-7P65Q426.js +0 -158
  249. package/dist/chunk-7TEK5KK7.js +0 -49
  250. package/dist/chunk-AIRFC5NQ.js +0 -143
  251. package/dist/chunk-CZPMTQOY.js +0 -68
  252. package/dist/chunk-N2JE7BWL.js +0 -81
  253. package/dist/chunk-NXR3BD2V.js +0 -90
  254. package/dist/chunk-O5EYMKFH.js +0 -6
  255. package/dist/chunk-Q5K6LWBZ.js +0 -45
  256. package/dist/chunk-TNUFPIXI.js +0 -1110
  257. package/dist/chunk-TZK36BU7.js +0 -38
  258. package/dist/chunk-W7HWMMBF.js +0 -46
  259. package/dist/chunk-Y4I74YEG.js +0 -33
@@ -1,6 +1,6 @@
1
1
  // src/schemas/resource-schema.ts
2
2
  import { z } from "zod";
3
- var resetTriggerEnum = z.enum(["short-rest", "long-rest", "dawn", "dusk", "turn", "round", "custom"]);
3
+ var resetTriggerEnum = z.enum(["short-rest", "long-rest", "either", "dawn", "dusk", "turn", "round", "custom"]);
4
4
  var actionCostEnum = z.enum(["action", "bonus-action", "reaction", "free", "special"]);
5
5
  var resourceSchema = z.object({
6
6
  id: z.string().min(1),
@@ -25,7 +25,8 @@ var resourceSchema = z.object({
25
25
  amount: z.union([z.number(), z.string()]),
26
26
  action: actionCostEnum.optional(),
27
27
  uses: z.number().int().nonnegative().optional(),
28
- reset: resetTriggerEnum
28
+ reset: resetTriggerEnum,
29
+ restores: z.enum(["uses", "spell-slots"]).optional()
29
30
  })).optional()
30
31
  });
31
32
  var resourceConsumptionSchema = z.object({
@@ -33,12 +34,16 @@ var resourceConsumptionSchema = z.object({
33
34
  resource: z.string().optional(),
34
35
  column: z.string().optional(),
35
36
  amount: z.number().int().positive(),
37
+ amount_max: z.number().int().positive().optional(),
36
38
  expend_condition: z.enum(["roll_succeeds", "roll_fails", "target_takes_damage", "always"]).optional(),
37
39
  free_uses: z.object({
38
40
  amount: z.number().int().positive(),
39
41
  reset: resetTriggerEnum,
40
42
  state_key: z.string().optional()
41
43
  }).optional()
44
+ }).refine((c) => c.amount_max === void 0 || c.amount_max >= c.amount, {
45
+ path: ["amount_max"],
46
+ message: "amount_max must be >= amount"
42
47
  });
43
48
 
44
49
  export {
@@ -1,15 +1,18 @@
1
1
  import {
2
2
  classCodec
3
- } from "../chunk-GE4TLPWM.js";
4
- import "../chunk-42Y5IJKT.js";
5
- import "../chunk-TLYDBT5F.js";
6
- import "../chunk-4TIJKN6O.js";
7
- import "../chunk-CZPMTQOY.js";
3
+ } from "../chunk-EHDATXP7.js";
4
+ import "../chunk-5RKLL2AD.js";
5
+ import "../chunk-4U55VNC7.js";
6
+ import "../chunk-CGRLQ34U.js";
7
+ import "../chunk-23LZLBJK.js";
8
+ import "../chunk-CJYCVNW2.js";
9
+ import "../chunk-W74BCA7V.js";
8
10
  import "../chunk-WYGD2UGN.js";
9
- import "../chunk-PZOWBI3B.js";
10
- import "../chunk-3DZ74AKK.js";
11
- import "../chunk-NXSWH3AE.js";
12
- import "../chunk-NXR3BD2V.js";
11
+ import "../chunk-YLL2QXY2.js";
12
+ import "../chunk-IN4M4X7P.js";
13
+ import "../chunk-IWRVOCT5.js";
14
+ import "../chunk-X3D6LXUU.js";
15
+ import "../chunk-UA5KS2PL.js";
13
16
  export {
14
17
  classCodec
15
18
  };
@@ -1,14 +1,17 @@
1
1
  import {
2
2
  parseClass
3
- } from "../chunk-42Y5IJKT.js";
4
- import "../chunk-TLYDBT5F.js";
5
- import "../chunk-4TIJKN6O.js";
6
- import "../chunk-CZPMTQOY.js";
3
+ } from "../chunk-5RKLL2AD.js";
4
+ import "../chunk-4U55VNC7.js";
5
+ import "../chunk-CGRLQ34U.js";
6
+ import "../chunk-23LZLBJK.js";
7
+ import "../chunk-CJYCVNW2.js";
8
+ import "../chunk-W74BCA7V.js";
7
9
  import "../chunk-WYGD2UGN.js";
8
- import "../chunk-PZOWBI3B.js";
9
- import "../chunk-3DZ74AKK.js";
10
- import "../chunk-NXSWH3AE.js";
11
- import "../chunk-NXR3BD2V.js";
10
+ import "../chunk-YLL2QXY2.js";
11
+ import "../chunk-IN4M4X7P.js";
12
+ import "../chunk-IWRVOCT5.js";
13
+ import "../chunk-X3D6LXUU.js";
14
+ import "../chunk-UA5KS2PL.js";
12
15
  export {
13
16
  parseClass
14
17
  };
@@ -82,14 +82,16 @@ export declare const classEntitySchema: z.ZodObject<{
82
82
  survival: "survival";
83
83
  }>>;
84
84
  }, z.core.$strip>;
85
+ choices: z.ZodOptional<z.ZodArray<z.ZodType<import("../index.js").Choice, unknown, z.core.$ZodTypeInternals<import("../index.js").Choice, unknown>>>>;
85
86
  starting_equipment: z.ZodArray<z.ZodType<import("./class.types.js").StartingEquipmentEntry, unknown, z.core.$ZodTypeInternals<import("./class.types.js").StartingEquipmentEntry, unknown>>>;
86
87
  starting_gold: z.ZodOptional<z.ZodType<import("./class.types.js").StartingGold, unknown, z.core.$ZodTypeInternals<import("./class.types.js").StartingGold, unknown>>>;
87
88
  spellcasting: z.ZodNullable<z.ZodObject<{
88
89
  caster_type: z.ZodEnum<{
89
- pact: "pact";
90
- full: "full";
91
90
  half: "half";
91
+ full: "full";
92
+ pact: "pact";
92
93
  third: "third";
94
+ artificer: "artificer";
93
95
  }>;
94
96
  ability: z.ZodEnum<{
95
97
  str: "str";
@@ -108,7 +110,7 @@ export declare const classEntitySchema: z.ZodObject<{
108
110
  subclass_level: z.ZodNumber;
109
111
  subclass_feature_name: z.ZodString;
110
112
  weapon_mastery: z.ZodNullable<z.ZodObject<{
111
- starting_count: z.ZodNumber;
113
+ starting_count: z.ZodOptional<z.ZodNumber>;
112
114
  scaling: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
113
115
  }, z.core.$strip>>;
114
116
  epic_boon_level: z.ZodNullable<z.ZodNumber>;
@@ -133,6 +135,7 @@ export declare const classEntitySchema: z.ZodObject<{
133
135
  reset: z.ZodEnum<{
134
136
  "short-rest": "short-rest";
135
137
  "long-rest": "long-rest";
138
+ either: "either";
136
139
  dawn: "dawn";
137
140
  dusk: "dusk";
138
141
  turn: "turn";
@@ -158,12 +161,17 @@ export declare const classEntitySchema: z.ZodObject<{
158
161
  reset: z.ZodEnum<{
159
162
  "short-rest": "short-rest";
160
163
  "long-rest": "long-rest";
164
+ either: "either";
161
165
  dawn: "dawn";
162
166
  dusk: "dusk";
163
167
  turn: "turn";
164
168
  round: "round";
165
169
  custom: "custom";
166
170
  }>;
171
+ restores: z.ZodOptional<z.ZodEnum<{
172
+ uses: "uses";
173
+ "spell-slots": "spell-slots";
174
+ }>>;
167
175
  }, z.core.$strip>>>;
168
176
  }, z.core.$strip>>;
169
177
  selection_pools: z.ZodOptional<z.ZodArray<z.ZodObject<{
@@ -196,7 +204,51 @@ export declare const classEntitySchema: z.ZodObject<{
196
204
  layout: z.ZodOptional<z.ZodEnum<{
197
205
  "spell-like": "spell-like";
198
206
  blocks: "blocks";
207
+ "dice-pool": "dice-pool";
208
+ "point-pool": "point-pool";
199
209
  }>>;
200
210
  }, z.core.$strip>;
201
211
  }, z.core.$strip>>>;
212
+ rendering_hint: z.ZodOptional<z.ZodString>;
213
+ has_fluff: z.ZodOptional<z.ZodBoolean>;
214
+ has_fluff_images: z.ZodOptional<z.ZodBoolean>;
215
+ table_col_labels: z.ZodOptional<z.ZodArray<z.ZodString>>;
216
+ starting_equipment_additional_from_background: z.ZodOptional<z.ZodBoolean>;
217
+ multiclassing: z.ZodOptional<z.ZodUnknown>;
218
+ cantrip_progression: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
219
+ prepared_spells: z.ZodOptional<z.ZodString>;
220
+ prepared_spells_change: z.ZodOptional<z.ZodString>;
221
+ prepared_spells_progression: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
222
+ spells_known_progression: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
223
+ spells_known_progression_fixed: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
224
+ spells_known_progression_fixed_allow_lower_level: z.ZodOptional<z.ZodBoolean>;
225
+ spells_known_progression_fixed_by_level: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodNumber>>>;
226
+ feat_progression: z.ZodOptional<z.ZodArray<z.ZodObject<{
227
+ name: z.ZodString;
228
+ progression: z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodNumber>, z.ZodArray<z.ZodNumber>]>;
229
+ feature_type: z.ZodOptional<z.ZodArray<z.ZodString>>;
230
+ featureType: z.ZodOptional<z.ZodArray<z.ZodString>>;
231
+ category: z.ZodOptional<z.ZodArray<z.ZodString>>;
232
+ required: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
233
+ }, z.core.$strip>>>;
234
+ optionalfeature_progression: z.ZodOptional<z.ZodArray<z.ZodObject<{
235
+ name: z.ZodString;
236
+ progression: z.ZodUnion<readonly [z.ZodRecord<z.ZodString, z.ZodNumber>, z.ZodArray<z.ZodNumber>]>;
237
+ feature_type: z.ZodOptional<z.ZodArray<z.ZodString>>;
238
+ featureType: z.ZodOptional<z.ZodArray<z.ZodString>>;
239
+ category: z.ZodOptional<z.ZodArray<z.ZodString>>;
240
+ required: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
241
+ }, z.core.$strip>>>;
242
+ additional_spells: z.ZodOptional<z.ZodArray<z.ZodObject<{
243
+ name: z.ZodOptional<z.ZodString>;
244
+ ability: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
245
+ choose: z.ZodArray<z.ZodString>;
246
+ }, z.core.$strip>]>>;
247
+ known: z.ZodOptional<z.ZodUnknown>;
248
+ innate: z.ZodOptional<z.ZodUnknown>;
249
+ prepared: z.ZodOptional<z.ZodUnknown>;
250
+ expanded: z.ZodOptional<z.ZodUnknown>;
251
+ resourceName: z.ZodOptional<z.ZodString>;
252
+ }, z.core.$strip>>>;
253
+ image: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
202
254
  }, z.core.$strip>;
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  classEntitySchema
3
- } from "../chunk-TLYDBT5F.js";
4
- import "../chunk-4TIJKN6O.js";
5
- import "../chunk-CZPMTQOY.js";
3
+ } from "../chunk-CGRLQ34U.js";
4
+ import "../chunk-23LZLBJK.js";
5
+ import "../chunk-CJYCVNW2.js";
6
+ import "../chunk-W74BCA7V.js";
6
7
  import "../chunk-WYGD2UGN.js";
7
- import "../chunk-PZOWBI3B.js";
8
- import "../chunk-3DZ74AKK.js";
9
- import "../chunk-NXSWH3AE.js";
10
- import "../chunk-NXR3BD2V.js";
8
+ import "../chunk-YLL2QXY2.js";
9
+ import "../chunk-IN4M4X7P.js";
10
+ import "../chunk-IWRVOCT5.js";
11
+ import "../chunk-X3D6LXUU.js";
12
+ import "../chunk-UA5KS2PL.js";
11
13
  export {
12
14
  classEntitySchema
13
15
  };
@@ -1,7 +1,8 @@
1
- import type { Feature, Ability, SkillSlug, Resource } from "@archivist-gg/dnd5e";
1
+ import type { Feature, Ability, SkillSlug, Resource, Choice } from "@archivist-gg/dnd5e";
2
2
  import type { StartingEquipmentEntry, StartingGold } from "@archivist-gg/dnd5e/types/equipment-grant";
3
3
  export type { StartingEquipmentEntry, StartingGold } from "@archivist-gg/dnd5e/types/equipment-grant";
4
4
  import type { SelectionPool, PoolGrant, TabDecl } from "@archivist-gg/dnd5e/types/selection-pool";
5
+ import type { AdditionalSpellsEntry, ProgressionEntry } from "@archivist-gg/dnd5e/schemas/entity-extras-schema";
5
6
  import type { Edition } from "@archivist-gg/dnd5e/types/edition";
6
7
  export type { Edition };
7
8
  export type ArmorCategory = "light" | "medium" | "heavy" | "shield";
@@ -30,7 +31,8 @@ export interface SkillChoices {
30
31
  count: number;
31
32
  from: SkillSlug[];
32
33
  }
33
- export type CasterType = "full" | "half" | "third" | "pact";
34
+ import type { CasterType } from "@archivist-gg/dnd5e/schemas/caster-type-schema";
35
+ export type { CasterType };
34
36
  export type SpellcastingPreparation = "known" | "prepared";
35
37
  export interface SpellcastingConfig {
36
38
  caster_type: CasterType;
@@ -38,8 +40,20 @@ export interface SpellcastingConfig {
38
40
  preparation: SpellcastingPreparation;
39
41
  spell_list: string;
40
42
  }
43
+ /** A SUBCLASS spellcasting block is a partial (R4-G1a D7): the converter emits {ability} alone on subclasses that
44
+ * only name a save ability (Path of the Giant, Four Elements) and {ability, caster_type} on the third-casters
45
+ * (Eldritch Knight, Arcane Trickster). The CLASS block stays fully required. */
46
+ export interface SubclassSpellcastingConfig {
47
+ ability: Ability;
48
+ caster_type?: CasterType;
49
+ preparation?: SpellcastingPreparation;
50
+ spell_list?: string;
51
+ }
41
52
  export interface WeaponMasteryConfig {
42
- starting_count: number;
53
+ /** OPTIONAL since R4-G1b (§2.7): the converter must be able to re-emit a countless mastery object
54
+ * (G5 owns counts-from-prose). Declaration 2 of 3 — the schema and the generator's COPIED
55
+ * `interface WeaponMasteryConfig` in tools/srd-canonical/merger-rules/class-merge.ts are the others. */
56
+ starting_count?: number;
43
57
  scaling?: Record<number, number>;
44
58
  }
45
59
  export interface ClassTableRow {
@@ -58,6 +72,14 @@ export interface ClassEntity {
58
72
  saving_throws: Ability[];
59
73
  proficiencies: ClassProficiencies;
60
74
  skill_choices: SkillChoices;
75
+ /**
76
+ * Entity-level decisions the class grants at L1, mirroring the long-standing
77
+ * `RaceEntity.choices` / `BackgroundEntity.choices` precedent. Classes were the
78
+ * sole holdout: a tool pick like the Bard's "three musical instruments of your
79
+ * choice" belongs to the CLASS, not to any one of its L1 features, so before
80
+ * this there was nowhere to author it.
81
+ */
82
+ choices?: Choice[];
61
83
  starting_equipment: StartingEquipmentEntry[];
62
84
  starting_gold?: StartingGold;
63
85
  spellcasting: SpellcastingConfig | null;
@@ -71,4 +93,27 @@ export interface ClassEntity {
71
93
  selection_pools?: SelectionPool[];
72
94
  pool_grants?: PoolGrant[];
73
95
  tabs?: TabDecl[];
96
+ /** Converter/bundle extras declared by class.schema.ts §2.7; all optional, none read today. */
97
+ rendering_hint?: string;
98
+ has_fluff?: boolean;
99
+ has_fluff_images?: boolean;
100
+ table_col_labels?: string[];
101
+ starting_equipment_additional_from_background?: boolean;
102
+ /** RAW 5etools passthrough (four measured arities incl. `{}`): `unknown` mirrors `z.unknown()`. */
103
+ multiclassing?: unknown;
104
+ cantrip_progression?: number[];
105
+ prepared_spells?: string;
106
+ prepared_spells_change?: string;
107
+ prepared_spells_progression?: number[];
108
+ spells_known_progression?: number[];
109
+ spells_known_progression_fixed?: number[];
110
+ /** ⚠️ BOOLEAN, not an array (finding 1). */
111
+ spells_known_progression_fixed_allow_lower_level?: boolean;
112
+ /** ⚠️ TWO-DEEP record: level -> spell level -> count (finding 1). */
113
+ spells_known_progression_fixed_by_level?: Record<string, Record<string, number>>;
114
+ feat_progression?: ProgressionEntry[];
115
+ optionalfeature_progression?: ProgressionEntry[];
116
+ additional_spells?: AdditionalSpellsEntry[];
117
+ /** One wikilink, or an array of them for the multi-fluff-image emit. */
118
+ image?: string | string[];
74
119
  }
@@ -0,0 +1,9 @@
1
+ import type { DocCodec } from "@archivist-gg/core";
2
+ import type { ConditionEntity } from "./condition.types.js";
3
+ /**
4
+ * Normalizing codec. `parse` delegates to `parseCondition`, which seeds the
5
+ * `edition: "2014"` default and validates against `conditionEntitySchema`.
6
+ * `serialize` stays `yaml.dump` (the edit-save path uses obsidian's separate
7
+ * serializer), mirroring every sibling entity codec.
8
+ */
9
+ export declare const conditionCodec: DocCodec<ConditionEntity>;
@@ -0,0 +1,2 @@
1
+ import type { EntityType } from "@archivist-gg/core";
2
+ export declare const conditionEntityType: EntityType;
@@ -0,0 +1,13 @@
1
+ import type { ConditionEntity } from "./condition.types.js";
2
+ import { ParseResult } from "@archivist-gg/core";
3
+ /**
4
+ * The RACE pattern (spec §6): required keys enforced by `parseYaml`, the
5
+ * `edition: "2014"` default seeded BEFORE validation (a declared edition wins —
6
+ * the spread order is load-bearing), and `result.data` returned DIRECTLY. That
7
+ * keeps `slug` on the output — the spell parser's slug strip is what mints its
8
+ * 1,048-row census row — and, because the measured corpus carries exactly the two
9
+ * declared key-sets, `z.object`'s strip removes nothing. The absence of a
10
+ * KNOWN_KEYS gate and a `raw` bag is why there is no *relocated* or *duplicated*
11
+ * row either.
12
+ */
13
+ export declare function parseCondition(source: string): ParseResult<ConditionEntity>;
@@ -0,0 +1,7 @@
1
+ import {
2
+ parseCondition
3
+ } from "../chunk-6X2NV665.js";
4
+ import "../chunk-UA5KS2PL.js";
5
+ export {
6
+ parseCondition
7
+ };
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The `condition` entity (spec §6). Measured corpus at design time: 89 documents
4
+ * (59 converter over 4 books + 30 bundle) in exactly TWO key-sets — with
5
+ * `has_fluff_images` (39) and without (50) — over 15 distinct names that are
6
+ * BYTE-IDENTICAL across every book that ships them. Editions: converter 44/15,
7
+ * bundle 15/15, so the closed enum is safe. NOT every book ships all 15
8
+ * (`Hunt for the Thessalhydra` has no Exhaustion): completeness is never assumed.
9
+ *
10
+ * Plain `z.object` on purpose — no `.loose()`, no raw bag, no KNOWN_KEYS list: the
11
+ * corpus has no keys beyond these, and the parser returns the validated object
12
+ * directly (see `condition.parser.ts`), so nothing is relocated or duplicated.
13
+ *
14
+ * `edition` is REQUIRED here; the parser seeds `"2014"` BEFORE validation, so an
15
+ * authored note without the key still parses (all 89 corpus docs carry it).
16
+ * `image` is already `.optional()` at its source — never append a second one.
17
+ */
18
+ export declare const conditionEntitySchema: z.ZodObject<{
19
+ slug: z.ZodString;
20
+ name: z.ZodString;
21
+ edition: z.ZodEnum<{
22
+ 2014: "2014";
23
+ 2024: "2024";
24
+ }>;
25
+ source: z.ZodString;
26
+ description: z.ZodString;
27
+ has_fluff_images: z.ZodOptional<z.ZodBoolean>;
28
+ image: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
29
+ }, z.core.$strip>;
@@ -0,0 +1,15 @@
1
+ import type { imageField } from "../schemas/entity-extras-schema.js";
2
+ import type { Edition } from "../types/edition.js";
3
+ import type { z } from "zod";
4
+ /** A 5e condition document (spec §6). Mirrors `conditionEntitySchema` exactly. */
5
+ export interface ConditionEntity {
6
+ slug: string;
7
+ name: string;
8
+ edition: Edition;
9
+ source: string;
10
+ /** Markdown; wikilinks to sibling conditions ride through verbatim. */
11
+ description: string;
12
+ has_fluff_images?: boolean;
13
+ /** One wikilink, or an array for >= 2 fluff images (images-ON emit). */
14
+ image?: z.infer<typeof imageField>;
15
+ }
File without changes
@@ -1,3 +1,4 @@
1
+ import type { Edition } from "../types/edition.js";
1
2
  export declare const CR_PROFICIENCY: Record<string, number>;
2
3
  export declare const CR_XP: Record<string, number>;
3
4
  export declare const ALL_CR_VALUES: string[];
@@ -11,6 +12,27 @@ export declare const DAMAGE_TYPES: string[];
11
12
  export declare const DAMAGE_NONMAGICAL_VARIANTS: string[];
12
13
  export declare const CONDITIONS: string[];
13
14
  export declare const STANDARD_SENSES: string[];
15
+ /** R4-G7 T8 RIDER-22 (F-STDACT) · the standard combat actions any character can take, per rules edition, in the book's
16
+ * alphabetical order. The plugin's Actions tab reads the character's edition, so this is rendering data, never a
17
+ * renderer constant (it printed ONE union of both editions). 2014 is the PHB chapter 9 list; 2024 is the 2024 action
18
+ * list, which drops Cast a Spell (now Magic) and Use an Object (now Utilize) and adds Influence and Study. No rules
19
+ * glossary ships in the SRD 2024 bundle; its prose names ten of the twelve as "the <X> action" and none of the 2014-only
20
+ * names (measured 2026-09-15 over the plugin repo's `.compendium-bundle/SRD 2024`). */
21
+ export declare const STANDARD_ACTIONS: Record<Edition, readonly string[]>;
14
22
  export declare const ALIGNMENT_ETHICAL: string[];
15
23
  export declare const ALIGNMENT_MORAL: string[];
16
24
  export declare const ALL_SECTIONS: string[];
25
+ /**
26
+ * Full ability NAME (lower-case) → canonical three-letter key. Distinct from `ABILITY_NAMES`
27
+ * above, which is the OTHER direction and yields the display casing ("str" → "STR").
28
+ *
29
+ * Moved here from `pc/pc.feature-effects.ts` in R4-G3a §6.2.3, where it was private: the scope
30
+ * normaliser (`pc/roll-scope.ts`) needs exactly the same vocabulary, and a second copy is the
31
+ * defect class this phase exists to remove. `src/dnd/*` imports nothing from `src/pc/*`, so the
32
+ * move introduces no cycle; the type is spelled `(typeof ABILITY_KEYS)[number]` rather than the
33
+ * `Ability` alias so this module keeps its zero imports.
34
+ */
35
+ export declare const ABILITY_NAME_TO_KEY: Record<string, (typeof ABILITY_KEYS)[number]>;
36
+ /** Accepts a canonical key ("dex") or a full ability name ("Dexterity"), any casing / padding;
37
+ * returns the canonical key, or null when the value is neither. */
38
+ export declare function normalizeAbility(value: string): (typeof ABILITY_KEYS)[number] | null;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  ABILITY_KEYS,
3
3
  ABILITY_NAMES,
4
+ ABILITY_NAME_TO_KEY,
4
5
  ALIGNMENT_ETHICAL,
5
6
  ALIGNMENT_MORAL,
6
7
  ALL_CR_VALUES,
@@ -14,11 +15,14 @@ import {
14
15
  DAMAGE_TYPES,
15
16
  SIZE_HIT_DICE,
16
17
  SKILL_ABILITY,
17
- STANDARD_SENSES
18
- } from "../chunk-WP2CX2JO.js";
18
+ STANDARD_ACTIONS,
19
+ STANDARD_SENSES,
20
+ normalizeAbility
21
+ } from "../chunk-WELIKLZF.js";
19
22
  export {
20
23
  ABILITY_KEYS,
21
24
  ABILITY_NAMES,
25
+ ABILITY_NAME_TO_KEY,
22
26
  ALIGNMENT_ETHICAL,
23
27
  ALIGNMENT_MORAL,
24
28
  ALL_CR_VALUES,
@@ -32,5 +36,7 @@ export {
32
36
  DAMAGE_TYPES,
33
37
  SIZE_HIT_DICE,
34
38
  SKILL_ABILITY,
35
- STANDARD_SENSES
39
+ STANDARD_ACTIONS,
40
+ STANDARD_SENSES,
41
+ normalizeAbility
36
42
  };
@@ -5,10 +5,10 @@ import {
5
5
  import {
6
6
  abilityModifier,
7
7
  formatModifier
8
- } from "../chunk-NAEPSZAM.js";
8
+ } from "../chunk-PDJSUH24.js";
9
9
  import {
10
10
  ABILITY_KEYS
11
- } from "../chunk-WP2CX2JO.js";
11
+ } from "../chunk-WELIKLZF.js";
12
12
 
13
13
  // src/dnd/formula-tags.ts
14
14
  function resolveSlugForTag(slug, tagType, registry) {
@@ -22,3 +22,29 @@ export declare function passivePerception(wisScore: number, perceptionProf: "non
22
22
  export declare function attackBonus(abilityScore: number, profBonus: number): number;
23
23
  export declare function saveDC(abilityScore: number, profBonus: number): number;
24
24
  export declare function abilityNameToKey(name: string): (typeof ABILITY_KEYS)[number] | null;
25
+ /** Is `type` one of the canonical damage types, whatever its casing? A rider whose declared type is
26
+ * anything else, a sentinel (`weapon`) or prose ("same as the weapon's type"), INHERITS the weapon row's
27
+ * own damage type; `pc.recalc.ts` resolves that where the rider is merged onto the row, never in a
28
+ * renderer, and never from a list of prose spellings. The ONE exception is the schema's own sentinel
29
+ * {@link CHOSEN_DAMAGE_TYPE}, which means the player's choice, not the row's type (R4-G7 T8 RIDER-13). */
30
+ export declare function isCanonicalDamageType(type: string): boolean;
31
+ /** The schema's own damage-type sentinel for a rider whose type the PLAYER picks when the damage is dealt
32
+ * (`feature-effect-schema.ts`, the `damage-bonus` arm: "player-selected damage type at action time"). It is a
33
+ * declared schema value, not a prose spelling, so it never inherits the weapon row's type: the rider keeps it,
34
+ * and the sheet prints the amount with no type and {@link CHOSEN_DAMAGE_TYPE_NOTE} in the row's caption
35
+ * (R4-G7 T8 RIDER-13). */
36
+ export declare const CHOSEN_DAMAGE_TYPE = "chosen";
37
+ /** The caption words a renderer prints for a {@link CHOSEN_DAMAGE_TYPE} rider in place of a damage type. One
38
+ * constant, so no renderer spells the phrase itself. */
39
+ export declare const CHOSEN_DAMAGE_TYPE_NOTE = "damage type of your choice";
40
+ /** Is `type` the {@link CHOSEN_DAMAGE_TYPE} sentinel, whatever its casing or surrounding space? */
41
+ export declare function isChosenDamageType(type: string | undefined): boolean;
42
+ /** Can a damage rider be printed INSIDE the damage text, as a dice chip? Only when it reads as a dice
43
+ * expression or a (signed) number, optionally followed by ONE canonical damage type: `1d6`, `+2`,
44
+ * `1d6 fire`. Anything else is prose ("your Wisdom modifier necrotic", "half your fighter level
45
+ * slashing") and belongs in the row's caption instead (R4-G7 T6a E-4 (c)).
46
+ *
47
+ * `text` is the rider's PRINTED form, its amount plus its resolved damage type, because a shipped
48
+ * rider may carry the type inside the amount itself (`{amount: "1d6 fire"}` with no `damage_type`, the
49
+ * migrated manual override of `pc.equipment.ts`). */
50
+ export declare function isRenderableDamageText(text: string): boolean;
package/dist/dnd/math.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import {
2
+ CHOSEN_DAMAGE_TYPE,
3
+ CHOSEN_DAMAGE_TYPE_NOTE,
2
4
  abilityModifier,
3
5
  abilityNameToKey,
4
6
  attackBonus,
@@ -6,6 +8,9 @@ import {
6
8
  formatModifier,
7
9
  hitDiceSizeFromCreatureSize,
8
10
  hpFromHitDice,
11
+ isCanonicalDamageType,
12
+ isChosenDamageType,
13
+ isRenderableDamageText,
9
14
  parseHitDiceFormula,
10
15
  passive,
11
16
  passivePerception,
@@ -14,9 +19,11 @@ import {
14
19
  saveDC,
15
20
  savingThrow,
16
21
  skillBonus
17
- } from "../chunk-NAEPSZAM.js";
18
- import "../chunk-WP2CX2JO.js";
22
+ } from "../chunk-PDJSUH24.js";
23
+ import "../chunk-WELIKLZF.js";
19
24
  export {
25
+ CHOSEN_DAMAGE_TYPE,
26
+ CHOSEN_DAMAGE_TYPE_NOTE,
20
27
  abilityModifier,
21
28
  abilityNameToKey,
22
29
  attackBonus,
@@ -24,6 +31,9 @@ export {
24
31
  formatModifier,
25
32
  hitDiceSizeFromCreatureSize,
26
33
  hpFromHitDice,
34
+ isCanonicalDamageType,
35
+ isChosenDamageType,
36
+ isRenderableDamageText,
27
37
  parseHitDiceFormula,
28
38
  passive,
29
39
  passivePerception,
@@ -1,6 +1,6 @@
1
1
  // src/dnd/prose-tags.ts
2
2
  function convert5eToolsTags(text) {
3
- const rewritten = text.replace(/\{@atk\s+mw,rw\}/gi, "Melee or Ranged Weapon Attack:").replace(/\{@atk\s+mws\}/gi, "Melee or Ranged Weapon Attack:").replace(/\{@atk\s+msw\}/gi, "Melee or Ranged Spell Attack:").replace(/\{@atk\s+mw\}/gi, "Melee Weapon Attack:").replace(/\{@atk\s+rw\}/gi, "Ranged Weapon Attack:").replace(/\{@atk\s+ms\}/gi, "Melee Spell Attack:").replace(/\{@atk\s+rs\}/gi, "Ranged Spell Attack:").replace(/\{@hit\s+(\d+)\}/gi, "`atk:+$1`").replace(/\{@h\}/gi, "Hit:").replace(/\{@damage\s+([^}]+)\}/gi, "`damage:$1`").replace(/\{@dice\s+([^}]+)\}/gi, "`roll:$1`").replace(/\{@d20\s+([^}]+)\}/gi, "`roll:d20$1`").replace(/\{@dc\s+(\d+)\}/gi, "`dc:$1`").replace(/\{@recharge\s+(\d)\}/gi, "(Recharge $1-6)").replace(/\{@recharge\}/gi, "(Recharge)").replace(/\{@chance\s+(\d+)\}/gi, "$1% chance").replace(/\{@b(?:old)?\s+([^}]+)\}/gi, "**$1**").replace(/\{@i(?:talic)?\s+([^}]+)\}/gi, "_$1_").replace(/\{@s(?:trike)?\s+([^}]+)\}/gi, "~~$1~~").replace(/\{@note\s+([^}]+)\}/gi, "($1)").replace(/\{@spell\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@item\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@creature\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@condition\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@skill\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@sense\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@action\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@status\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@ability\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@class\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@feat\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@background\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@race\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@disease\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@hazard\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@plane\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@language\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@book\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@adventure\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@\w+\s+([^}]+)\}/g, "$1");
3
+ const rewritten = text.replace(/\{@atk\s+mw,rw\}/gi, "Melee or Ranged Weapon Attack:").replace(/\{@atk\s+mws\}/gi, "Melee or Ranged Weapon Attack:").replace(/\{@atk\s+msw\}/gi, "Melee or Ranged Spell Attack:").replace(/\{@atk\s+mw\}/gi, "Melee Weapon Attack:").replace(/\{@atk\s+rw\}/gi, "Ranged Weapon Attack:").replace(/\{@atk\s+ms\}/gi, "Melee Spell Attack:").replace(/\{@atk\s+rs\}/gi, "Ranged Spell Attack:").replace(/\{@hit\s+(\d+)\}/gi, "`atk:+$1`").replace(/\{@h\}\s*/gi, "Hit: ").replace(/\{@damage\s+([^}]+)\}/gi, "`damage:$1`").replace(/\{@dice\s+([^}]+)\}/gi, "`roll:$1`").replace(/\{@d20\s+([^}]+)\}/gi, "`roll:d20$1`").replace(/\{@dc\s+(\d+)\}/gi, "`dc:$1`").replace(/\{@recharge\s+(\d)\}/gi, "(Recharge $1-6)").replace(/\{@recharge\}/gi, "(Recharge)").replace(/\{@chance\s+(\d+)\}/gi, "$1% chance").replace(/\{@b(?:old)?\s+([^}]+)\}/gi, "**$1**").replace(/\{@i(?:talic)?\s+([^}]+)\}/gi, "_$1_").replace(/\{@s(?:trike)?\s+([^}]+)\}/gi, "~~$1~~").replace(/\{@note\s+([^}]+)\}/gi, "($1)").replace(/\{@spell\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@item\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@creature\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@condition\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@skill\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@sense\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@action\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@status\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@ability\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@class\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@feat\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@background\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@race\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@disease\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@hazard\s+([^|}]+)[^}]*\}/gi, "**$1**").replace(/\{@plane\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@language\s+([^|}]+)[^}]*\}/gi, "$1").replace(/\{@book\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@adventure\s+([^|}]+)[^}]*\}/gi, "_$1_").replace(/\{@\w+\s+([^}]+)\}/g, "$1");
4
4
  return decorateProseDice(rewritten);
5
5
  }
6
6
  function decorateProseDice(text) {
@@ -1,16 +1,23 @@
1
1
  /**
2
- * Tiny DSL for Resource.max_formula and Resource.recovery[].amount (SP4d). Grammar:
2
+ * Tiny DSL for Resource.max_formula and Resource.recovery[].amount (SP4d; R4-G4 §6 added max / min). Grammar:
3
3
  * expr := term (('+' | '-') term)*
4
4
  * term := factor (('*' | '/') factor)*
5
- * factor := number | string-arg-only | ident | '{' ident '}' | fn '(' expr ')'
5
+ * factor := number | string-arg-only | ident | '{' ident '}' | fn1 '(' expr ')' | fnN '(' expr (',' expr)+ ')'
6
6
  * | "column" '(' string ')' | '(' expr ')'
7
- * fn := 'ceil' | 'floor'
7
+ * fn1 := 'ceil' | 'floor' (exactly one argument)
8
+ * fnN := 'max' | 'min' (two or more comma-separated arguments)
8
9
  * ident := level | class_level | prof | <abil>_mod
9
- * The single-quoted string literal (e.g. 'Seals') is valid ONLY as the
10
- * argument to column(...).
11
- * '*' and '/' bind tighter than '+'/'-'. '/' is real division; wrap in
12
- * ceil()/floor() for integer results (e.g. "ceil({class_level}/2)").
13
- * `999` is the at-will sentinel; it evaluates as the literal 999.
10
+ * The single-quoted string literal (e.g. 'Seals') is valid ONLY as the argument to column(...).
11
+ * '*' and '/' bind tighter than '+'/'-'. '/' is real division; wrap in ceil()/floor() for integer
12
+ * results (e.g. "ceil({class_level}/2)"). "max(1, {cha_mod})" is how the data says "a minimum of once".
13
+ * `AT_WILL_MAX` (999) is the at-will sentinel: it evaluates as the literal 999; R4-G4 T3 (§5) taught
14
+ * the plugin's charge boxes to render "at will" for it instead of 999 boxes (the `opts.atWill` branch
15
+ * at the head of `renderChargeBoxes`, fed by the `atWill: fu.max === AT_WILL_MAX` opt its callers
16
+ * pass). Measured 2026-09-05 on the plugin tree that carries T7b with
17
+ * `grep -rn "atWill:" packages/obsidian/src`: FOUR lines, the two T3 feature trackers
18
+ * `renderCardResource` and `renderFirstResourceTracker`, T5's pool-tab dice head `renderPoolHead`,
19
+ * and T7b's `renderPickTracker`, which draws a pool pick's own `uses` on the pool row, the granted
20
+ * row and the boon row.
14
21
  */
15
22
  export interface FormulaBindings {
16
23
  level: number;
@@ -27,6 +34,7 @@ export interface FormulaBindings {
27
34
  * Read by the `column('Name')` accessor; missing name → 0. */
28
35
  columns: Record<string, number>;
29
36
  }
37
+ export declare const AT_WILL_MAX = 999;
30
38
  export declare function isValidMaxFormula(formula: string): boolean;
31
39
  export declare function evaluateMaxFormula(formula: string, bindings: FormulaBindings): number;
32
40
  export interface ScalableResource {
@@ -36,6 +44,24 @@ export interface ScalableResource {
36
44
  max: string;
37
45
  }[];
38
46
  }
39
- /** The max-formula string in effect at `totalLevel`: the highest `scales_at`
40
- * step whose level ≤ totalLevel, else the base `max_formula`. */
47
+ /** The max-formula string in effect at `totalLevel`: the highest `scales_at` step whose level
48
+ * ≤ totalLevel (the FIRST declaration wins on a duplicate level; a `level: 0` step is skipped), else
49
+ * the base `max_formula`. Parse-free, so a die-string step comes back as the die string. Its one
50
+ * production caller, the plugin's `seedFeatureUses` (`pc.resource-seed.ts`), moved to
51
+ * `resolveMaxCountAt` in R4-G4 T3, so it is now TEST-ONLY: zero callers in this repo's `src/` and zero
52
+ * in the plugin's `packages/obsidian/src/`, pinned by this repo's `tests/resource-formula.test.ts`
53
+ * (its Bardic-Die-2024 and duplicate-level-tie cases) and by the plugin's cross-repo file of the same
54
+ * name (its `describe("resolveMaxAt")` block). */
41
55
  export declare function resolveMaxAt(totalLevel: number, resource: ScalableResource): string;
56
+ /** The max COUNT in effect at `level`: the highest `scales_at` step at or below `level` whose `max`
57
+ * PARSES under the DSL, else the base `max_formula` if it parses, else null. Ties break exactly as
58
+ * `resolveMaxAt` breaks them (the FIRST declaration at a duplicate level wins, a `level: 0` step is
59
+ * skipped), so a duplicate-level pair of PARSING steps cannot make the count and the die label pick
60
+ * different steps; where one member of the pair is a die string they DO pick different steps
61
+ * (`[{level:3,max:"1d8"},{level:3,max:"3"}]` at 3 reads 3 here and "1d8" there), which is the same
62
+ * parse-vs-string divergence described next. A step that does not parse is a die size (Bardic Die
63
+ * 2024: "1d8" at 5), not a count, and is skipped HERE while `resolveMaxAt` still returns it; a base
64
+ * that does not parse (Sneak Attack "1d6") is a damage die, correctly no tracker. `resolveMaxAt`
65
+ * keeps the parse-free string lookup; R4-G4 T3 handed its one production caller, the plugin seed, to
66
+ * this function (see its docblock), so a null here is what the seed warns on and leaves un-seeded. */
67
+ export declare function resolveMaxCountAt(level: number, resource: ScalableResource, bindings: FormulaBindings): number | null;