@archivist-gg/dnd5e 0.3.1 → 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 (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-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-6IRYTM5V.js → chunk-DPUJDOKV.js} +119 -28
  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-BIK4DFWK.js → chunk-HJ5EEZ47.js} +1 -1
  39. package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
  40. package/dist/{chunk-TN6ZLTNU.js → chunk-I2NDWFDD.js} +51 -4
  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-SE7AZDR3.js → chunk-JRDPUDT5.js} +29 -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-5ZBE4CWV.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-D3CLOBE3.js → chunk-OSQFPGLM.js} +44 -8
  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 +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 +176 -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 +30 -1
  153. package/dist/pc/pc.equipment.js +12 -8
  154. package/dist/pc/pc.feature-effects.d.ts +225 -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 +124 -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 +78 -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
@@ -4,49 +4,88 @@ import {
4
4
  import {
5
5
  collectChosenAbilityPoints,
6
6
  collectChosenProficiencies
7
- } from "../chunk-TNUFPIXI.js";
8
- import "../chunk-7TEK5KK7.js";
7
+ } from "../chunk-XQCSGNXE.js";
8
+ import {
9
+ resourceLevelFor
10
+ } from "../chunk-UXPGW4TI.js";
9
11
  import {
10
12
  computeSpellLimits,
11
13
  deriveSpellSlots,
12
14
  effectiveSpellcastingAbility,
13
15
  resolveSpellcasting
14
- } from "../chunk-6IRYTM5V.js";
15
- import "../chunk-5XUXXAQJ.js";
16
- 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";
17
29
  import {
30
+ buildUnarmedRow,
18
31
  computeAppliedBonuses,
19
32
  computeSlotsAndAttacks,
20
33
  emptyAppliedBonuses
21
- } from "../chunk-D3CLOBE3.js";
22
- import "../chunk-353WXS6S.js";
23
- import "../chunk-O5EYMKFH.js";
24
- import "../chunk-N6N74K6X.js";
34
+ } from "../chunk-OSQFPGLM.js";
35
+ import "../chunk-UIRMA5KM.js";
36
+ import "../chunk-UBBKSYBY.js";
25
37
  import {
26
- computeFeatureEffects
27
- } 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";
28
46
  import "../chunk-LWFTHJIE.js";
29
47
  import "../chunk-DNAJRMNN.js";
30
- import "../chunk-4LZJXJJS.js";
31
- 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";
32
56
  import "../chunk-VTTA2ALZ.js";
57
+ import "../chunk-OZP6JFGT.js";
58
+ import "../chunk-VQAXTIBW.js";
33
59
  import {
34
60
  abilityModifier,
35
61
  attackBonus,
62
+ isCanonicalDamageType,
63
+ isChosenDamageType,
36
64
  passive,
37
65
  passivePerception,
38
66
  proficiencyFromLevel,
39
67
  saveDC,
40
68
  savingThrow,
41
69
  skillBonus
42
- } from "../chunk-NAEPSZAM.js";
70
+ } from "../chunk-PDJSUH24.js";
43
71
  import {
44
72
  ABILITY_KEYS,
45
73
  ALL_SKILLS,
46
74
  SKILL_ABILITY
47
- } from "../chunk-WP2CX2JO.js";
75
+ } from "../chunk-WELIKLZF.js";
76
+ import "../chunk-4U55VNC7.js";
77
+ import "../chunk-UA5KS2PL.js";
48
78
 
49
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
+ ]);
50
89
  function phbAverageForDie(hitDieStr) {
51
90
  const n = parseDieSize(hitDieStr);
52
91
  if (n == null) return 4;
@@ -88,7 +127,9 @@ function collectClassAsiBranch(resolved) {
88
127
  const out = {};
89
128
  for (const c of resolved.classes) {
90
129
  for (const [, choice] of Object.entries(c.choices)) {
91
- 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;
92
133
  if (!asi) continue;
93
134
  for (const ab of ABILITY_KEYS) {
94
135
  const v = asi[ab];
@@ -98,8 +139,8 @@ function collectClassAsiBranch(resolved) {
98
139
  }
99
140
  return out;
100
141
  }
101
- function abilityBonusBreakdown(resolved) {
102
- var _a, _b, _c, _d, _e, _f;
142
+ function abilityBonusBreakdown(resolved, featureEffects) {
143
+ var _a, _b, _c, _d, _e, _f, _g;
103
144
  const race = flattenRaceAsi(resolved.race);
104
145
  const origin = collectChosenAbilityPoints(resolved);
105
146
  const sub = subraceAsi(resolved);
@@ -116,7 +157,7 @@ function abilityBonusBreakdown(resolved) {
116
157
  const bonus = (_d = f.ability_bonuses) == null ? void 0 : _d[ab];
117
158
  if (typeof bonus === "number") feat += bonus;
118
159
  }
119
- 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 };
120
161
  }
121
162
  return out;
122
163
  }
@@ -151,65 +192,123 @@ function hpLevelCount(classes) {
151
192
  function multiclassMaxHP(classes, conMod) {
152
193
  return Math.max(1, hitDiceAverageSum(classes) + conMod * hpLevelCount(classes));
153
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
+ }
154
210
  function unarmoredAC(resolved, mods, warnings) {
155
211
  return unarmoredACBreakdown(resolved, mods, warnings).total;
156
212
  }
157
- function unarmoredACBreakdown(resolved, mods, warnings) {
158
- var _a, _b, _c, _d, _e, _f;
213
+ function unarmoredACBreakdown(resolved, mods, warnings, shieldBonus = 0) {
214
+ var _a, _b, _c, _d, _e;
159
215
  const baseTerms = [
160
216
  { source: "Unarmored", amount: 10, kind: "unarmored" },
161
217
  { source: "DEX modifier", amount: mods.dex, kind: "dex" }
162
218
  ];
219
+ const { activeBuffs } = assembleEffectFeatures(resolved);
220
+ const candidates = [
221
+ { total: 10 + mods.dex, terms: baseTerms, shieldAllowed: true }
222
+ ];
163
223
  for (const rf of resolved.features) {
164
- const eff = ((_a = rf.feature.effects) != null ? _a : []).find((e) => e.kind === "unarmored-ac");
165
- if (eff && eff.kind === "unarmored-ac") {
166
- const base = (_b = eff.base) != null ? _b : 10;
167
- const terms = [
168
- { source: "Unarmored", amount: base, kind: "unarmored" },
169
- { source: "DEX modifier", amount: mods.dex, kind: "dex" }
170
- ];
171
- 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;
172
230
  for (const ab of eff.abilities) {
173
- if (ab === "dex") continue;
174
- 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" });
175
232
  total += mods[ab];
176
233
  }
177
- return { total, terms };
234
+ candidates.push({ total, terms, shieldAllowed: eff.allow_shield === true });
178
235
  }
179
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
+ }
180
243
  for (const rf of resolved.features) {
181
244
  const feat = rf.feature;
182
- if ((_d = feat.unarmored_defense) == null ? void 0 : _d.ability) {
245
+ if ((_c = feat.unarmored_defense) == null ? void 0 : _c.ability) {
183
246
  const ab = feat.unarmored_defense.ability;
184
- const amt = (_e = mods[ab]) != null ? _e : 0;
247
+ const amt = (_d = mods[ab]) != null ? _d : 0;
185
248
  const terms = [
186
249
  ...baseTerms,
187
250
  { source: `${ab.toUpperCase()} modifier (Unarmored Defense)`, amount: amt, kind: "ability" }
188
251
  ];
189
- return { total: 10 + mods.dex + amt, terms };
252
+ return { total: 10 + mods.dex + amt, terms, shieldAllowed: true };
190
253
  }
191
254
  }
192
255
  for (const rf of resolved.features) {
193
- const name = ((_f = rf.feature.name) != null ? _f : "").toLowerCase();
256
+ const name = ((_e = rf.feature.name) != null ? _e : "").toLowerCase();
194
257
  if (!/unarmored\s*defense/.test(name)) continue;
195
258
  if (rf.source.kind === "class" && rf.source.slug.includes("monk")) {
196
- warnings.push(`Unarmored Defense detected by name on ${rf.source.slug}; populate unarmored_defense:{ability:wis} flag for accuracy.`);
197
259
  const terms = [
198
260
  ...baseTerms,
199
261
  { source: "WIS modifier (Unarmored Defense)", amount: mods.wis, kind: "ability" }
200
262
  ];
201
- return { total: 10 + mods.dex + mods.wis, terms };
263
+ return { total: 10 + mods.dex + mods.wis, terms, shieldAllowed: true };
202
264
  }
203
265
  if (rf.source.kind === "class" && rf.source.slug.includes("barbarian")) {
204
- warnings.push(`Unarmored Defense detected by name on ${rf.source.slug}; populate unarmored_defense:{ability:con} flag for accuracy.`);
205
266
  const terms = [
206
267
  ...baseTerms,
207
268
  { source: "CON modifier (Unarmored Defense)", amount: mods.con, kind: "ability" }
208
269
  ];
209
- return { total: 10 + mods.dex + mods.con, terms };
270
+ return { total: 10 + mods.dex + mods.con, terms, shieldAllowed: true };
210
271
  }
211
272
  }
212
- 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] } : {} };
213
312
  }
214
313
  function initiativeBonus(dexMod, feats, edition) {
215
314
  let bonus = dexMod;
@@ -326,18 +425,51 @@ function mergeInto(target, source) {
326
425
  for (const c of source.categories) if (!target.categories.includes(c)) target.categories.push(c);
327
426
  for (const s of source.specific) if (!target.specific.includes(s)) target.specific.push(s);
328
427
  }
329
- function dedupeDefenseList(lists) {
330
- const seen = /* @__PURE__ */ new Set();
331
- const out = [];
332
- for (const list of lists) {
333
- for (const v of list) {
334
- const key = v.trim().toLowerCase();
335
- if (!key || seen.has(key)) continue;
336
- seen.add(key);
337
- 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;
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;
338
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;
339
464
  }
340
- 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));
341
473
  }
342
474
  function computeProficiencies(resolved) {
343
475
  var _a, _b, _c, _d, _e, _f, _g;
@@ -384,28 +516,12 @@ function computeProficiencies(resolved) {
384
516
  };
385
517
  }
386
518
  function recalc(resolved, registry) {
387
- 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;
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;
388
520
  const warnings = [];
389
521
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
390
522
  const chosenProfs = collectChosenProficiencies(resolved);
391
- const activeBuffs = new Set((_b = resolved.state.active_buffs) != null ? _b : []);
392
- const buffFeatures = [];
393
- const pushBoon = (item, pool) => {
394
- var _a2, _b2, _c2, _d2, _e2, _f2;
395
- const e = item.entity;
396
- if (!e || ((_b2 = (_a2 = e.effects) == null ? void 0 : _a2.length) != null ? _b2 : 0) === 0) return;
397
- buffFeatures.push({
398
- feature: { id: item.slug, name: e.name, activatable: (_c2 = e.activatable) != null ? _c2 : false, effects: e.effects },
399
- // source is inert for the fold; attribute to the pool's owning class
400
- // (never a hardcoded class) so the generic engine carries no homebrew name.
401
- 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 }
402
- });
403
- };
404
- for (const pool of (_c = resolved.pools) != null ? _c : []) {
405
- for (const sel of (_d = pool.selected) != null ? _d : []) pushBoon(sel, pool);
406
- for (const g of (_e = pool.grants) != null ? _e : []) pushBoon(g, pool);
407
- }
408
- 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) });
409
525
  const profsForApply = computeProficiencies(resolved);
410
526
  for (const t of chosenProfs.tools) {
411
527
  if (!profsForApply.tools.specific.includes(t)) profsForApply.tools.specific.push(t);
@@ -413,6 +529,9 @@ function recalc(resolved, registry) {
413
529
  for (const l of chosenProfs.languages) {
414
530
  if (!profsForApply.languages.includes(l)) profsForApply.languages.push(l);
415
531
  }
532
+ for (const w of chosenProfs.weapons) {
533
+ if (!profsForApply.weapons.specific.includes(w)) profsForApply.weapons.specific.push(w);
534
+ }
416
535
  for (const t of featureEffects.proficiencies.tools) {
417
536
  if (!profsForApply.tools.specific.includes(t)) profsForApply.tools.specific.push(t);
418
537
  }
@@ -424,6 +543,9 @@ function recalc(resolved, registry) {
424
543
  }
425
544
  for (const w of featureEffects.proficiencies.weapons) {
426
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
+ }
427
549
  }
428
550
  profsForApply.languages.sort();
429
551
  const applied = registry ? computeAppliedBonuses(resolved, profsForApply, registry, warnings) : emptyAppliedBonuses();
@@ -440,7 +562,7 @@ function recalc(resolved, registry) {
440
562
  const scores = { ...baseScores };
441
563
  for (const ab of ABILITY_KEYS) {
442
564
  const bonus = applied.ability_bonuses[ab];
443
- if (typeof bonus === "number") scores[ab] += bonus;
565
+ scores[ab] += (typeof bonus === "number" ? bonus : 0) + ((_b = featureEffects.ability_bonus[ab]) != null ? _b : 0);
444
566
  }
445
567
  for (const ab of ABILITY_KEYS) {
446
568
  const stat = applied.ability_statics[ab];
@@ -467,31 +589,32 @@ function recalc(resolved, registry) {
467
589
  resolved.definition.edition,
468
590
  scores
469
591
  );
470
- const firstClass = (_g = (_f = resolved.classes[0]) == null ? void 0 : _f.entity) != null ? _g : null;
471
- 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 : []);
472
594
  for (const ab of featureEffects.proficiencies.saves) saveProfs.add(ab);
595
+ for (const ab of chosenProfs.saves) saveProfs.add(ab);
473
596
  const saves = {};
474
597
  for (const ab of ABILITY_KEYS) {
475
- const override = (_i = overrides.saves) == null ? void 0 : _i[ab];
476
- 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);
477
600
  const derivedBonus = savingThrow(scores[ab], prof, proficiencyBonus) + applied.save_bonus + conditionEffects.d20_test_penalty;
478
- 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;
479
602
  saves[ab] = { bonus, proficient: prof };
480
603
  }
481
604
  const profSet = /* @__PURE__ */ new Set([
482
605
  ...resolved.definition.skills.proficient,
483
- ...(_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 : [],
484
607
  ...chosenProfs.skills,
485
608
  ...featureEffects.proficiencies.skills
486
609
  ]);
487
- 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]);
488
611
  const skills = {};
489
612
  for (const skill of ALL_SKILLS) {
490
613
  const skillKey = skillSlugFromDisplay(skill);
491
614
  const ab = SKILL_ABILITY[skillSlugToAbilityLookup(skillKey)];
492
- const override = (_n = overrides.skills) == null ? void 0 : _n[skillKey];
493
- const tri = (_o = override == null ? void 0 : override.proficiency) != null ? _o : expSet.has(skillKey) ? "expertise" : profSet.has(skillKey) ? "proficient" : "none";
494
- 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;
495
618
  skills[skillKey] = {
496
619
  bonus,
497
620
  proficiency: tri,
@@ -502,12 +625,12 @@ function recalc(resolved, registry) {
502
625
  const investigationTri = skills.investigation.proficiency;
503
626
  const insightTri = skills.insight.proficiency;
504
627
  const passives = {
505
- perception: (_r = (_q = overrides.passives) == null ? void 0 : _q.perception) != null ? _r : passivePerception(scores.wis, perceptionTri, proficiencyBonus),
506
- investigation: (_t = (_s = overrides.passives) == null ? void 0 : _s.investigation) != null ? _t : passive(scores.int, investigationTri, proficiencyBonus),
507
- 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)
508
631
  };
509
- const hpRolled = (_x = (_w = overrides.hp) == null ? void 0 : _w.rolled) != null ? _x : null;
510
- 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;
511
634
  const averageDiceSum = hitDiceAverageSum(resolved.classes);
512
635
  const conLevels = hpLevelCount(resolved.classes);
513
636
  const diceSum = hpRolled != null ? hpRolled : averageDiceSum;
@@ -515,7 +638,7 @@ function recalc(resolved, registry) {
515
638
  const diceConClamped = Math.max(1, diceConRaw);
516
639
  const hpMaxDerived = diceConClamped + featureEffects.hp_per_level_bonus * totalLevel + (hpModifier != null ? hpModifier : 0);
517
640
  const hpMaxAfterConditions = Math.max(0, Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier));
518
- 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;
519
642
  const hpBreakdown = {
520
643
  diceSum,
521
644
  diceSource: hpRolled != null ? "rolled" : "average",
@@ -533,16 +656,13 @@ function recalc(resolved, registry) {
533
656
  exhaustionMultiplier: conditionEffects.hp_max_multiplier,
534
657
  exhaustionLevel: conditionEffects.exhaustion_level,
535
658
  derivedMax: hpMaxAfterConditions,
536
- 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,
537
660
  final: hpMax
538
661
  };
539
- 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 }));
540
663
  const sumTerms = (terms) => terms.reduce((s, t) => s + t.amount, 0);
541
664
  const weaponAbilities = [...featureEffects.weaponAbilities];
542
- const wantsSpellcasting = resolved.features.some((rf) => {
543
- var _a2;
544
- return ((_a2 = rf.feature.effects) != null ? _a2 : []).some((e) => e.kind === "weapon-ability" && e.ability === "spellcasting");
545
- });
665
+ const wantsSpellcasting = resolved.features.some((rf) => selfEffectsOf(rf.feature).some((e) => e.kind === "weapon-ability" && e.ability === "spellcasting"));
546
666
  if (wantsSpellcasting) {
547
667
  let primaryCasterAbility = null;
548
668
  for (const c of resolved.classes) {
@@ -560,16 +680,17 @@ function recalc(resolved, registry) {
560
680
  let acBreakdownDerived = [];
561
681
  let acInformationalDerived = [];
562
682
  if (registry) {
563
- 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 : []);
564
684
  if (derivedEquipment.equippedSlots.armor) {
565
685
  const featTerms = featureAcTermsFor(true);
566
686
  acDerived = derivedEquipment.ac + sumTerms(featTerms);
567
687
  acBreakdownDerived = [...derivedEquipment.acBreakdown, ...featTerms];
568
688
  acInformationalDerived = derivedEquipment.acInformational;
569
689
  } else {
570
- 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);
571
692
  const additive = derivedEquipment.acBreakdown.filter(
572
- (b) => b.kind === "item" || b.kind === "override" || b.kind === "shield"
693
+ (b) => b.kind === "item" || b.kind === "override" || b.kind === "shield" && shieldAllowed
573
694
  );
574
695
  const featTerms = featureAcTermsFor(false);
575
696
  const additiveSum = additive.reduce((sum, b) => sum + b.amount, 0);
@@ -583,16 +704,16 @@ function recalc(resolved, registry) {
583
704
  acDerived = total + sumTerms(featTerms);
584
705
  acBreakdownDerived = [...terms, ...featTerms];
585
706
  }
586
- const ac = (_F = overrides.ac) != null ? _F : acDerived;
707
+ const ac = (_C = overrides.ac) != null ? _C : acDerived;
587
708
  const additiveSpeed = speedFromRace(resolved) + applied.speed_bonuses.walk + featureEffects.speed_walk_bonus;
588
709
  const baseSpeed = Math.max(featureEffects.speed_walk_set, additiveSpeed);
589
710
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
590
711
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
591
- const speed = (_G = overrides.speed) != null ? _G : conditionSpeed;
712
+ const speed = (_D = overrides.speed) != null ? _D : conditionSpeed;
592
713
  if (!resolved.race) warnings.push("No race resolved; speed defaulted to 30.");
593
- 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;
594
715
  const senses = {
595
- 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),
596
717
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
597
718
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
598
719
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -615,7 +736,8 @@ function recalc(resolved, registry) {
615
736
  saveDC: dc,
616
737
  attackBonus: atk,
617
738
  casterType: profile.casterType,
618
- preparation: profile.preparation
739
+ preparation: profile.preparation,
740
+ spellList: profile.spellList
619
741
  });
620
742
  slotInputs.push({ casterType: profile.casterType, level: c.level });
621
743
  limitInputs.push({ classSlug: c.entity.slug, level: c.level, profile, abilityScore: scores[ab] });
@@ -637,24 +759,39 @@ function recalc(resolved, registry) {
637
759
  const derivedSlots = deriveSpellSlots(slotInputs);
638
760
  const spellLimits = computeSpellLimits(limitInputs);
639
761
  const defenses = {
640
- resistances: dedupeDefenseList([
641
- (_M = (_L = resolved.definition.defenses) == null ? void 0 : _L.resistances) != null ? _M : [],
762
+ resistances: suppress(resolved, "resistances", composeDefenseEntries(
763
+ (_J = (_I = resolved.definition.defenses) == null ? void 0 : _I.resistances) != null ? _J : [],
642
764
  applied.defenses.resistances,
643
765
  featureEffects.resistances
644
- ]),
645
- immunities: dedupeDefenseList([
646
- (_O = (_N = resolved.definition.defenses) == null ? void 0 : _N.immunities) != null ? _O : [],
647
- applied.defenses.immunities
648
- ]),
649
- vulnerabilities: dedupeDefenseList([
650
- (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.vulnerabilities) != null ? _Q : [],
651
- applied.defenses.vulnerabilities
652
- ]),
653
- condition_immunities: dedupeDefenseList([
654
- (_S = (_R = resolved.definition.defenses) == null ? void 0 : _R.condition_immunities) != null ? _S : [],
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 : [],
655
779
  applied.defenses.condition_immunities,
656
780
  featureEffects.condition_immunities
657
- ])
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: {}
658
795
  };
659
796
  return {
660
797
  totalLevel,
@@ -695,9 +832,9 @@ function recalc(resolved, registry) {
695
832
  // untouched rows keep `critRange`/`attackNotes` ABSENT (not 20 / not []).
696
833
  // crit-range: folded weapon crit threshold, only when an effect lowered it.
697
834
  // attackNotes: reroll-damage / attack-rule captions, only when non-empty.
698
- attacks: ((_T = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _T : []).map((a) => {
835
+ attacks: attackRows.map((a) => {
699
836
  var _a2;
700
- 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));
701
838
  return {
702
839
  ...a,
703
840
  toHit: a.toHit + conditionEffects.d20_test_penalty,
@@ -706,12 +843,13 @@ function recalc(resolved, registry) {
706
843
  ...riders.length ? { damageRiders: riders } : {}
707
844
  };
708
845
  }),
709
- equippedSlots: (_U = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _U : {},
710
- carriedWeight: (_V = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _V : 0,
711
- attunementUsed: (_W = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _W : 0,
712
- attunementLimit: (_Y = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _Y : (_X = overrides.attunement_limit) != null ? _X : 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,
713
850
  conditionEffects,
714
- rollModifiers: featureEffects.rollModifiers
851
+ rollModifiers: featureEffects.rollModifiers,
852
+ saveOutcomes: featureEffects.saveOutcomes
715
853
  };
716
854
  }
717
855
  export {
@@ -728,6 +866,7 @@ export {
728
866
  parseDieSize,
729
867
  phbAverageForDie,
730
868
  recalc,
869
+ resolveUnarmedStrike,
731
870
  speedFromRace,
732
871
  unarmoredAC,
733
872
  unarmoredACBreakdown