@archivist-gg/dnd5e 0.3.0 → 0.3.4

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 (260) 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 +34 -0
  10. package/dist/background/background.schema.js +9 -6
  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-4FWNK4FD.js +159 -0
  16. package/dist/chunk-4U55VNC7.js +22 -0
  17. package/dist/{chunk-4JHOHWBI.js → chunk-4XTNPNQB.js} +1 -1
  18. package/dist/{chunk-HCP3GMHS.js → chunk-5N2GW72F.js} +15 -2
  19. package/dist/{chunk-42Y5IJKT.js → chunk-5U5FFFA3.js} +5 -1
  20. package/dist/{chunk-4F6AIZ36.js → chunk-5XMQPTHD.js} +1 -1
  21. package/dist/{chunk-GJOI2GHP.js → chunk-6GNXYAYP.js} +1 -1
  22. package/dist/chunk-6PKV5V2H.js +178 -0
  23. package/dist/{chunk-66XXW2Z2.js → chunk-6PXTNCBP.js} +2 -2
  24. package/dist/chunk-6X2NV665.js +33 -0
  25. package/dist/{chunk-LV4SNWZQ.js → chunk-6X4KUDMU.js} +8 -1
  26. package/dist/{chunk-ZMR77DDL.js → chunk-AW3EHF3L.js} +1 -1
  27. package/dist/chunk-CJYCVNW2.js +7 -0
  28. package/dist/chunk-COEOOQX2.js +133 -0
  29. package/dist/{chunk-XTIQWSFM.js → chunk-D5U7GMPX.js} +1 -1
  30. package/dist/{chunk-RAWJTA45.js → chunk-DEEHHLAP.js} +1 -1
  31. package/dist/chunk-DPUJDOKV.js +365 -0
  32. package/dist/{chunk-73HOFQQ5.js → chunk-ESS46GR4.js} +1 -1
  33. package/dist/chunk-EVMUJYUD.js +195 -0
  34. package/dist/{chunk-2BWAID3Y.js → chunk-FDBWYMZK.js} +29 -3
  35. package/dist/{chunk-K6Q5OUGK.js → chunk-GFZ7PITJ.js} +86 -10
  36. package/dist/chunk-H7KBLR4X.js +81 -0
  37. package/dist/{chunk-L7E2UT5A.js → chunk-HB7XZXDK.js} +5 -1
  38. package/dist/{chunk-VTYUBINW.js → chunk-HJ5EEZ47.js} +1 -1
  39. package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
  40. package/dist/{chunk-A4WENOUQ.js → chunk-I2NDWFDD.js} +52 -8
  41. package/dist/{chunk-RSDRMH54.js → chunk-IMZFOOVL.js} +1 -1
  42. package/dist/{chunk-3DZ74AKK.js → chunk-IN4M4X7P.js} +8 -2
  43. package/dist/chunk-IUAAXXNO.js +58 -0
  44. package/dist/{chunk-XJNECUPT.js → chunk-JC5UNIVM.js} +19 -0
  45. package/dist/chunk-JJ46T5XX.js +297 -0
  46. package/dist/{chunk-TUIFSVLI.js → chunk-JRDPUDT5.js} +30 -3
  47. package/dist/{chunk-24GFQU7T.js → chunk-JSZ4H6AQ.js} +1 -1
  48. package/dist/chunk-KU3YLF6D.js +106 -0
  49. package/dist/{chunk-5INR4NSL.js → chunk-LDDCNPHD.js} +1 -1
  50. package/dist/{chunk-DZXSWSBP.js → chunk-LMBAEIP6.js} +1 -1
  51. package/dist/chunk-LVQLWRCU.js +15 -0
  52. package/dist/chunk-MI7P3NX3.js +161 -0
  53. package/dist/chunk-O4SRD3J5.js +165 -0
  54. package/dist/{chunk-EMOORSQ7.js → chunk-OSQFPGLM.js} +45 -6
  55. package/dist/chunk-OZP6JFGT.js +162 -0
  56. package/dist/{chunk-NAEPSZAM.js → chunk-PDJSUH24.js} +24 -2
  57. package/dist/chunk-PP2UHLBA.js +50 -0
  58. package/dist/chunk-PVCEA4HZ.js +6 -0
  59. package/dist/{chunk-XLSVNUTK.js → chunk-R3VAKWKW.js} +1 -1
  60. package/dist/chunk-RIXI5D3R.js +89 -0
  61. package/dist/chunk-RLGQ5PZZ.js +16 -0
  62. package/dist/chunk-S7REMWW4.js +21 -0
  63. package/dist/{chunk-7VJ6BOA5.js → chunk-SMLXZUBH.js} +9 -1
  64. package/dist/{chunk-NXSWH3AE.js → chunk-T26ZVCL5.js} +1 -1
  65. package/dist/chunk-TOM66P2P.js +38 -0
  66. package/dist/chunk-UA5KS2PL.js +26 -0
  67. package/dist/{chunk-N6N74K6X.js → chunk-UBBKSYBY.js} +1 -1
  68. package/dist/{chunk-353WXS6S.js → chunk-UIRMA5KM.js} +1 -1
  69. package/dist/{chunk-GE4TLPWM.js → chunk-US5IKYCW.js} +1 -1
  70. package/dist/chunk-UXPGW4TI.js +101 -0
  71. package/dist/chunk-VQAXTIBW.js +100 -0
  72. package/dist/{chunk-WP2CX2JO.js → chunk-WELIKLZF.js} +22 -1
  73. package/dist/chunk-WPWOHGPI.js +172 -0
  74. package/dist/{chunk-GZ46OVGZ.js → chunk-WSVMLNTO.js} +1 -1
  75. package/dist/{chunk-4LZJXJJS.js → chunk-WXWPK3LI.js} +6 -2
  76. package/dist/{chunk-ZZGEVJKX.js → chunk-XBQMCEI2.js} +1 -1
  77. package/dist/{chunk-PHQRGDRQ.js → chunk-XGOFP7AQ.js} +5 -1
  78. package/dist/chunk-XJ2F2WO6.js +8 -0
  79. package/dist/chunk-XQCSGNXE.js +1580 -0
  80. package/dist/chunk-YBLDE5CG.js +42 -0
  81. package/dist/{chunk-JEYQU3JT.js → chunk-YHYTW5QA.js} +2 -18
  82. package/dist/{chunk-TLYDBT5F.js → chunk-YJJTISBN.js} +64 -7
  83. package/dist/{chunk-PZOWBI3B.js → chunk-YLL2QXY2.js} +7 -2
  84. package/dist/{chunk-MDEJHMKK.js → chunk-ZONJ66NE.js} +26 -5
  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 +230 -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 +2120 -6923
  122. package/dist/item/item.ai-schema.d.ts +1 -1
  123. package/dist/item/item.codec.js +4 -3
  124. package/dist/item/item.enrichment.js +4 -4
  125. package/dist/item/item.parser.js +3 -2
  126. package/dist/item/item.schema.d.ts +69 -3
  127. package/dist/item/item.schema.js +2 -1
  128. package/dist/item/item.types.d.ts +69 -3
  129. package/dist/monster/monster.codec.d.ts +7 -6
  130. package/dist/monster/monster.enrichment.js +4 -4
  131. package/dist/monster/monster.format.d.ts +135 -0
  132. package/dist/monster/monster.format.js +78 -0
  133. package/dist/monster/monster.parser.d.ts +6 -1
  134. package/dist/monster/monster.parser.js +10 -1
  135. package/dist/monster/monster.schema.d.ts +369 -0
  136. package/dist/monster/monster.schema.js +34 -0
  137. package/dist/monster/monster.types.d.ts +200 -14
  138. package/dist/optional-feature/optional-feature.codec.js +6 -5
  139. package/dist/optional-feature/optional-feature.parser.js +5 -4
  140. package/dist/optional-feature/optional-feature.schema.d.ts +176 -0
  141. package/dist/optional-feature/optional-feature.schema.js +4 -3
  142. package/dist/pack.d.ts +1 -1
  143. package/dist/pc/conditions.constants.d.ts +0 -1
  144. package/dist/pc/conditions.constants.js +1 -3
  145. package/dist/pc/decision-recognizer.js +1 -1
  146. package/dist/pc/pc.additional-spells.d.ts +47 -0
  147. package/dist/pc/pc.additional-spells.js +23 -0
  148. package/dist/pc/pc.asi-flatten.d.ts +18 -0
  149. package/dist/pc/pc.decision-engine.d.ts +106 -5
  150. package/dist/pc/pc.decision-engine.js +28 -10
  151. package/dist/pc/pc.defense-normalize.d.ts +11 -0
  152. package/dist/pc/pc.defense-normalize.js +6 -0
  153. package/dist/pc/pc.equipment.d.ts +30 -1
  154. package/dist/pc/pc.equipment.js +12 -7
  155. package/dist/pc/pc.feature-effects.d.ts +225 -11
  156. package/dist/pc/pc.feature-effects.js +21 -5
  157. package/dist/pc/pc.parser.js +2 -2
  158. package/dist/pc/pc.pools.d.ts +11 -3
  159. package/dist/pc/pc.pools.js +9 -13
  160. package/dist/pc/pc.proficiencies.d.ts +60 -4
  161. package/dist/pc/pc.proficiencies.js +89 -37
  162. package/dist/pc/pc.proficiency-grants.d.ts +58 -0
  163. package/dist/pc/pc.proficiency-normalize.d.ts +29 -0
  164. package/dist/pc/pc.proficiency-normalize.js +12 -0
  165. package/dist/pc/pc.proficiency-query.d.ts +13 -0
  166. package/dist/pc/pc.proficiency-query.js +5 -1
  167. package/dist/pc/pc.recalc.d.ts +69 -14
  168. package/dist/pc/pc.recalc.js +291 -142
  169. package/dist/pc/pc.resolver.d.ts +34 -8
  170. package/dist/pc/pc.resolver.js +27 -12
  171. package/dist/pc/pc.resource-seed.d.ts +3 -2
  172. package/dist/pc/pc.resource-seed.js +19 -17
  173. package/dist/pc/pc.resources.d.ts +87 -0
  174. package/dist/pc/pc.resources.js +21 -0
  175. package/dist/pc/pc.rest.d.ts +10 -1
  176. package/dist/pc/pc.rest.js +66 -12
  177. package/dist/pc/pc.schema.d.ts +147 -7
  178. package/dist/pc/pc.schema.js +4 -2
  179. package/dist/pc/pc.slotting.js +3 -3
  180. package/dist/pc/pc.spellcasting.d.ts +80 -7
  181. package/dist/pc/pc.spellcasting.js +18 -6
  182. package/dist/pc/pc.table-column.d.ts +23 -0
  183. package/dist/pc/pc.table-column.js +13 -3
  184. package/dist/pc/pc.types.d.ts +253 -16
  185. package/dist/pc/pool-layout.d.ts +47 -0
  186. package/dist/pc/pool-layout.js +16 -0
  187. package/dist/pc/roll-scope.d.ts +2 -0
  188. package/dist/pc/roll-scope.js +8 -0
  189. package/dist/pc/roll-tag-labels.d.ts +40 -0
  190. package/dist/pc/roll-tag-labels.js +17 -0
  191. package/dist/pc/spell-source.d.ts +21 -0
  192. package/dist/pc/spell-source.js +13 -0
  193. package/dist/race/race.codec.js +9 -7
  194. package/dist/race/race.parser.js +8 -6
  195. package/dist/race/race.schema.d.ts +51 -1
  196. package/dist/race/race.schema.js +8 -5
  197. package/dist/race/race.structural.d.ts +7 -0
  198. package/dist/race/race.structural.js +6 -0
  199. package/dist/race/race.types.d.ts +20 -0
  200. package/dist/schemas/attack-schema.d.ts +5 -0
  201. package/dist/schemas/caster-type-schema.d.ts +14 -0
  202. package/dist/schemas/caster-type-schema.js +6 -0
  203. package/dist/schemas/choice-schema.js +2 -2
  204. package/dist/schemas/entity-extras-schema.d.ts +53 -0
  205. package/dist/schemas/entity-extras-schema.js +10 -0
  206. package/dist/schemas/equipment-grant-schema.d.ts +2 -0
  207. package/dist/schemas/equipment-grant-schema.js +1 -1
  208. package/dist/schemas/feature-alias.d.ts +34 -0
  209. package/dist/schemas/feature-effect-schema.d.ts +124 -0
  210. package/dist/schemas/feature-effect-schema.js +1 -1
  211. package/dist/schemas/feature-schema.d.ts +8 -0
  212. package/dist/schemas/feature-schema.js +6 -4
  213. package/dist/schemas/resource-schema.d.ts +43 -0
  214. package/dist/schemas/resource-schema.js +1 -1
  215. package/dist/schemas/selection-pool-schema.d.ts +2 -0
  216. package/dist/schemas/selection-pool-schema.js +1 -1
  217. package/dist/spell/spell.access.js +23 -3
  218. package/dist/spell/spell.codec.js +4 -3
  219. package/dist/spell/spell.enrichment.js +4 -4
  220. package/dist/spell/spell.parser.d.ts +30 -0
  221. package/dist/spell/spell.parser.js +9 -2
  222. package/dist/spell/spell.scaling.d.ts +27 -6
  223. package/dist/spell/spell.scaling.js +25 -6
  224. package/dist/spell/spell.schema.d.ts +44 -2
  225. package/dist/spell/spell.schema.js +2 -1
  226. package/dist/spell/spell.types.d.ts +14 -0
  227. package/dist/subclass/subclass.codec.d.ts +1 -1
  228. package/dist/subclass/subclass.codec.js +11 -8
  229. package/dist/subclass/subclass.parser.js +10 -7
  230. package/dist/subclass/subclass.schema.d.ts +54 -7
  231. package/dist/subclass/subclass.schema.js +8 -6
  232. package/dist/subclass/subclass.types.d.ts +20 -2
  233. package/dist/types/choice.d.ts +56 -0
  234. package/dist/types/choice.js +21 -3
  235. package/dist/types/equipment-grant.d.ts +8 -1
  236. package/dist/types/feature-effect.d.ts +78 -23
  237. package/dist/types/feature.d.ts +70 -1
  238. package/dist/types/optional-feature.types.d.ts +28 -0
  239. package/dist/types/resource.d.ts +21 -1
  240. package/dist/types/selection-pool.d.ts +17 -2
  241. package/dist/weapon/weapon.classify.js +2 -2
  242. package/dist/weapon/weapon.codec.js +4 -3
  243. package/dist/weapon/weapon.parser.js +3 -2
  244. package/dist/weapon/weapon.schema.d.ts +4 -0
  245. package/dist/weapon/weapon.schema.js +2 -1
  246. package/dist/weapon/weapon.types.d.ts +8 -0
  247. package/package.json +2 -2
  248. package/dist/chunk-5MZSB6OM.js +0 -1089
  249. package/dist/chunk-5XUXXAQJ.js +0 -30
  250. package/dist/chunk-7P65Q426.js +0 -158
  251. package/dist/chunk-AIRFC5NQ.js +0 -143
  252. package/dist/chunk-BH6AMZVY.js +0 -25
  253. package/dist/chunk-CZPMTQOY.js +0 -68
  254. package/dist/chunk-M2EMFD6S.js +0 -269
  255. package/dist/chunk-N2JE7BWL.js +0 -81
  256. package/dist/chunk-NXR3BD2V.js +0 -90
  257. package/dist/chunk-Q5K6LWBZ.js +0 -45
  258. package/dist/chunk-TZK36BU7.js +0 -38
  259. package/dist/chunk-W7HWMMBF.js +0 -46
  260. package/dist/chunk-Y4I74YEG.js +0 -33
@@ -4,47 +4,88 @@ import {
4
4
  import {
5
5
  collectChosenAbilityPoints,
6
6
  collectChosenProficiencies
7
- } from "../chunk-5MZSB6OM.js";
8
- import "../chunk-BH6AMZVY.js";
7
+ } from "../chunk-XQCSGNXE.js";
8
+ import {
9
+ resourceLevelFor
10
+ } from "../chunk-UXPGW4TI.js";
9
11
  import {
10
12
  computeSpellLimits,
11
13
  deriveSpellSlots,
14
+ effectiveSpellcastingAbility,
12
15
  resolveSpellcasting
13
- } from "../chunk-M2EMFD6S.js";
14
- import "../chunk-5XUXXAQJ.js";
15
- import "../chunk-JEYQU3JT.js";
16
+ } 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
+ import {
27
+ toDefenseSlug
28
+ } from "../chunk-XJ2F2WO6.js";
16
29
  import {
30
+ buildUnarmedRow,
17
31
  computeAppliedBonuses,
18
32
  computeSlotsAndAttacks,
19
33
  emptyAppliedBonuses
20
- } from "../chunk-EMOORSQ7.js";
21
- import "../chunk-353WXS6S.js";
22
- import "../chunk-N6N74K6X.js";
34
+ } from "../chunk-OSQFPGLM.js";
35
+ import "../chunk-UIRMA5KM.js";
36
+ import "../chunk-UBBKSYBY.js";
23
37
  import {
24
- computeFeatureEffects
25
- } from "../chunk-AIRFC5NQ.js";
38
+ assembleEffectFeatures,
39
+ computeFeatureEffects,
40
+ foldsNow,
41
+ selfEffectsOf
42
+ } from "../chunk-JJ46T5XX.js";
43
+ import "../chunk-TOM66P2P.js";
44
+ import "../chunk-KU3YLF6D.js";
45
+ import "../chunk-RLGQ5PZZ.js";
26
46
  import "../chunk-LWFTHJIE.js";
27
47
  import "../chunk-DNAJRMNN.js";
28
- import "../chunk-4LZJXJJS.js";
29
- import "../chunk-LV4SNWZQ.js";
48
+ import "../chunk-LVQLWRCU.js";
49
+ import "../chunk-WXWPK3LI.js";
50
+ import "../chunk-6X4KUDMU.js";
51
+ import "../chunk-YBLDE5CG.js";
52
+ import {
53
+ evaluateMaxFormula,
54
+ isValidMaxFormula
55
+ } from "../chunk-EVMUJYUD.js";
30
56
  import "../chunk-VTTA2ALZ.js";
57
+ import "../chunk-OZP6JFGT.js";
58
+ import "../chunk-VQAXTIBW.js";
31
59
  import {
32
60
  abilityModifier,
33
61
  attackBonus,
62
+ isCanonicalDamageType,
63
+ isChosenDamageType,
34
64
  passive,
35
65
  passivePerception,
36
66
  proficiencyFromLevel,
37
67
  saveDC,
38
68
  savingThrow,
39
69
  skillBonus
40
- } from "../chunk-NAEPSZAM.js";
70
+ } from "../chunk-PDJSUH24.js";
41
71
  import {
42
72
  ABILITY_KEYS,
43
73
  ALL_SKILLS,
44
74
  SKILL_ABILITY
45
- } from "../chunk-WP2CX2JO.js";
75
+ } from "../chunk-WELIKLZF.js";
76
+ import "../chunk-4U55VNC7.js";
77
+ import "../chunk-UA5KS2PL.js";
46
78
 
47
79
  // src/pc/pc.recalc.ts
80
+ var WEAPON_CATEGORY_WORDS = /* @__PURE__ */ new Set([
81
+ "simple",
82
+ "martial",
83
+ "simple-melee",
84
+ "simple-ranged",
85
+ "martial-melee",
86
+ "martial-ranged",
87
+ "natural"
88
+ ]);
48
89
  function phbAverageForDie(hitDieStr) {
49
90
  const n = parseDieSize(hitDieStr);
50
91
  if (n == null) return 4;
@@ -86,7 +127,9 @@ function collectClassAsiBranch(resolved) {
86
127
  const out = {};
87
128
  for (const c of resolved.classes) {
88
129
  for (const [, choice] of Object.entries(c.choices)) {
89
- const asi = choice == null ? void 0 : choice.asi;
130
+ const block = choice;
131
+ if (typeof (block == null ? void 0 : block.feat) === "string") continue;
132
+ const asi = block == null ? void 0 : block.asi;
90
133
  if (!asi) continue;
91
134
  for (const ab of ABILITY_KEYS) {
92
135
  const v = asi[ab];
@@ -96,8 +139,8 @@ function collectClassAsiBranch(resolved) {
96
139
  }
97
140
  return out;
98
141
  }
99
- function abilityBonusBreakdown(resolved) {
100
- var _a, _b, _c, _d, _e, _f;
142
+ function abilityBonusBreakdown(resolved, featureEffects) {
143
+ var _a, _b, _c, _d, _e, _f, _g;
101
144
  const race = flattenRaceAsi(resolved.race);
102
145
  const origin = collectChosenAbilityPoints(resolved);
103
146
  const sub = subraceAsi(resolved);
@@ -114,7 +157,7 @@ function abilityBonusBreakdown(resolved) {
114
157
  const bonus = (_d = f.ability_bonuses) == null ? void 0 : _d[ab];
115
158
  if (typeof bonus === "number") feat += bonus;
116
159
  }
117
- out[ab] = { species, background: (_e = origin.background[ab]) != null ? _e : 0, class: (_f = classAsi[ab]) != null ? _f : 0, feat };
160
+ out[ab] = { species, background: (_e = origin.background[ab]) != null ? _e : 0, class: ((_f = classAsi[ab]) != null ? _f : 0) + ((_g = featureEffects == null ? void 0 : featureEffects.ability_bonus[ab]) != null ? _g : 0), feat };
118
161
  }
119
162
  return out;
120
163
  }
@@ -149,65 +192,123 @@ function hpLevelCount(classes) {
149
192
  function multiclassMaxHP(classes, conMod) {
150
193
  return Math.max(1, hitDiceAverageSum(classes) + conMod * hpLevelCount(classes));
151
194
  }
195
+ function resolveRiderAmount(amount, bindings) {
196
+ if (!amount.includes("{")) return amount;
197
+ const formula = amount.replace(/\{prof_bonus\}/g, "{prof}");
198
+ if (!isValidMaxFormula(formula)) return amount;
199
+ return String(evaluateMaxFormula(formula, bindings));
200
+ }
201
+ function resolveDamageRider(rider, rowDamageType, bindings) {
202
+ const out = { ...rider, amount: resolveRiderAmount(rider.amount, bindings) };
203
+ if (rider.damage_type !== void 0 && !isChosenDamageType(rider.damage_type)) {
204
+ const resolved = isCanonicalDamageType(rider.damage_type) ? rider.damage_type : rowDamageType;
205
+ if (resolved) out.damage_type = resolved;
206
+ else delete out.damage_type;
207
+ }
208
+ return out;
209
+ }
152
210
  function unarmoredAC(resolved, mods, warnings) {
153
211
  return unarmoredACBreakdown(resolved, mods, warnings).total;
154
212
  }
155
- function unarmoredACBreakdown(resolved, mods, warnings) {
156
- var _a, _b, _c, _d, _e, _f;
213
+ function unarmoredACBreakdown(resolved, mods, warnings, shieldBonus = 0) {
214
+ var _a, _b, _c, _d, _e;
157
215
  const baseTerms = [
158
216
  { source: "Unarmored", amount: 10, kind: "unarmored" },
159
217
  { source: "DEX modifier", amount: mods.dex, kind: "dex" }
160
218
  ];
219
+ const { activeBuffs } = assembleEffectFeatures(resolved);
220
+ const candidates = [
221
+ { total: 10 + mods.dex, terms: baseTerms, shieldAllowed: true }
222
+ ];
161
223
  for (const rf of resolved.features) {
162
- const eff = ((_a = rf.feature.effects) != null ? _a : []).find((e) => e.kind === "unarmored-ac");
163
- if (eff && eff.kind === "unarmored-ac") {
164
- const base = (_b = eff.base) != null ? _b : 10;
165
- const terms = [
166
- { source: "Unarmored", amount: base, kind: "unarmored" },
167
- { source: "DEX modifier", amount: mods.dex, kind: "dex" }
168
- ];
169
- let total = base + mods.dex;
224
+ if (!foldsNow(rf, activeBuffs)) continue;
225
+ for (const eff of selfEffectsOf(rf.feature)) {
226
+ if (eff.kind !== "unarmored-ac") continue;
227
+ const base = (_a = eff.base) != null ? _a : 10;
228
+ const terms = [{ source: "Unarmored", amount: base, kind: "unarmored" }];
229
+ let total = base;
170
230
  for (const ab of eff.abilities) {
171
- if (ab === "dex") continue;
172
- terms.push({ source: `${ab.toUpperCase()} modifier (${(_c = rf.feature.name) != null ? _c : "Unarmored"})`, amount: mods[ab], kind: "ability" });
231
+ terms.push(ab === "dex" ? { source: "DEX modifier", amount: mods.dex, kind: "dex" } : { source: `${ab.toUpperCase()} modifier (${(_b = rf.feature.name) != null ? _b : "Unarmored"})`, amount: mods[ab], kind: "ability" });
173
232
  total += mods[ab];
174
233
  }
175
- return { total, terms };
234
+ candidates.push({ total, terms, shieldAllowed: eff.allow_shield === true });
176
235
  }
177
236
  }
237
+ if (candidates.length > 1) {
238
+ const applied = (c) => c.total + (c.shieldAllowed ? shieldBonus : 0);
239
+ let best = candidates[0];
240
+ for (const c of candidates) if (applied(c) > applied(best)) best = c;
241
+ return best;
242
+ }
178
243
  for (const rf of resolved.features) {
179
244
  const feat = rf.feature;
180
- if ((_d = feat.unarmored_defense) == null ? void 0 : _d.ability) {
245
+ if ((_c = feat.unarmored_defense) == null ? void 0 : _c.ability) {
181
246
  const ab = feat.unarmored_defense.ability;
182
- const amt = (_e = mods[ab]) != null ? _e : 0;
247
+ const amt = (_d = mods[ab]) != null ? _d : 0;
183
248
  const terms = [
184
249
  ...baseTerms,
185
250
  { source: `${ab.toUpperCase()} modifier (Unarmored Defense)`, amount: amt, kind: "ability" }
186
251
  ];
187
- return { total: 10 + mods.dex + amt, terms };
252
+ return { total: 10 + mods.dex + amt, terms, shieldAllowed: true };
188
253
  }
189
254
  }
190
255
  for (const rf of resolved.features) {
191
- const name = ((_f = rf.feature.name) != null ? _f : "").toLowerCase();
256
+ const name = ((_e = rf.feature.name) != null ? _e : "").toLowerCase();
192
257
  if (!/unarmored\s*defense/.test(name)) continue;
193
258
  if (rf.source.kind === "class" && rf.source.slug.includes("monk")) {
194
- warnings.push(`Unarmored Defense detected by name on ${rf.source.slug}; populate unarmored_defense:{ability:wis} flag for accuracy.`);
195
259
  const terms = [
196
260
  ...baseTerms,
197
261
  { source: "WIS modifier (Unarmored Defense)", amount: mods.wis, kind: "ability" }
198
262
  ];
199
- return { total: 10 + mods.dex + mods.wis, terms };
263
+ return { total: 10 + mods.dex + mods.wis, terms, shieldAllowed: true };
200
264
  }
201
265
  if (rf.source.kind === "class" && rf.source.slug.includes("barbarian")) {
202
- warnings.push(`Unarmored Defense detected by name on ${rf.source.slug}; populate unarmored_defense:{ability:con} flag for accuracy.`);
203
266
  const terms = [
204
267
  ...baseTerms,
205
268
  { source: "CON modifier (Unarmored Defense)", amount: mods.con, kind: "ability" }
206
269
  ];
207
- return { total: 10 + mods.dex + mods.con, terms };
270
+ return { total: 10 + mods.dex + mods.con, terms, shieldAllowed: true };
208
271
  }
209
272
  }
210
- return { total: 10 + mods.dex, terms: baseTerms };
273
+ return { total: 10 + mods.dex, terms: baseTerms, shieldAllowed: true };
274
+ }
275
+ function resolveUnarmedStrike(resolved) {
276
+ var _a, _b, _c;
277
+ const dice = [];
278
+ const abilities = /* @__PURE__ */ new Set();
279
+ const classOf = (rf) => rf.source.kind === "class" ? resolved.classes.find((c) => {
280
+ var _a2;
281
+ return ((_a2 = c.entity) == null ? void 0 : _a2.slug) === rf.source.slug;
282
+ }) : void 0;
283
+ const readDie = (rf, d) => {
284
+ var _a2, _b2;
285
+ if (typeof d === "string") return d;
286
+ if (!d) return void 0;
287
+ const cls = classOf(rf);
288
+ return cls ? (_b2 = diceColumnAt((_a2 = cls.entity) == null ? void 0 : _a2.table, cls.level, d.column)) != null ? _b2 : void 0 : void 0;
289
+ };
290
+ for (const rf of resolved.features) {
291
+ const authored = selfEffectsOf(rf.feature).filter((e) => e.kind === "unarmed-strike");
292
+ for (const e of authored) {
293
+ const d2 = readDie(rf, e.dice);
294
+ if (d2) dice.push(d2);
295
+ for (const ab of (_a = e.abilities) != null ? _a : []) abilities.add(ab);
296
+ }
297
+ if (authored.length || rf.source.kind !== "class") continue;
298
+ const slug = ((_c = (_b = rf.feature.id) != null ? _b : rf.feature.name) != null ? _c : "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
299
+ const column = unarmedDieColumnFor(slug);
300
+ if (!column) continue;
301
+ const d = readDie(rf, { column });
302
+ if (!d) continue;
303
+ dice.push(d);
304
+ abilities.add("dex");
305
+ }
306
+ const avg = (d) => {
307
+ const m = /^(\d+)d(\d+)$/i.exec(d);
308
+ return m ? Number(m[1]) * (Number(m[2]) + 1) / 2 : 1;
309
+ };
310
+ const best = dice.sort((a, b) => avg(b) - avg(a))[0];
311
+ return { ...best ? { dice: best } : {}, ...abilities.size ? { abilities: [...abilities] } : {} };
211
312
  }
212
313
  function initiativeBonus(dexMod, feats, edition) {
213
314
  let bonus = dexMod;
@@ -308,28 +409,67 @@ function computeAbilityScores(resolved, overrides) {
308
409
  }
309
410
  return out;
310
411
  }
311
- function normalizeProfList(input) {
412
+ function normalizeArmorProf(input) {
312
413
  var _a, _b;
313
414
  if (!input) return { categories: [], specific: [] };
314
- if (Array.isArray(input)) return { categories: [], specific: input };
415
+ if (Array.isArray(input)) return { categories: input, specific: [] };
315
416
  return { categories: (_a = input.categories) != null ? _a : [], specific: (_b = input.specific) != null ? _b : [] };
316
417
  }
418
+ function normalizeWeaponToolProf(input) {
419
+ var _a, _b, _c;
420
+ if (!input) return { categories: [], specific: [] };
421
+ if (Array.isArray(input)) return { categories: [], specific: input };
422
+ return { categories: (_a = input.categories) != null ? _a : [], specific: ((_b = input.fixed) != null ? _b : []).concat((_c = input.specific) != null ? _c : []) };
423
+ }
317
424
  function mergeInto(target, source) {
318
425
  for (const c of source.categories) if (!target.categories.includes(c)) target.categories.push(c);
319
426
  for (const s of source.specific) if (!target.specific.includes(s)) target.specific.push(s);
320
427
  }
321
- function dedupeDefenseList(lists) {
322
- const seen = /* @__PURE__ */ new Set();
323
- const out = [];
324
- for (const list of lists) {
325
- for (const v of list) {
326
- const key = v.trim().toLowerCase();
327
- if (!key || seen.has(key)) continue;
328
- seen.add(key);
329
- out.push(v);
428
+ var ORIGIN_RANK = { manual: 0, equipment: 1, grant: 2 };
429
+ function composeDefenseEntries(manual, equipment, grants) {
430
+ var _a;
431
+ const byValue = /* @__PURE__ */ new Map();
432
+ const consider = (list, origin) => {
433
+ for (const raw of list) {
434
+ const value = toDefenseSlug(raw);
435
+ if (!value) continue;
436
+ const existing = byValue.get(value);
437
+ if (!existing) {
438
+ byValue.set(value, { value, label: raw.trim(), origin });
439
+ continue;
440
+ }
441
+ if (ORIGIN_RANK[origin] > ORIGIN_RANK[existing.origin]) existing.origin = origin;
330
442
  }
443
+ };
444
+ consider(manual, "manual");
445
+ consider(equipment, "equipment");
446
+ for (const g of grants) {
447
+ const value = toDefenseSlug(g.value);
448
+ if (!value) continue;
449
+ const existing = byValue.get(value);
450
+ if (!existing) {
451
+ byValue.set(value, {
452
+ value,
453
+ label: g.value.trim(),
454
+ origin: "grant",
455
+ sources: [...g.sources],
456
+ ...g.condition ? { condition: g.condition } : {}
457
+ });
458
+ continue;
459
+ }
460
+ if (ORIGIN_RANK.grant > ORIGIN_RANK[existing.origin]) existing.origin = "grant";
461
+ const sources = (_a = existing.sources) != null ? _a : existing.sources = [];
462
+ for (const src of g.sources) if (!sources.includes(src)) sources.push(src);
463
+ if (!existing.condition && g.condition) existing.condition = g.condition;
331
464
  }
332
- return out;
465
+ return [...byValue.values()];
466
+ }
467
+ function suppress(resolved, bucket, entries) {
468
+ var _a, _b, _c, _d, _e;
469
+ const suppressed = new Set(
470
+ ((_e = (_d = (_c = (_b = (_a = resolved.definition) == null ? void 0 : _a.overrides) == null ? void 0 : _b.defenses) == null ? void 0 : _c[bucket]) == null ? void 0 : _d.remove) != null ? _e : []).map(toDefenseSlug)
471
+ );
472
+ return entries.filter((e) => !suppressed.has(e.value));
333
473
  }
334
474
  function computeProficiencies(resolved) {
335
475
  var _a, _b, _c, _d, _e, _f, _g;
@@ -340,31 +480,31 @@ function computeProficiencies(resolved) {
340
480
  for (const c of resolved.classes) {
341
481
  const p = (_a = c.entity) == null ? void 0 : _a.proficiencies;
342
482
  if (!p) continue;
343
- mergeInto(armor, normalizeProfList(p.armor));
344
- mergeInto(weapons, normalizeProfList(p.weapons));
345
- mergeInto(tools, normalizeProfList(p.tools));
483
+ mergeInto(armor, normalizeArmorProf(p.armor));
484
+ mergeInto(weapons, normalizeWeaponToolProf(p.weapons));
485
+ mergeInto(tools, normalizeWeaponToolProf(p.tools));
346
486
  (_b = p.languages) == null ? void 0 : _b.forEach((l) => languages.add(l));
347
487
  }
348
488
  const racePr = (_c = resolved.race) == null ? void 0 : _c.proficiencies;
349
489
  if (racePr) {
350
- mergeInto(armor, normalizeProfList(racePr.armor));
351
- mergeInto(weapons, normalizeProfList(racePr.weapons));
352
- mergeInto(tools, normalizeProfList(racePr.tools));
490
+ mergeInto(armor, normalizeArmorProf(racePr.armor));
491
+ mergeInto(weapons, normalizeWeaponToolProf(racePr.weapons));
492
+ mergeInto(tools, normalizeWeaponToolProf(racePr.tools));
353
493
  (_d = racePr.languages) == null ? void 0 : _d.forEach((l) => languages.add(l));
354
494
  }
355
495
  const bgPr = (_e = resolved.background) == null ? void 0 : _e.proficiencies;
356
496
  if (bgPr) {
357
- mergeInto(armor, normalizeProfList(bgPr.armor));
358
- mergeInto(weapons, normalizeProfList(bgPr.weapons));
359
- mergeInto(tools, normalizeProfList(bgPr.tools));
497
+ mergeInto(armor, normalizeArmorProf(bgPr.armor));
498
+ mergeInto(weapons, normalizeWeaponToolProf(bgPr.weapons));
499
+ mergeInto(tools, normalizeWeaponToolProf(bgPr.tools));
360
500
  (_f = bgPr.languages) == null ? void 0 : _f.forEach((l) => languages.add(l));
361
501
  }
362
502
  for (const f of resolved.feats) {
363
503
  const grants = f.grants_proficiency;
364
504
  if (!grants) continue;
365
- mergeInto(armor, normalizeProfList(grants.armor));
366
- mergeInto(weapons, normalizeProfList(grants.weapons));
367
- mergeInto(tools, normalizeProfList(grants.tools));
505
+ mergeInto(armor, normalizeArmorProf(grants.armor));
506
+ mergeInto(weapons, normalizeWeaponToolProf(grants.weapons));
507
+ mergeInto(tools, normalizeWeaponToolProf(grants.tools));
368
508
  (_g = grants.languages) == null ? void 0 : _g.forEach((l) => languages.add(l));
369
509
  }
370
510
  return {
@@ -376,28 +516,12 @@ function computeProficiencies(resolved) {
376
516
  };
377
517
  }
378
518
  function recalc(resolved, registry) {
379
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa;
519
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V;
380
520
  const warnings = [];
381
521
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
382
522
  const chosenProfs = collectChosenProficiencies(resolved);
383
- const activeBuffs = new Set((_b = resolved.state.active_buffs) != null ? _b : []);
384
- const buffFeatures = [];
385
- const pushBoon = (item, pool) => {
386
- var _a2, _b2, _c2, _d2, _e2, _f2;
387
- const e = item.entity;
388
- if (!e || ((_b2 = (_a2 = e.effects) == null ? void 0 : _a2.length) != null ? _b2 : 0) === 0) return;
389
- buffFeatures.push({
390
- feature: { id: item.slug, name: e.name, activatable: (_c2 = e.activatable) != null ? _c2 : false, effects: e.effects },
391
- // source is inert for the fold; attribute to the pool's owning class
392
- // (never a hardcoded class) so the generic engine carries no homebrew name.
393
- source: { kind: "class", slug: (_f2 = (_e2 = (_d2 = resolved.classes[pool.classIndex]) == null ? void 0 : _d2.entity) == null ? void 0 : _e2.slug) != null ? _f2 : pool.id, level: pool.anchorLevel }
394
- });
395
- };
396
- for (const pool of (_c = resolved.pools) != null ? _c : []) {
397
- for (const sel of (_d = pool.selected) != null ? _d : []) pushBoon(sel, pool);
398
- for (const g of (_e = pool.grants) != null ? _e : []) pushBoon(g, pool);
399
- }
400
- const featureEffects = computeFeatureEffects([...resolved.features, ...buffFeatures], { activeBuffs });
523
+ const { features: effectFeatures, activeBuffs } = assembleEffectFeatures(resolved);
524
+ const featureEffects = computeFeatureEffects(effectFeatures, { activeBuffs, levelFor: (src) => resourceLevelFor(src, resolved) });
401
525
  const profsForApply = computeProficiencies(resolved);
402
526
  for (const t of chosenProfs.tools) {
403
527
  if (!profsForApply.tools.specific.includes(t)) profsForApply.tools.specific.push(t);
@@ -405,6 +529,9 @@ function recalc(resolved, registry) {
405
529
  for (const l of chosenProfs.languages) {
406
530
  if (!profsForApply.languages.includes(l)) profsForApply.languages.push(l);
407
531
  }
532
+ for (const w of chosenProfs.weapons) {
533
+ if (!profsForApply.weapons.specific.includes(w)) profsForApply.weapons.specific.push(w);
534
+ }
408
535
  for (const t of featureEffects.proficiencies.tools) {
409
536
  if (!profsForApply.tools.specific.includes(t)) profsForApply.tools.specific.push(t);
410
537
  }
@@ -416,6 +543,9 @@ function recalc(resolved, registry) {
416
543
  }
417
544
  for (const w of featureEffects.proficiencies.weapons) {
418
545
  if (!profsForApply.weapons.categories.includes(w)) profsForApply.weapons.categories.push(w);
546
+ if (!WEAPON_CATEGORY_WORDS.has(w) && !profsForApply.weapons.specific.includes(w)) {
547
+ profsForApply.weapons.specific.push(w);
548
+ }
419
549
  }
420
550
  profsForApply.languages.sort();
421
551
  const applied = registry ? computeAppliedBonuses(resolved, profsForApply, registry, warnings) : emptyAppliedBonuses();
@@ -432,7 +562,7 @@ function recalc(resolved, registry) {
432
562
  const scores = { ...baseScores };
433
563
  for (const ab of ABILITY_KEYS) {
434
564
  const bonus = applied.ability_bonuses[ab];
435
- if (typeof bonus === "number") scores[ab] += bonus;
565
+ scores[ab] += (typeof bonus === "number" ? bonus : 0) + ((_b = featureEffects.ability_bonus[ab]) != null ? _b : 0);
436
566
  }
437
567
  for (const ab of ABILITY_KEYS) {
438
568
  const stat = applied.ability_statics[ab];
@@ -459,31 +589,32 @@ function recalc(resolved, registry) {
459
589
  resolved.definition.edition,
460
590
  scores
461
591
  );
462
- const firstClass = (_g = (_f = resolved.classes[0]) == null ? void 0 : _f.entity) != null ? _g : null;
463
- const saveProfs = new Set((_h = firstClass == null ? void 0 : firstClass.saving_throws) != null ? _h : []);
592
+ const firstClass = (_d = (_c = resolved.classes[0]) == null ? void 0 : _c.entity) != null ? _d : null;
593
+ const saveProfs = new Set((_e = firstClass == null ? void 0 : firstClass.saving_throws) != null ? _e : []);
464
594
  for (const ab of featureEffects.proficiencies.saves) saveProfs.add(ab);
595
+ for (const ab of chosenProfs.saves) saveProfs.add(ab);
465
596
  const saves = {};
466
597
  for (const ab of ABILITY_KEYS) {
467
- const override = (_i = overrides.saves) == null ? void 0 : _i[ab];
468
- const prof = (_j = override == null ? void 0 : override.proficient) != null ? _j : saveProfs.has(ab);
598
+ const override = (_f = overrides.saves) == null ? void 0 : _f[ab];
599
+ const prof = (_g = override == null ? void 0 : override.proficient) != null ? _g : saveProfs.has(ab);
469
600
  const derivedBonus = savingThrow(scores[ab], prof, proficiencyBonus) + applied.save_bonus + conditionEffects.d20_test_penalty;
470
- const bonus = (_k = override == null ? void 0 : override.bonus) != null ? _k : derivedBonus;
601
+ const bonus = (_h = override == null ? void 0 : override.bonus) != null ? _h : derivedBonus;
471
602
  saves[ab] = { bonus, proficient: prof };
472
603
  }
473
604
  const profSet = /* @__PURE__ */ new Set([
474
605
  ...resolved.definition.skills.proficient,
475
- ...(_m = (_l = resolved.background) == null ? void 0 : _l.skill_proficiencies) != null ? _m : [],
606
+ ...(_j = (_i = resolved.background) == null ? void 0 : _i.skill_proficiencies) != null ? _j : [],
476
607
  ...chosenProfs.skills,
477
608
  ...featureEffects.proficiencies.skills
478
609
  ]);
479
- const expSet = /* @__PURE__ */ new Set([...resolved.definition.skills.expertise, ...chosenProfs.expertise]);
610
+ const expSet = /* @__PURE__ */ new Set([...resolved.definition.skills.expertise, ...chosenProfs.expertise, ...featureEffects.proficiencies.skillExpertise]);
480
611
  const skills = {};
481
612
  for (const skill of ALL_SKILLS) {
482
613
  const skillKey = skillSlugFromDisplay(skill);
483
614
  const ab = SKILL_ABILITY[skillSlugToAbilityLookup(skillKey)];
484
- const override = (_n = overrides.skills) == null ? void 0 : _n[skillKey];
485
- const tri = (_o = override == null ? void 0 : override.proficiency) != null ? _o : expSet.has(skillKey) ? "expertise" : profSet.has(skillKey) ? "proficient" : "none";
486
- const bonus = (_p = override == null ? void 0 : override.bonus) != null ? _p : skillBonus(scores[ab], tri, proficiencyBonus) + conditionEffects.d20_test_penalty;
615
+ const override = (_k = overrides.skills) == null ? void 0 : _k[skillKey];
616
+ const tri = (_l = override == null ? void 0 : override.proficiency) != null ? _l : expSet.has(skillKey) ? "expertise" : profSet.has(skillKey) ? "proficient" : "none";
617
+ const bonus = (_m = override == null ? void 0 : override.bonus) != null ? _m : skillBonus(scores[ab], tri, proficiencyBonus) + conditionEffects.d20_test_penalty;
487
618
  skills[skillKey] = {
488
619
  bonus,
489
620
  proficiency: tri,
@@ -494,12 +625,12 @@ function recalc(resolved, registry) {
494
625
  const investigationTri = skills.investigation.proficiency;
495
626
  const insightTri = skills.insight.proficiency;
496
627
  const passives = {
497
- perception: (_r = (_q = overrides.passives) == null ? void 0 : _q.perception) != null ? _r : passivePerception(scores.wis, perceptionTri, proficiencyBonus),
498
- investigation: (_t = (_s = overrides.passives) == null ? void 0 : _s.investigation) != null ? _t : passive(scores.int, investigationTri, proficiencyBonus),
499
- insight: (_v = (_u = overrides.passives) == null ? void 0 : _u.insight) != null ? _v : passive(scores.wis, insightTri, proficiencyBonus)
628
+ perception: (_o = (_n = overrides.passives) == null ? void 0 : _n.perception) != null ? _o : passivePerception(scores.wis, perceptionTri, proficiencyBonus),
629
+ investigation: (_q = (_p = overrides.passives) == null ? void 0 : _p.investigation) != null ? _q : passive(scores.int, investigationTri, proficiencyBonus),
630
+ insight: (_s = (_r = overrides.passives) == null ? void 0 : _r.insight) != null ? _s : passive(scores.wis, insightTri, proficiencyBonus)
500
631
  };
501
- const hpRolled = (_x = (_w = overrides.hp) == null ? void 0 : _w.rolled) != null ? _x : null;
502
- const hpModifier = (_z = (_y = overrides.hp) == null ? void 0 : _y.modifier) != null ? _z : null;
632
+ const hpRolled = (_u = (_t = overrides.hp) == null ? void 0 : _t.rolled) != null ? _u : null;
633
+ const hpModifier = (_w = (_v = overrides.hp) == null ? void 0 : _v.modifier) != null ? _w : null;
503
634
  const averageDiceSum = hitDiceAverageSum(resolved.classes);
504
635
  const conLevels = hpLevelCount(resolved.classes);
505
636
  const diceSum = hpRolled != null ? hpRolled : averageDiceSum;
@@ -507,7 +638,7 @@ function recalc(resolved, registry) {
507
638
  const diceConClamped = Math.max(1, diceConRaw);
508
639
  const hpMaxDerived = diceConClamped + featureEffects.hp_per_level_bonus * totalLevel + (hpModifier != null ? hpModifier : 0);
509
640
  const hpMaxAfterConditions = Math.max(0, Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier));
510
- const hpMax = (_B = (_A = overrides.hp) == null ? void 0 : _A.max) != null ? _B : hpMaxAfterConditions;
641
+ const hpMax = (_y = (_x = overrides.hp) == null ? void 0 : _x.max) != null ? _y : hpMaxAfterConditions;
511
642
  const hpBreakdown = {
512
643
  diceSum,
513
644
  diceSource: hpRolled != null ? "rolled" : "average",
@@ -525,23 +656,20 @@ function recalc(resolved, registry) {
525
656
  exhaustionMultiplier: conditionEffects.hp_max_multiplier,
526
657
  exhaustionLevel: conditionEffects.exhaustion_level,
527
658
  derivedMax: hpMaxAfterConditions,
528
- override: (_D = (_C = overrides.hp) == null ? void 0 : _C.max) != null ? _D : null,
659
+ override: (_A = (_z = overrides.hp) == null ? void 0 : _z.max) != null ? _A : null,
529
660
  final: hpMax
530
661
  };
531
- const featureAcTermsFor = (hasArmor) => featureEffects.ac_terms.filter((t) => !t.requires_armor || hasArmor).map((t) => ({ source: t.label, amount: t.value, kind: "feature" }));
662
+ const featureAcTermsFor = (hasArmor) => featureEffects.ac_terms.filter((t) => !t.requires_armor || hasArmor).map((t) => ({ source: t.label, amount: t.value, kind: "feature", condition: t.condition }));
532
663
  const sumTerms = (terms) => terms.reduce((s, t) => s + t.amount, 0);
533
664
  const weaponAbilities = [...featureEffects.weaponAbilities];
534
- const wantsSpellcasting = resolved.features.some((rf) => {
535
- var _a2;
536
- return ((_a2 = rf.feature.effects) != null ? _a2 : []).some((e) => e.kind === "weapon-ability" && e.ability === "spellcasting");
537
- });
665
+ const wantsSpellcasting = resolved.features.some((rf) => selfEffectsOf(rf.feature).some((e) => e.kind === "weapon-ability" && e.ability === "spellcasting"));
538
666
  if (wantsSpellcasting) {
539
667
  let primaryCasterAbility = null;
540
668
  for (const c of resolved.classes) {
541
669
  if (!c.entity) continue;
542
670
  const profile = resolveSpellcasting(c);
543
671
  if (profile) {
544
- primaryCasterAbility = profile.ability;
672
+ primaryCasterAbility = effectiveSpellcastingAbility(c.entity.slug, profile.ability, overrides);
545
673
  break;
546
674
  }
547
675
  }
@@ -552,16 +680,17 @@ function recalc(resolved, registry) {
552
680
  let acBreakdownDerived = [];
553
681
  let acInformationalDerived = [];
554
682
  if (registry) {
555
- derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_E = resolved.weaponMasteries) != null ? _E : []);
683
+ derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_B = resolved.weaponMasteries) != null ? _B : []);
556
684
  if (derivedEquipment.equippedSlots.armor) {
557
685
  const featTerms = featureAcTermsFor(true);
558
686
  acDerived = derivedEquipment.ac + sumTerms(featTerms);
559
687
  acBreakdownDerived = [...derivedEquipment.acBreakdown, ...featTerms];
560
688
  acInformationalDerived = derivedEquipment.acInformational;
561
689
  } else {
562
- const { total: unarmored, terms: unarmoredTerms } = unarmoredACBreakdown(resolved, mods, warnings);
690
+ const shieldBonus = derivedEquipment.acBreakdown.filter((b) => b.kind === "shield").reduce((sum, b) => sum + b.amount, 0);
691
+ const { total: unarmored, terms: unarmoredTerms, shieldAllowed } = unarmoredACBreakdown(resolved, mods, warnings, shieldBonus);
563
692
  const additive = derivedEquipment.acBreakdown.filter(
564
- (b) => b.kind === "item" || b.kind === "override" || b.kind === "shield"
693
+ (b) => b.kind === "item" || b.kind === "override" || b.kind === "shield" && shieldAllowed
565
694
  );
566
695
  const featTerms = featureAcTermsFor(false);
567
696
  const additiveSum = additive.reduce((sum, b) => sum + b.amount, 0);
@@ -575,16 +704,16 @@ function recalc(resolved, registry) {
575
704
  acDerived = total + sumTerms(featTerms);
576
705
  acBreakdownDerived = [...terms, ...featTerms];
577
706
  }
578
- const ac = (_F = overrides.ac) != null ? _F : acDerived;
707
+ const ac = (_C = overrides.ac) != null ? _C : acDerived;
579
708
  const additiveSpeed = speedFromRace(resolved) + applied.speed_bonuses.walk + featureEffects.speed_walk_bonus;
580
709
  const baseSpeed = Math.max(featureEffects.speed_walk_set, additiveSpeed);
581
710
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
582
711
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
583
- const speed = (_G = overrides.speed) != null ? _G : conditionSpeed;
712
+ const speed = (_D = overrides.speed) != null ? _D : conditionSpeed;
584
713
  if (!resolved.race) warnings.push("No race resolved; speed defaulted to 30.");
585
- const init = (_H = overrides.initiative) != null ? _H : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
714
+ const init = (_E = overrides.initiative) != null ? _E : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
586
715
  const senses = {
587
- darkvision: Math.max((_K = (_J = (_I = resolved.race) == null ? void 0 : _I.vision) == null ? void 0 : _J.darkvision) != null ? _K : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
716
+ darkvision: Math.max((_H = (_G = (_F = resolved.race) == null ? void 0 : _F.vision) == null ? void 0 : _G.darkvision) != null ? _H : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
588
717
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
589
718
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
590
719
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -596,19 +725,22 @@ function recalc(resolved, registry) {
596
725
  if (!c.entity) continue;
597
726
  const profile = resolveSpellcasting(c);
598
727
  if (!profile) continue;
599
- const dc = saveDC(scores[profile.ability], proficiencyBonus) + applied.spell_save_dc;
600
- const atk = attackBonus(scores[profile.ability], proficiencyBonus) + applied.spell_attack;
728
+ const ab = effectiveSpellcastingAbility(c.entity.slug, profile.ability, overrides);
729
+ const dc = saveDC(scores[ab], proficiencyBonus) + applied.spell_save_dc;
730
+ const atk = attackBonus(scores[ab], proficiencyBonus) + applied.spell_attack;
601
731
  spellcastingClasses.push({
602
732
  classSlug: c.entity.slug,
603
733
  className: c.entity.name,
604
- ability: profile.ability,
605
- saveDC: (_M = (_L = overrides.spellcasting) == null ? void 0 : _L.saveDC) != null ? _M : dc,
606
- attackBonus: (_O = (_N = overrides.spellcasting) == null ? void 0 : _N.attackBonus) != null ? _O : atk,
734
+ ability: ab,
735
+ defaultAbility: profile.ability,
736
+ saveDC: dc,
737
+ attackBonus: atk,
607
738
  casterType: profile.casterType,
608
- preparation: profile.preparation
739
+ preparation: profile.preparation,
740
+ spellList: profile.spellList
609
741
  });
610
742
  slotInputs.push({ casterType: profile.casterType, level: c.level });
611
- limitInputs.push({ classSlug: c.entity.slug, level: c.level, profile, abilityScore: scores[profile.ability] });
743
+ limitInputs.push({ classSlug: c.entity.slug, level: c.level, profile, abilityScore: scores[ab] });
612
744
  }
613
745
  const spellcasting = spellcastingClasses.length > 0 ? {
614
746
  ability: spellcastingClasses[0].ability,
@@ -627,24 +759,39 @@ function recalc(resolved, registry) {
627
759
  const derivedSlots = deriveSpellSlots(slotInputs);
628
760
  const spellLimits = computeSpellLimits(limitInputs);
629
761
  const defenses = {
630
- resistances: dedupeDefenseList([
631
- (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.resistances) != null ? _Q : [],
762
+ resistances: suppress(resolved, "resistances", composeDefenseEntries(
763
+ (_J = (_I = resolved.definition.defenses) == null ? void 0 : _I.resistances) != null ? _J : [],
632
764
  applied.defenses.resistances,
633
765
  featureEffects.resistances
634
- ]),
635
- immunities: dedupeDefenseList([
636
- (_S = (_R = resolved.definition.defenses) == null ? void 0 : _R.immunities) != null ? _S : [],
637
- applied.defenses.immunities
638
- ]),
639
- vulnerabilities: dedupeDefenseList([
640
- (_U = (_T = resolved.definition.defenses) == null ? void 0 : _T.vulnerabilities) != null ? _U : [],
641
- applied.defenses.vulnerabilities
642
- ]),
643
- condition_immunities: dedupeDefenseList([
644
- (_W = (_V = resolved.definition.defenses) == null ? void 0 : _V.condition_immunities) != null ? _W : [],
766
+ )),
767
+ immunities: suppress(resolved, "immunities", composeDefenseEntries(
768
+ (_L = (_K = resolved.definition.defenses) == null ? void 0 : _K.immunities) != null ? _L : [],
769
+ applied.defenses.immunities,
770
+ featureEffects.immunities
771
+ )),
772
+ vulnerabilities: suppress(resolved, "vulnerabilities", composeDefenseEntries(
773
+ (_N = (_M = resolved.definition.defenses) == null ? void 0 : _M.vulnerabilities) != null ? _N : [],
774
+ applied.defenses.vulnerabilities,
775
+ featureEffects.vulnerabilities
776
+ )),
777
+ condition_immunities: suppress(resolved, "condition_immunities", composeDefenseEntries(
778
+ (_P = (_O = resolved.definition.defenses) == null ? void 0 : _O.condition_immunities) != null ? _P : [],
645
779
  applied.defenses.condition_immunities,
646
780
  featureEffects.condition_immunities
647
- ])
781
+ ))
782
+ };
783
+ const attackRows = [...(_Q = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _Q : [], buildUnarmedRow(mods, proficiencyBonus, resolveUnarmedStrike(resolved))];
784
+ const riderBindings = {
785
+ level: totalLevel,
786
+ class_level: totalLevel,
787
+ prof: proficiencyBonus,
788
+ str_mod: mods.str,
789
+ dex_mod: mods.dex,
790
+ con_mod: mods.con,
791
+ int_mod: mods.int,
792
+ wis_mod: mods.wis,
793
+ cha_mod: mods.cha,
794
+ columns: {}
648
795
  };
649
796
  return {
650
797
  totalLevel,
@@ -685,9 +832,9 @@ function recalc(resolved, registry) {
685
832
  // untouched rows keep `critRange`/`attackNotes` ABSENT (not 20 / not []).
686
833
  // crit-range: folded weapon crit threshold, only when an effect lowered it.
687
834
  // attackNotes: reroll-damage / attack-rule captions, only when non-empty.
688
- attacks: ((_X = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _X : []).map((a) => {
835
+ attacks: attackRows.map((a) => {
689
836
  var _a2;
690
- const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses];
837
+ const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses].map((r) => resolveDamageRider(r, a.damageType, riderBindings));
691
838
  return {
692
839
  ...a,
693
840
  toHit: a.toHit + conditionEffects.d20_test_penalty,
@@ -696,12 +843,13 @@ function recalc(resolved, registry) {
696
843
  ...riders.length ? { damageRiders: riders } : {}
697
844
  };
698
845
  }),
699
- equippedSlots: (_Y = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _Y : {},
700
- carriedWeight: (_Z = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _Z : 0,
701
- attunementUsed: (__ = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? __ : 0,
702
- attunementLimit: (_aa = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _aa : (_$ = overrides.attunement_limit) != null ? _$ : 3,
846
+ equippedSlots: (_R = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _R : {},
847
+ carriedWeight: (_S = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _S : 0,
848
+ attunementUsed: (_T = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _T : 0,
849
+ attunementLimit: (_V = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _V : (_U = overrides.attunement_limit) != null ? _U : 3,
703
850
  conditionEffects,
704
- rollModifiers: featureEffects.rollModifiers
851
+ rollModifiers: featureEffects.rollModifiers,
852
+ saveOutcomes: featureEffects.saveOutcomes
705
853
  };
706
854
  }
707
855
  export {
@@ -718,6 +866,7 @@ export {
718
866
  parseDieSize,
719
867
  phbAverageForDie,
720
868
  recalc,
869
+ resolveUnarmedStrike,
721
870
  speedFromRace,
722
871
  unarmoredAC,
723
872
  unarmoredACBreakdown