@archivist-gg/dnd5e 0.3.11 → 0.3.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/LICENSES/SRD.md +38 -3
  2. package/dist/armor/armor.codec.js +3 -3
  3. package/dist/armor/armor.parser.js +2 -2
  4. package/dist/armor/armor.schema.d.ts +1 -0
  5. package/dist/armor/armor.schema.js +1 -1
  6. package/dist/armor/armor.types.d.ts +2 -0
  7. package/dist/background/background.codec.js +5 -5
  8. package/dist/background/background.parser.js +4 -4
  9. package/dist/background/background.schema.js +3 -3
  10. package/dist/{chunk-XTRDCSJB.js → chunk-2JSQE3DD.js} +15 -1
  11. package/dist/chunk-2LULMQTF.js +14 -0
  12. package/dist/{chunk-MAH6DCRI.js → chunk-2UDSN6VW.js} +1 -1
  13. package/dist/chunk-3LWMFYKS.js +57 -0
  14. package/dist/{chunk-JCEV7KYN.js → chunk-3MGQFFNE.js} +1 -1
  15. package/dist/chunk-3VZZDKRA.js +1014 -0
  16. package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
  17. package/dist/{chunk-2M34FLAY.js → chunk-5MXFW4O3.js} +9 -3
  18. package/dist/{chunk-4DOMDEBZ.js → chunk-6EI737IO.js} +1 -1
  19. package/dist/{chunk-G247QXWW.js → chunk-7ATNGKBS.js} +1 -1
  20. package/dist/{chunk-XY6X2APM.js → chunk-7Q2VPKCD.js} +17 -0
  21. package/dist/{chunk-T2SNEJOE.js → chunk-7QN7XSAK.js} +1 -1
  22. package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
  23. package/dist/{chunk-7YU4NPKR.js → chunk-AZRGFUSR.js} +1 -1
  24. package/dist/{chunk-PP2UHLBA.js → chunk-B3DP42OM.js} +5 -0
  25. package/dist/chunk-CM5CWO4K.js +735 -0
  26. package/dist/{chunk-MQ747UCR.js → chunk-DOXSFYLH.js} +70 -2
  27. package/dist/chunk-EJP263OP.js +186 -0
  28. package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
  29. package/dist/{chunk-V6LJFP4R.js → chunk-FANQVQ3D.js} +2 -2
  30. package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
  31. package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
  32. package/dist/{chunk-JANNRGJC.js → chunk-G6PBI2BU.js} +1 -1
  33. package/dist/chunk-H5PTKYXL.js +101 -0
  34. package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
  35. package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
  36. package/dist/chunk-HTYMW5CH.js +228 -0
  37. package/dist/chunk-IHE6KVC3.js +13 -0
  38. package/dist/{chunk-QHMWA3SZ.js → chunk-JCMUVZIK.js} +1 -1
  39. package/dist/{chunk-V373TRJE.js → chunk-JSM6JFZR.js} +198 -125
  40. package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
  41. package/dist/chunk-KR6JF3BF.js +14 -0
  42. package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
  43. package/dist/chunk-LBEXLN6I.js +91 -0
  44. package/dist/{chunk-BLRW2UU6.js → chunk-LF5AGJA4.js} +2 -2
  45. package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
  46. package/dist/{chunk-BIA32MQ5.js → chunk-MBX25B6D.js} +1 -1
  47. package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
  48. package/dist/{chunk-J77CKYV3.js → chunk-OFCSP6MT.js} +1 -1
  49. package/dist/{chunk-2INMRR3Q.js → chunk-ONTGZR5T.js} +326 -149
  50. package/dist/{chunk-MWCCGPG3.js → chunk-OOSRUJBI.js} +3 -2
  51. package/dist/{chunk-U3BABVJF.js → chunk-PKX6TGRE.js} +2 -2
  52. package/dist/{chunk-PJMG5XV3.js → chunk-PQZ4LM4Z.js} +1 -1
  53. package/dist/chunk-PXVNAY7T.js +84 -0
  54. package/dist/chunk-QH36K2PU.js +158 -0
  55. package/dist/{chunk-R747YKS7.js → chunk-QZSWN2KT.js} +1 -1
  56. package/dist/{chunk-CHUALUIX.js → chunk-RYLXAYIQ.js} +1 -1
  57. package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
  58. package/dist/{chunk-PZCE7DJM.js → chunk-T6QIF5XR.js} +31 -1
  59. package/dist/{chunk-CBEKVAX4.js → chunk-TULQ4FFX.js} +41 -13
  60. package/dist/{chunk-S56D6B6C.js → chunk-UUBJCNQU.js} +12 -3
  61. package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
  62. package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
  63. package/dist/{chunk-3HX5VLWP.js → chunk-VRV3NNTA.js} +2 -2
  64. package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
  65. package/dist/{chunk-BL3VELKP.js → chunk-Y5VVP73C.js} +1 -1
  66. package/dist/{chunk-PI4LLJG4.js → chunk-YD2VAHA6.js} +2 -2
  67. package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
  68. package/dist/{chunk-NWDF5HG3.js → chunk-YKL6SHRJ.js} +1 -1
  69. package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
  70. package/dist/chunk-ZUQW5VBZ.js +89 -0
  71. package/dist/class/class.codec.js +7 -7
  72. package/dist/class/class.parser.js +6 -6
  73. package/dist/class/class.schema.d.ts +18 -0
  74. package/dist/class/class.schema.js +5 -5
  75. package/dist/class/class.standard-array.d.ts +16 -0
  76. package/dist/class/class.standard-array.js +20 -0
  77. package/dist/class/class.types.d.ts +3 -0
  78. package/dist/dnd/amount-text.d.ts +38 -0
  79. package/dist/dnd/amount-text.js +13 -0
  80. package/dist/dnd/resource-words.d.ts +4 -0
  81. package/dist/dnd/resource-words.js +30 -0
  82. package/dist/entities/base-item-resolver.js +2 -2
  83. package/dist/entities/slug.d.ts +18 -8
  84. package/dist/entities/slug.js +3 -1
  85. package/dist/feat/feat.codec.js +5 -5
  86. package/dist/feat/feat.parser.js +4 -4
  87. package/dist/feat/feat.schema.d.ts +41 -3
  88. package/dist/feat/feat.schema.js +3 -3
  89. package/dist/index.js +7513 -4177
  90. package/dist/item/item.actions-map.d.ts +40 -5
  91. package/dist/item/item.actions-map.js +5 -84
  92. package/dist/item/item.attunement.js +3 -9
  93. package/dist/item/item.bonuses.js +5 -2
  94. package/dist/item/item.codec.js +3 -3
  95. package/dist/item/item.conditions.js +4 -1
  96. package/dist/item/item.conditions.types.d.ts +4 -0
  97. package/dist/item/item.cost.d.ts +3 -0
  98. package/dist/item/item.cost.js +29 -0
  99. package/dist/item/item.icon.d.ts +15 -0
  100. package/dist/item/item.icon.js +211 -0
  101. package/dist/item/item.parser.js +2 -2
  102. package/dist/item/item.schema.d.ts +16 -1
  103. package/dist/item/item.schema.js +3 -1
  104. package/dist/item/item.types.d.ts +9 -2
  105. package/dist/monster/monster.parser.js +5 -5
  106. package/dist/monster/monster.schema.js +4 -4
  107. package/dist/optional-feature/optional-feature.codec.js +5 -4
  108. package/dist/optional-feature/optional-feature.parser.js +4 -3
  109. package/dist/optional-feature/optional-feature.schema.d.ts +255 -3
  110. package/dist/optional-feature/optional-feature.schema.js +7 -2
  111. package/dist/pc/pc.additional-spells.js +3 -3
  112. package/dist/pc/pc.amount-bindings.d.ts +32 -0
  113. package/dist/pc/pc.amount-bindings.js +23 -0
  114. package/dist/pc/pc.asi-flatten.d.ts +62 -1
  115. package/dist/pc/pc.asi-flatten.js +16 -0
  116. package/dist/pc/pc.conditions.js +1 -1
  117. package/dist/pc/pc.containment.d.ts +45 -0
  118. package/dist/pc/pc.containment.js +24 -0
  119. package/dist/pc/pc.decision-engine.d.ts +24 -3
  120. package/dist/pc/pc.decision-engine.js +26 -16
  121. package/dist/pc/pc.entry-overrides.d.ts +79 -0
  122. package/dist/pc/pc.entry-overrides.js +40 -0
  123. package/dist/pc/pc.equipment.d.ts +2 -2
  124. package/dist/pc/pc.equipment.js +19 -7
  125. package/dist/pc/pc.feature-effects.d.ts +12 -0
  126. package/dist/pc/pc.feature-effects.js +2 -2
  127. package/dist/pc/pc.infusions.d.ts +228 -0
  128. package/dist/pc/pc.infusions.js +64 -0
  129. package/dist/pc/pc.member-choices.d.ts +90 -0
  130. package/dist/pc/pc.member-choices.js +32 -0
  131. package/dist/pc/pc.parser.js +18 -1
  132. package/dist/pc/pc.pools.d.ts +8 -1
  133. package/dist/pc/pc.pools.js +13 -3
  134. package/dist/pc/pc.proficiencies.js +23 -15
  135. package/dist/pc/pc.proficiency-query.js +6 -0
  136. package/dist/pc/pc.recalc.d.ts +39 -36
  137. package/dist/pc/pc.recalc.js +115 -70
  138. package/dist/pc/pc.resolver.d.ts +2 -1
  139. package/dist/pc/pc.resolver.js +22 -14
  140. package/dist/pc/pc.resource-seed.js +1 -1
  141. package/dist/pc/pc.resources.d.ts +6 -1
  142. package/dist/pc/pc.resources.js +3 -1
  143. package/dist/pc/pc.rest.d.ts +21 -1
  144. package/dist/pc/pc.rest.js +52 -19
  145. package/dist/pc/pc.schema.d.ts +43 -2
  146. package/dist/pc/pc.schema.js +1 -1
  147. package/dist/pc/pc.slotting.d.ts +36 -3
  148. package/dist/pc/pc.slotting.js +13 -5
  149. package/dist/pc/pc.tool-picks.d.ts +51 -0
  150. package/dist/pc/pc.tool-picks.js +18 -0
  151. package/dist/pc/pc.types.d.ts +115 -14
  152. package/dist/pc/pc.weapon-grant.d.ts +15 -0
  153. package/dist/pc/pool-layout.d.ts +8 -0
  154. package/dist/pc/pool-layout.js +5 -3
  155. package/dist/pc/resource-equivalents.d.ts +44 -0
  156. package/dist/pc/spell-source.js +4 -9
  157. package/dist/race/race.codec.js +6 -6
  158. package/dist/race/race.parser.js +5 -5
  159. package/dist/race/race.schema.js +4 -4
  160. package/dist/schemas/attack-schema.d.ts +1 -1
  161. package/dist/schemas/choice-schema.js +2 -2
  162. package/dist/schemas/feature-effect-schema.d.ts +41 -3
  163. package/dist/schemas/feature-effect-schema.js +1 -1
  164. package/dist/schemas/feature-schema.js +3 -3
  165. package/dist/schemas/selection-pool-schema.d.ts +10 -0
  166. package/dist/schemas/selection-pool-schema.js +1 -1
  167. package/dist/spell/spell.codec.js +2 -2
  168. package/dist/spell/spell.parser.d.ts +6 -1
  169. package/dist/spell/spell.parser.js +5 -3
  170. package/dist/spell/spell.types.d.ts +10 -0
  171. package/dist/srd/retired-items.d.ts +14 -0
  172. package/dist/srd/retired-items.js +11 -0
  173. package/dist/subclass/subclass.codec.js +7 -7
  174. package/dist/subclass/subclass.parser.js +6 -6
  175. package/dist/subclass/subclass.schema.d.ts +10 -0
  176. package/dist/subclass/subclass.schema.js +5 -5
  177. package/dist/types/choice.d.ts +13 -0
  178. package/dist/types/equipment-grant.d.ts +18 -1
  179. package/dist/types/equipment-grant.js +12 -0
  180. package/dist/types/feature-effect.d.ts +12 -1
  181. package/dist/types/optional-feature.types.d.ts +84 -1
  182. package/dist/types/selection-pool.d.ts +18 -3
  183. package/dist/weapon/weapon.classify.d.ts +10 -8
  184. package/dist/weapon/weapon.classify.js +2 -2
  185. package/dist/weapon/weapon.codec.js +3 -3
  186. package/dist/weapon/weapon.parser.js +2 -2
  187. package/dist/weapon/weapon.schema.d.ts +1 -0
  188. package/dist/weapon/weapon.schema.js +1 -1
  189. package/dist/weapon/weapon.types.d.ts +2 -0
  190. package/package.json +1 -1
  191. package/dist/chunk-O4SRD3J5.js +0 -165
  192. package/dist/chunk-WXWPK3LI.js +0 -55
@@ -1,34 +1,46 @@
1
+ import {
2
+ qualifiedGrantCovers
3
+ } from "./chunk-3LWMFYKS.js";
1
4
  import {
2
5
  classifyWeaponRange
3
- } from "./chunk-UIRMA5KM.js";
6
+ } from "./chunk-YDGMBMYI.js";
4
7
  import {
5
- defaultSlotForType,
6
- effectiveArmor,
7
- isItemEntity,
8
- isWeaponEntity,
9
- resolveEntityForEntry
10
- } from "./chunk-UBBKSYBY.js";
8
+ resolveContainment
9
+ } from "./chunk-EJP263OP.js";
11
10
  import {
12
11
  normKey
13
12
  } from "./chunk-RLGQ5PZZ.js";
13
+ import {
14
+ WEAPON_DEFAULT_ACTION_COST,
15
+ resolveEntryEntity
16
+ } from "./chunk-3VZZDKRA.js";
14
17
  import {
15
18
  readNumericBonus
16
- } from "./chunk-LWFTHJIE.js";
19
+ } from "./chunk-HHBD4SQ6.js";
20
+ import {
21
+ defaultSlotForType,
22
+ effectiveArmor,
23
+ effectiveWeapon,
24
+ isItemEntity,
25
+ isShieldArmor,
26
+ isTwoHandedWeapon,
27
+ slotAcTerms
28
+ } from "./chunk-LHZXYFBU.js";
17
29
  import {
18
30
  resolveBaseItem
19
- } from "./chunk-WXWPK3LI.js";
31
+ } from "./chunk-CM5CWO4K.js";
20
32
  import {
21
33
  bareEntitySlug
22
- } from "./chunk-6X4KUDMU.js";
34
+ } from "./chunk-ZCTUYGNV.js";
23
35
 
24
36
  // src/weapon/weapon-mastery.ts
25
37
  var MASTERY = {
26
38
  cleave: { label: "Cleave", description: "If you hit a creature with a melee attack roll using this weapon, you can make an attack roll with the weapon against a second creature within 5 feet of the first that is also within your reach. On a hit, the second creature takes the weapon's damage, but don't add your ability modifier to that damage unless it is negative. You can make this extra attack only once per turn.", gist: "hit a 2nd creature in reach" },
27
39
  graze: { label: "Graze", description: "If your attack roll with this weapon misses a creature, you can deal damage to that creature equal to the ability modifier you used to make the attack roll. This damage is the same type dealt by the weapon, and the damage can be increased only by increasing the ability modifier.", gist: "on miss: ability-mod damage" },
28
40
  nick: { label: "Nick", description: "When you make the extra attack of the Light property, you can make it as part of the Attack action instead of as a Bonus Action. You can make this extra attack only once per turn.", gist: "extra Light attack (no Bonus Action)" },
29
- push: { label: "Push", description: "If you hit a creature with this weapon, you can push the creature up to 10 feet straight away from yourself if it is Large or smaller.", gist: "on hit: pushed 10 ft" },
41
+ push: { label: "Push", description: "If you hit a creature with this weapon, you can push the creature up to 10 feet straight away from yourself if it is Large or smaller.", gist: "on hit: pushed 10 ft." },
30
42
  sap: { label: "Sap", description: "If you hit a creature with this weapon, that creature has Disadvantage on its next attack roll before the start of your next turn.", gist: "on hit: target Disadvantage" },
31
- slow: { label: "Slow", description: "If you hit a creature with this weapon and deal damage, you can reduce its Speed by 10 feet until the start of your next turn. If the creature is hit more than once by weapons that have this property, the Speed reduction doesn't exceed 10 feet.", gist: "on hit: -10 ft Speed" },
43
+ slow: { label: "Slow", description: "If you hit a creature with this weapon and deal damage, you can reduce its Speed by 10 feet until the start of your next turn. If the creature is hit more than once by weapons that have this property, the Speed reduction doesn't exceed 10 feet.", gist: "on hit: -10 ft. Speed" },
32
44
  topple: { label: "Topple", description: "If you hit a creature with this weapon, you can force the creature to make a Constitution saving throw (DC 8 plus the ability modifier used to make the attack roll and your Proficiency Bonus). On a failed save, the creature has the Prone condition.", gist: "on fail: Prone" },
33
45
  vex: { label: "Vex", description: "If you hit a creature with this weapon and deal damage, you have Advantage on your next attack roll against that creature before the end of your next turn.", gist: "on hit: you gain Advantage next" }
34
46
  };
@@ -52,6 +64,7 @@ function emptyAppliedBonuses() {
52
64
  ability_bonuses: {},
53
65
  ability_statics: {},
54
66
  save_bonus: 0,
67
+ save_terms: [],
55
68
  speed_bonuses: { walk: 0, fly: null, swim: 0, climb: 0 },
56
69
  spell_attack: 0,
57
70
  spell_save_dc: 0,
@@ -75,13 +88,15 @@ function unwrapClassSlug(maybeWiki) {
75
88
  const m = /^\[\[([^\]]+)\]\]$/.exec(maybeWiki);
76
89
  return (m ? m[1] : maybeWiki).toLowerCase();
77
90
  }
78
- function buildConditionContext(resolved, equippedSlots) {
91
+ function buildConditionContext(resolved, equippedSlots, registry) {
79
92
  var _a, _b;
80
93
  return {
81
94
  derived: { equippedSlots },
82
95
  classList: (_a = resolved.definition.class) != null ? _a : [],
83
96
  race: resolved.definition.race,
84
- subclasses: ((_b = resolved.definition.class) != null ? _b : []).map((c) => c.subclass).filter((s) => typeof s === "string" && s.length > 0).map(unwrapClassSlug)
97
+ subclasses: ((_b = resolved.definition.class) != null ? _b : []).map((c) => c.subclass).filter((s) => typeof s === "string" && s.length > 0).map(unwrapClassSlug),
98
+ // H234 H2: `wielding_two_handed` reads a magic main-hand weapon's base through it.
99
+ registry
85
100
  };
86
101
  }
87
102
  function pushApply(outcome, field, source, pool, onApply) {
@@ -92,29 +107,30 @@ function pushApply(outcome, field, source, pool, onApply) {
92
107
  }
93
108
  }
94
109
  function computeAppliedBonuses(resolved, _profs, registry, warnings) {
95
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
110
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s;
96
111
  const out = emptyAppliedBonuses();
97
112
  const equipment = (_a = resolved.definition.equipment) != null ? _a : [];
98
- const ctx = buildConditionContext(resolved, {});
99
- for (const entry of equipment) {
100
- const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
113
+ const ctx = buildConditionContext(resolved, {}, registry);
114
+ for (let index = 0; index < equipment.length; index++) {
115
+ const entry = equipment[index];
116
+ const { entity, entityType } = resolveEntryEntity(entry, index, registry, resolved.infusions);
101
117
  if (!entity) {
102
118
  const slug = unwrapSlug(entry.item);
103
- if (slug && entry.equipped) warnings.push(`Equipped item [[${slug}]] not found in compendium.`);
119
+ if (slug && entry.equipped && !((_b = resolved.infusions) == null ? void 0 : _b.views.has(index))) warnings.push(`Equipped item [[${slug}]] not found in compendium.`);
104
120
  continue;
105
121
  }
106
122
  if (!isAttunedActive(entry, entity)) continue;
107
123
  if (entityType !== "item") continue;
108
124
  const item = entity;
109
- (_b = item.resist) == null ? void 0 : _b.forEach((s) => out.defenses.resistances.push(s));
110
- (_c = item.immune) == null ? void 0 : _c.forEach((s) => out.defenses.immunities.push(s));
111
- (_d = item.vulnerable) == null ? void 0 : _d.forEach((s) => out.defenses.vulnerabilities.push(s));
112
- (_e = item.condition_immune) == null ? void 0 : _e.forEach((s) => out.defenses.condition_immunities.push(s));
113
- (_g = (_f = entry.overrides) == null ? void 0 : _f.resist) == null ? void 0 : _g.forEach((s) => out.defenses.resistances.push(s));
114
- (_i = (_h = entry.overrides) == null ? void 0 : _h.immune) == null ? void 0 : _i.forEach((s) => out.defenses.immunities.push(s));
115
- (_k = (_j = entry.overrides) == null ? void 0 : _j.vulnerable) == null ? void 0 : _k.forEach((s) => out.defenses.vulnerabilities.push(s));
116
- (_m = (_l = entry.overrides) == null ? void 0 : _l.condition_immune) == null ? void 0 : _m.forEach((s) => out.defenses.condition_immunities.push(s));
117
- const gs = (_n = item.grants) == null ? void 0 : _n.senses;
125
+ (_c = item.resist) == null ? void 0 : _c.forEach((s) => out.defenses.resistances.push(s));
126
+ (_d = item.immune) == null ? void 0 : _d.forEach((s) => out.defenses.immunities.push(s));
127
+ (_e = item.vulnerable) == null ? void 0 : _e.forEach((s) => out.defenses.vulnerabilities.push(s));
128
+ (_f = item.condition_immune) == null ? void 0 : _f.forEach((s) => out.defenses.condition_immunities.push(s));
129
+ (_h = (_g = entry.overrides) == null ? void 0 : _g.resist) == null ? void 0 : _h.forEach((s) => out.defenses.resistances.push(s));
130
+ (_j = (_i = entry.overrides) == null ? void 0 : _i.immune) == null ? void 0 : _j.forEach((s) => out.defenses.immunities.push(s));
131
+ (_l = (_k = entry.overrides) == null ? void 0 : _k.vulnerable) == null ? void 0 : _l.forEach((s) => out.defenses.vulnerabilities.push(s));
132
+ (_n = (_m = entry.overrides) == null ? void 0 : _m.condition_immune) == null ? void 0 : _n.forEach((s) => out.defenses.condition_immunities.push(s));
133
+ const gs = (_o = item.grants) == null ? void 0 : _o.senses;
118
134
  if (gs) {
119
135
  if (typeof gs.darkvision === "number") out.senses.darkvision = Math.max(out.senses.darkvision, gs.darkvision);
120
136
  if (typeof gs.blindsight === "number") out.senses.blindsight = Math.max(out.senses.blindsight, gs.blindsight);
@@ -123,13 +139,15 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
123
139
  }
124
140
  const b = item.bonuses;
125
141
  if (!b) continue;
142
+ const saveSource = (_q = (_p = entry.overrides) == null ? void 0 : _p.name) != null ? _q : item.name;
126
143
  pushApply(
127
144
  readNumericBonus(b.saving_throws, ctx),
128
145
  "saving_throws",
129
- item.name,
146
+ saveSource,
130
147
  out.informational,
131
148
  (v) => {
132
149
  out.save_bonus += v;
150
+ out.save_terms.push({ source: saveSource, amount: v });
133
151
  }
134
152
  );
135
153
  pushApply(
@@ -150,7 +168,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
150
168
  out.spell_save_dc += v;
151
169
  }
152
170
  );
153
- if ((_o = b.ability_scores) == null ? void 0 : _o.bonus) {
171
+ if ((_r = b.ability_scores) == null ? void 0 : _r.bonus) {
154
172
  for (const [k, v] of Object.entries(b.ability_scores.bonus)) {
155
173
  if (!isAbilityKey(k)) continue;
156
174
  pushApply(
@@ -165,7 +183,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
165
183
  );
166
184
  }
167
185
  }
168
- if ((_p = b.ability_scores) == null ? void 0 : _p.static) {
186
+ if ((_s = b.ability_scores) == null ? void 0 : _s.static) {
169
187
  for (const [k, n] of Object.entries(b.ability_scores.static)) {
170
188
  if (!isAbilityKey(k) || typeof n !== "number") continue;
171
189
  const prev = out.ability_statics[k];
@@ -227,28 +245,22 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
227
245
  }
228
246
  return out;
229
247
  }
230
- function isTwoHanded(weapon) {
231
- return weapon.properties.some((p) => p === "two_handed");
232
- }
233
248
  function assignSlots(resolved, registry, warnings) {
234
- var _a, _b;
249
+ var _a;
235
250
  const slots = {};
236
251
  const eq = (_a = resolved.definition.equipment) != null ? _a : [];
237
252
  for (let i = 0; i < eq.length; i++) {
238
253
  const entry = eq[i];
239
254
  if (!entry.equipped || !entry.slot) continue;
240
- const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
241
- if (slots[entry.slot]) {
242
- warnings.push(`${entry.slot} slot conflict: ${entry.item} ignored (already taken).`);
243
- continue;
244
- }
255
+ const { entity, entityType } = resolveEntryEntity(entry, i, registry, resolved.infusions);
256
+ if (slots[entry.slot]) continue;
245
257
  const placed = { index: i, entity, entityType, entry };
246
258
  slots[entry.slot] = placed;
247
259
  }
248
260
  for (let i = 0; i < eq.length; i++) {
249
261
  const entry = eq[i];
250
262
  if (!entry.equipped || entry.slot) continue;
251
- const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
263
+ const { entity, entityType } = resolveEntryEntity(entry, i, registry, resolved.infusions);
252
264
  if (!entity || !entityType) continue;
253
265
  const defaultSlot = defaultSlotForType(entityType, entity, registry);
254
266
  if (!defaultSlot) {
@@ -263,23 +275,45 @@ function assignSlots(resolved, registry, warnings) {
263
275
  if (defaultSlot === "mainhand") {
264
276
  if (!slots.mainhand) slots.mainhand = placed;
265
277
  else if (!slots.offhand) slots.offhand = placed;
266
- else warnings.push(`No free hand for ${entry.item}; entry remains equipped without slot.`);
267
- } else {
268
- if (slots[defaultSlot]) {
269
- warnings.push(`${defaultSlot} slot already filled; ${entry.item} ignored.`);
270
- } else {
271
- slots[defaultSlot] = placed;
272
- }
278
+ } else if (!slots[defaultSlot]) {
279
+ slots[defaultSlot] = placed;
273
280
  }
274
281
  }
275
- const main = (_b = slots.mainhand) == null ? void 0 : _b.entity;
276
- if (main && isWeaponEntity(main) && isTwoHanded(main) && slots.shield) {
277
- warnings.push(`Two-handed weapon equipped; shield ignored.`);
278
- }
279
282
  return slots;
280
283
  }
284
+ function pickShield(equippedSlots, equipment, registry, infusions) {
285
+ const slotted = equippedSlots.shield;
286
+ const slottedArmor = effectiveArmor(slotted == null ? void 0 : slotted.entity, registry);
287
+ if (slotted && slottedArmor && isShieldArmor(slottedArmor)) {
288
+ return { index: slotted.index, shield: slottedArmor, entity: slotted.entity, entry: slotted.entry };
289
+ }
290
+ for (let i = 0; i < equipment.length; i++) {
291
+ const entry = equipment[i];
292
+ if (!entry.equipped) continue;
293
+ const { entity } = resolveEntryEntity(entry, i, registry, infusions);
294
+ const armor = effectiveArmor(entity, registry);
295
+ if (armor && isShieldArmor(armor)) return { index: i, shield: armor, entity, entry };
296
+ }
297
+ return null;
298
+ }
299
+ function twoHandedShieldWarnings(equipment, registry, warnings, infusions) {
300
+ const equipped = equipment.flatMap((entry, i) => {
301
+ if (!entry.equipped) return [];
302
+ const { entity } = resolveEntryEntity(entry, i, registry, infusions);
303
+ return [{ entry, entity }];
304
+ });
305
+ const isShield = (e) => {
306
+ const armor = effectiveArmor(e.entity, registry);
307
+ return !!armor && isShieldArmor(armor);
308
+ };
309
+ for (const e of equipped) {
310
+ if (!e.entity || !isTwoHandedWeapon(e.entity, registry)) continue;
311
+ if (!equipped.some((other) => other !== e && isShield(other))) continue;
312
+ warnings.push(`${e.entity.name} is two-handed and a Shield is also equipped.`);
313
+ }
314
+ }
281
315
  function computeAC(equippedSlots, resolved, mods, registry, warnings) {
282
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
316
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
283
317
  const breakdown = [];
284
318
  const armorSlot = equippedSlots.armor;
285
319
  const armorEntity = (_a = armorSlot == null ? void 0 : armorSlot.entity) != null ? _a : null;
@@ -289,13 +323,25 @@ function computeAC(equippedSlots, resolved, mods, registry, warnings) {
289
323
  `Magic armor "${armorEntity.name}" base_item ${armorEntity.base_item} did not resolve to a base armor; AC not applied.`
290
324
  );
291
325
  }
326
+ const acCtx = buildConditionContext(resolved, equippedSlots, registry);
327
+ const skip = /* @__PURE__ */ new Set();
328
+ const slotBonus = (slot) => {
329
+ var _a2, _b2;
330
+ const view = slot ? (_a2 = resolved.infusions) == null ? void 0 : _a2.views.get(slot.index) : void 0;
331
+ if (!slot || !(view == null ? void 0 : view.entity) || !isItemEntity(view.entity) || !isAttunedActive(slot.entry, view.entity)) return 0;
332
+ const out = readNumericBonus((_b2 = view.entity.bonuses) == null ? void 0 : _b2.ac, acCtx);
333
+ if ((out == null ? void 0 : out.kind) !== "applied") return 0;
334
+ skip.add(slot.index);
335
+ return out.value;
336
+ };
337
+ const armorTerms = slotAcTerms(armor, armorSlot == null ? void 0 : armorSlot.entry);
292
338
  let ac = 10;
293
- if (armor) {
294
- const armorBase = armor.ac.base + ((_b = armor.ac.flat) != null ? _b : 0);
339
+ if (armor && armorTerms.armor !== null) {
340
+ const armorBase = armorTerms.armor + slotBonus(armorSlot);
295
341
  ac = armorBase;
296
- breakdown.push({ source: (_c = armorEntity == null ? void 0 : armorEntity.name) != null ? _c : armor.name, amount: armorBase, kind: "armor" });
342
+ breakdown.push({ source: (_b = armorEntity == null ? void 0 : armorEntity.name) != null ? _b : armor.name, amount: armorBase, kind: "armor" });
297
343
  if (armor.ac.add_dex) {
298
- const dexCap = (_d = armor.ac.dex_max) != null ? _d : Number.POSITIVE_INFINITY;
344
+ const dexCap = (_c = armor.ac.dex_max) != null ? _c : Number.POSITIVE_INFINITY;
299
345
  const dexAdd = Math.min(mods.dex, dexCap);
300
346
  ac += dexAdd;
301
347
  const capped = mods.dex > dexCap;
@@ -306,28 +352,34 @@ function computeAC(equippedSlots, resolved, mods, registry, warnings) {
306
352
  breakdown.push({ source: "Base", amount: 10, kind: "unarmored" });
307
353
  breakdown.push({ source: "DEX modifier", amount: mods.dex, kind: "dex" });
308
354
  }
309
- const acBonus = (_e = armorSlot == null ? void 0 : armorSlot.entry.overrides) == null ? void 0 : _e.ac_bonus;
310
- if (typeof acBonus === "number" && acBonus !== 0) {
355
+ const acBonus = armorTerms.override;
356
+ if (acBonus !== 0) {
311
357
  ac += acBonus;
312
- breakdown.push({ source: `${(_f = armorEntity == null ? void 0 : armorEntity.name) != null ? _f : "Armor"} (override)`, amount: acBonus, kind: "override" });
358
+ breakdown.push({ source: `${(_d = armorEntity == null ? void 0 : armorEntity.name) != null ? _d : "Armor"} (override)`, amount: acBonus, kind: "override" });
313
359
  }
314
- const main = (_g = equippedSlots.mainhand) == null ? void 0 : _g.entity;
315
- const mainIsTwoHanded = main && isWeaponEntity(main) && isTwoHanded(main);
316
- const shieldEntity = (_i = (_h = equippedSlots.shield) == null ? void 0 : _h.entity) != null ? _i : null;
317
- const shield = effectiveArmor(shieldEntity, registry);
318
- if (shield && !mainIsTwoHanded) {
319
- const n = shield.ac.base + ((_j = shield.ac.flat) != null ? _j : 0);
360
+ const picked = pickShield(equippedSlots, (_e = resolved.definition.equipment) != null ? _e : [], registry, resolved.infusions);
361
+ if (picked) {
362
+ const { shield, entity: shieldEntity } = picked;
363
+ const shieldTerms = slotAcTerms(shield, picked.entry);
364
+ const n = shieldTerms.armor + slotBonus(picked);
320
365
  ac += n;
321
- breakdown.push({ source: (_k = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _k : shield.name, amount: n, kind: "shield" });
366
+ breakdown.push({ source: (_f = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _f : shield.name, amount: n, kind: "shield" });
367
+ const shieldAcBonus = shieldTerms.override;
368
+ if (shieldAcBonus !== 0) {
369
+ ac += shieldAcBonus;
370
+ breakdown.push({ source: `${(_g = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _g : shield.name} (override)`, amount: shieldAcBonus, kind: "shield" });
371
+ }
322
372
  }
323
373
  const acInformational = [];
324
- const acCtx = buildConditionContext(resolved, equippedSlots);
325
- for (const entry of (_l = resolved.definition.equipment) != null ? _l : []) {
326
- const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
374
+ const acEquipment = (_h = resolved.definition.equipment) != null ? _h : [];
375
+ for (let index = 0; index < acEquipment.length; index++) {
376
+ if (skip.has(index)) continue;
377
+ const entry = acEquipment[index];
378
+ const { entity, entityType } = resolveEntryEntity(entry, index, registry, resolved.infusions);
327
379
  if (!entity || entityType !== "item") continue;
328
380
  if (!isAttunedActive(entry, entity)) continue;
329
381
  const item = entity;
330
- const out = readNumericBonus((_m = item.bonuses) == null ? void 0 : _m.ac, acCtx);
382
+ const out = readNumericBonus((_i = item.bonuses) == null ? void 0 : _i.ac, acCtx);
331
383
  if (!out) continue;
332
384
  if (out.kind === "applied") {
333
385
  ac += out.value;
@@ -365,6 +417,7 @@ function attackAbility(weapon, mods, weaponAbilities) {
365
417
  function isWeaponSlugProficient(weapon, weaponSlug, profs) {
366
418
  const wp = profs.weapons;
367
419
  if (wp.specific.some((e) => e === weaponSlug || normKey(e) === normKey(weapon.name))) return true;
420
+ if (wp.specific.some((e) => qualifiedGrantCovers(e, weapon))) return true;
368
421
  const cat = weapon.category;
369
422
  if (typeof cat === "string") {
370
423
  if (/^simple\b/.test(cat) && wp.categories.includes("simple")) return true;
@@ -373,9 +426,9 @@ function isWeaponSlugProficient(weapon, weaponSlug, profs) {
373
426
  }
374
427
  return false;
375
428
  }
376
- function magicBonusesForWeaponEntry(entry, registry, ctx) {
429
+ function magicBonusesForWeaponEntry(entry, registry, ctx, index, infusions) {
377
430
  var _a;
378
- const { entity } = resolveEntityForEntry(entry.item, registry);
431
+ const { entity } = resolveEntryEntity(entry, index, registry, infusions);
379
432
  const ovr = (_a = entry.overrides) != null ? _a : {};
380
433
  const entryAttack = typeof ovr.bonus === "number" ? ovr.bonus : 0;
381
434
  const entryDamage = typeof ovr.damage_bonus === "number" ? ovr.damage_bonus : 0;
@@ -440,8 +493,8 @@ function buildAttackRow(args) {
440
493
  { source: magicSource, amount: magic.dmg, kind: "item" }
441
494
  ];
442
495
  const modes = classifyWeaponRange(weapon);
443
- const fmtRanged = (r) => `${r.normal}/${r.long} ft`;
444
- const range = modes.melee ? `${modes.melee.reach} ft` : modes.ranged ? fmtRanged(modes.ranged) : void 0;
496
+ const fmtRanged = (r) => `${r.normal}/${r.long} ft.`;
497
+ const range = modes.melee ? `${modes.melee.reach} ft.` : modes.ranged ? fmtRanged(modes.ranged) : void 0;
445
498
  const thrownRange = modes.melee && modes.ranged ? fmtRanged(modes.ranged) : void 0;
446
499
  const stringProps = weapon.properties.filter(
447
500
  (p) => typeof p === "string"
@@ -455,14 +508,17 @@ function buildAttackRow(args) {
455
508
  toHit,
456
509
  damageDice,
457
510
  damageType: (_b = magic.damageTypeOverride) != null ? _b : weapon.damage.type,
458
- // Riders: item damage_riders (Task 2) + the migrated manual override string.
511
+ // Riders: item damage_riders (Task 2) + the entry's overrides.extra_damage string. The override
512
+ // rider carries NO source: the player typed it on this very row, so the weapons table attributes it
513
+ // to nothing (no "(manual)" in a caption, no hover title on its chip).
459
514
  ...(() => {
460
515
  const riders = [
461
516
  ...magic.riders,
462
- ...magic.extra ? [{ amount: magic.extra, source: "manual" }] : []
517
+ ...magic.extra ? [{ amount: magic.extra }] : []
463
518
  ];
464
519
  return riders.length ? { damageRiders: riders } : {};
465
520
  })(),
521
+ weaponCategory: modes.melee ? "melee" : "ranged",
466
522
  properties: finalProps,
467
523
  proficient,
468
524
  breakdown: { toHit: toHitBreakdown, damage: damageBreakdown },
@@ -496,7 +552,7 @@ function buildUnarmedRow(mods, proficiencyBonus, spec) {
496
552
  id: "unarmed-strike",
497
553
  name: "Unarmed Strike",
498
554
  unarmed: true,
499
- range: "5 ft",
555
+ range: "5 ft.",
500
556
  toHit,
501
557
  damageDice,
502
558
  damageType: "bludgeoning",
@@ -507,8 +563,10 @@ function buildUnarmedRow(mods, proficiencyBonus, spec) {
507
563
  { source: label, amount: abilityMod, kind: "ability" },
508
564
  { source: "Proficiency bonus", amount: proficiencyBonus, kind: "ability" }
509
565
  ],
566
+ // T17 T-33: the base term is the one the total sums. With no die the strike deals 1 + mod, so the base is +1
567
+ // (it read +0 beside a total of 1 + mod); a die carries its own base, as a weapon's does, so it stays +0.
510
568
  damage: [
511
- { source: "Base damage", amount: 0, kind: "ability" },
569
+ { source: "Base damage", amount: (spec == null ? void 0 : spec.dice) ? 0 : 1, kind: "ability" },
512
570
  { source: label, amount: abilityMod, kind: "ability" }
513
571
  ]
514
572
  },
@@ -528,45 +586,22 @@ function formatWeaponSubLabel(weapon, properties, modes) {
528
586
  if (properties.length > 0) parts.push(properties.map(humanizeWeaponToken).join(", "));
529
587
  return parts.join(" \xB7 ");
530
588
  }
531
- function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities = []) {
532
- var _a, _b, _c, _d, _e;
589
+ function computeAttacks(equippedSlots, equipment, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities = [], infusions) {
590
+ var _a, _b;
533
591
  const rows = [];
534
- const handedSlots = [
535
- { key: "mainhand", placed: equippedSlots.mainhand },
536
- { key: "offhand", placed: equippedSlots.offhand }
537
- ];
538
- for (const { key, placed } of handedSlots) {
539
- if (!placed) continue;
540
- const { entity, entry } = placed;
541
- if (!entity) continue;
542
- let weapon = null;
543
- if (isWeaponEntity(entity)) {
544
- weapon = entity;
545
- } else if (isItemEntity(entity) && typeof entity.base_item === "string") {
546
- const baseSlug = entity.base_item;
547
- const found = resolveBaseItem(baseSlug, registry);
548
- if (found && found.entityType === "weapon" && isWeaponEntity(found.data)) {
549
- weapon = found.data;
550
- } else {
551
- warnings.push(`Magic weapon ${entity.name} references missing base_item ${baseSlug}.`);
552
- continue;
553
- }
554
- } else {
555
- continue;
556
- }
557
- const slugFromEntry = (_a = unwrapSlug(entry.item)) != null ? _a : weapon.slug;
592
+ const rowFor = (index, entry, weapon, slotKey, versatileDice) => {
593
+ var _a2, _b2, _c, _d, _e;
594
+ const slugFromEntry = (_a2 = unwrapSlug(entry.item)) != null ? _a2 : weapon.slug;
558
595
  const proficient = isWeaponSlugProficient(weapon, slugFromEntry, profs) || isWeaponSlugProficient(weapon, weapon.slug, profs);
559
596
  if (!proficient) {
560
597
  warnings.push(`Character not proficient with ${weapon.name}; proficiency bonus excluded.`);
561
598
  }
562
599
  const ability = attackAbility(weapon, mods, weaponAbilities);
563
- const magic = magicBonusesForWeaponEntry(entry, registry, ctx);
564
- const ovr = (_b = entry.overrides) != null ? _b : {};
565
- const displayName = (_d = (_c = ovr.name) != null ? _c : magic.itemName) != null ? _d : weapon.name;
566
- const versatileDice = key === "mainhand" && hasProperty(weapon, "versatile") && typeof weapon.damage.versatile_dice === "string" && !equippedSlots.offhand ? weapon.damage.versatile_dice : void 0;
567
- const baseRow = buildAttackRow({
568
- id: `${placed.index}:standard`,
569
- name: displayName,
600
+ const magic = magicBonusesForWeaponEntry(entry, registry, ctx, index, infusions);
601
+ const ovr = (_b2 = entry.overrides) != null ? _b2 : {};
602
+ return buildAttackRow({
603
+ id: `${index}:standard`,
604
+ name: (_d = (_c = ovr.name) != null ? _c : magic.itemName) != null ? _d : weapon.name,
570
605
  weapon,
571
606
  baseDice: weapon.damage.dice,
572
607
  ability,
@@ -574,13 +609,38 @@ function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficie
574
609
  proficient,
575
610
  proficiencyBonus,
576
611
  magic,
577
- slotKey: key,
578
- actionCost: (_e = ovr.action) != null ? _e : "action",
612
+ slotKey,
613
+ actionCost: (_e = ovr.action) != null ? _e : WEAPON_DEFAULT_ACTION_COST,
579
614
  versatileDice,
580
615
  weaponMasteries
581
616
  });
582
- rows.push(baseRow);
617
+ };
618
+ const handedSlots = [
619
+ { key: "mainhand", placed: equippedSlots.mainhand },
620
+ { key: "offhand", placed: equippedSlots.offhand }
621
+ ];
622
+ for (const { key, placed } of handedSlots) {
623
+ if (!placed) continue;
624
+ const { entity, entry } = placed;
625
+ if (!entity) continue;
626
+ const weapon = effectiveWeapon(entity, registry);
627
+ if (!weapon) {
628
+ if (isItemEntity(entity) && typeof entity.base_item === "string") {
629
+ warnings.push(`Magic weapon ${entity.name} references missing base_item ${entity.base_item}.`);
630
+ }
631
+ continue;
632
+ }
633
+ const versatileDice = key === "mainhand" && hasProperty(weapon, "versatile") && typeof weapon.damage.versatile_dice === "string" && !equippedSlots.offhand ? weapon.damage.versatile_dice : void 0;
634
+ rows.push(rowFor(placed.index, entry, weapon, key, versatileDice));
583
635
  }
636
+ const handIndex = /* @__PURE__ */ new Set([(_a = equippedSlots.mainhand) == null ? void 0 : _a.index, (_b = equippedSlots.offhand) == null ? void 0 : _b.index]);
637
+ equipment.forEach((entry, index) => {
638
+ if (!entry.equipped || handIndex.has(index)) return;
639
+ const { entity } = resolveEntryEntity(entry, index, registry, infusions);
640
+ const weapon = effectiveWeapon(entity, registry);
641
+ if (!weapon) return;
642
+ rows.push(rowFor(index, entry, weapon));
643
+ });
584
644
  return rows;
585
645
  }
586
646
  function coerceWeight(raw) {
@@ -593,25 +653,38 @@ function coerceWeight(raw) {
593
653
  }
594
654
  function computeCarriedWeight(resolved, registry) {
595
655
  var _a;
656
+ const equipment = (_a = resolved.definition.equipment) != null ? _a : [];
657
+ const view = resolveContainment(equipment, registry);
658
+ const weightlessContainer = equipment.map((entry) => {
659
+ var _a2, _b, _c;
660
+ const data = (_a2 = resolveBaseItem(entry.item, registry)) == null ? void 0 : _a2.data;
661
+ return ((_c = (_b = data == null ? void 0 : data.container) == null ? void 0 : _b.capacity) == null ? void 0 : _c.weightless) === true;
662
+ });
663
+ const exempt = (i) => {
664
+ for (let p = view.parentOf[i]; p !== null; p = view.parentOf[p]) if (weightlessContainer[p]) return true;
665
+ return false;
666
+ };
596
667
  let total = 0;
597
- for (const entry of (_a = resolved.definition.equipment) != null ? _a : []) {
668
+ equipment.forEach((entry, i) => {
669
+ if (exempt(i)) return;
598
670
  const found = resolveBaseItem(entry.item, registry);
599
- if (!found) continue;
671
+ if (!found) return;
600
672
  const entity = found.data;
601
673
  const w = coerceWeight(entity.weight);
602
- if (w === 0) continue;
674
+ if (w === 0) return;
603
675
  const qty = typeof entry.qty === "number" && entry.qty >= 0 ? entry.qty : 1;
604
676
  total += w * qty;
605
- }
677
+ });
606
678
  return total;
607
679
  }
608
680
  function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, proficiencyBonus, weaponAbilities = [], weaponMasteries = [], attunementFloor = 0) {
609
- var _a, _b, _c;
681
+ var _a, _b, _c, _d, _e;
610
682
  const equippedSlots = assignSlots(resolved, registry, warnings);
611
- const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
683
+ twoHandedShieldWarnings((_a = resolved.definition.equipment) != null ? _a : [], registry, warnings, resolved.infusions);
684
+ const overrides = (_b = resolved.definition.overrides) != null ? _b : {};
612
685
  const acOut = computeAC(equippedSlots, resolved, mods, registry, warnings);
613
- const ctx = buildConditionContext(resolved, equippedSlots);
614
- const attacks = computeAttacks(equippedSlots, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities);
686
+ const ctx = buildConditionContext(resolved, equippedSlots, registry);
687
+ const attacks = computeAttacks(equippedSlots, (_c = resolved.definition.equipment) != null ? _c : [], mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities, resolved.infusions);
615
688
  return {
616
689
  ac: acOut.ac,
617
690
  acBreakdown: acOut.breakdown,
@@ -620,10 +693,10 @@ function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, profi
620
693
  equippedSlots,
621
694
  carriedWeight: computeCarriedWeight(resolved, registry),
622
695
  // Attunement is persistent: an attuned item still occupies a slot even when unequipped (SRD).
623
- attunementUsed: ((_b = resolved.definition.equipment) != null ? _b : []).filter((e) => e.attuned).length,
696
+ attunementUsed: ((_d = resolved.definition.equipment) != null ? _d : []).filter((e) => e.attuned).length,
624
697
  // PRECEDENCE: an explicit character override wins outright (a number the player typed is intent);
625
698
  // otherwise the baseline 3 is raised — never lowered — by whatever features granted.
626
- attunementLimit: (_c = overrides.attunement_limit) != null ? _c : Math.max(3, attunementFloor)
699
+ attunementLimit: (_e = overrides.attunement_limit) != null ? _e : Math.max(3, attunementFloor)
627
700
  };
628
701
  }
629
702
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseWeapon
3
- } from "./chunk-HZA7OE7N.js";
3
+ } from "./chunk-XCFC7LGF.js";
4
4
 
5
5
  // src/weapon/weapon.codec.ts
6
6
  import yaml from "js-yaml";
@@ -0,0 +1,14 @@
1
+ // src/pc/spell-source.ts
2
+ var SPELL_SOURCE = {
3
+ class: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false },
4
+ feat: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
5
+ item: { ownAbility: false, section: "consumable", freeCastWhenNoSlot: false, showInPrepare: false, countsAsGranted: true },
6
+ race: { ownAbility: true, section: "spellbook", freeCastWhenNoSlot: true, showInPrepare: true, countsAsGranted: true },
7
+ domain: { ownAbility: false, section: "spellbook", freeCastWhenNoSlot: false, showInPrepare: true, countsAsGranted: false }
8
+ };
9
+ var spellSource = (s) => SPELL_SOURCE[s.source];
10
+
11
+ export {
12
+ SPELL_SOURCE,
13
+ spellSource
14
+ };
@@ -59,6 +59,9 @@ function resolveFeatureResources(features) {
59
59
  }
60
60
  return out;
61
61
  }
62
+ function pickResourceId(entry) {
63
+ return entry.param != null ? entry.key : entry.slug;
64
+ }
62
65
  function resolveResourceIndex(resolved) {
63
66
  var _a, _b, _c, _d, _e;
64
67
  const out = new Map(resolveFeatureResources((_a = resolved.features) != null ? _a : []));
@@ -67,16 +70,18 @@ function resolveResourceIndex(resolved) {
67
70
  const classSlug = (_c = rc == null ? void 0 : rc.entity) == null ? void 0 : _c.slug;
68
71
  if (!classSlug) continue;
69
72
  for (const entry of [...(_d = pool.selected) != null ? _d : [], ...(_e = pool.grants) != null ? _e : []]) {
73
+ if (entry.itemBound === true) continue;
70
74
  const uses = entry.entity.uses;
71
- if (!uses || out.has(entry.slug)) continue;
75
+ const id = pickResourceId(entry);
76
+ if (!uses || out.has(id)) continue;
72
77
  const maxFormula = String(uses.max);
73
78
  if (!isValidMaxFormula(maxFormula)) {
74
79
  warnOnce(`pool-uses:${entry.slug}`, `optional feature "${entry.slug}" has a prose uses.max (${JSON.stringify(uses.max)}); no tracker`);
75
80
  continue;
76
81
  }
77
82
  const pres = entry.entity;
78
- out.set(entry.slug, {
79
- id: entry.slug,
83
+ out.set(id, {
84
+ id,
80
85
  name: entry.entity.name,
81
86
  reset: uses.recharge,
82
87
  maxFormula,
@@ -101,6 +106,7 @@ export {
101
106
  resourceLevelFor,
102
107
  resolveRecovery,
103
108
  resolveFeatureResources,
109
+ pickResourceId,
104
110
  resolveResourceIndex,
105
111
  poolSaveDC
106
112
  };