@archivist-gg/dnd5e 0.3.10 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/LICENSES/SRD.md +38 -3
  2. package/dist/armor/armor.codec.js +3 -3
  3. package/dist/armor/armor.parser.js +2 -2
  4. package/dist/armor/armor.schema.d.ts +1 -0
  5. package/dist/armor/armor.schema.js +1 -1
  6. package/dist/armor/armor.types.d.ts +2 -0
  7. package/dist/background/background.codec.js +5 -5
  8. package/dist/background/background.parser.js +4 -4
  9. package/dist/background/background.schema.js +3 -3
  10. package/dist/chunk-2LULMQTF.js +14 -0
  11. package/dist/{chunk-CBEKVAX4.js → chunk-4BZ47YJ4.js} +10 -3
  12. package/dist/{chunk-22MOUU2G.js → chunk-4SLOJXJ4.js} +1 -1
  13. package/dist/{chunk-2DFENQIJ.js → chunk-5GKJAUMX.js} +2 -0
  14. package/dist/{chunk-J77CKYV3.js → chunk-5KGV6TF7.js} +1 -1
  15. package/dist/{chunk-3UNP3G4D.js → chunk-6ZY3U6BQ.js} +1 -1
  16. package/dist/{chunk-DNAJRMNN.js → chunk-A54HHCWW.js} +6 -7
  17. package/dist/{chunk-2M34FLAY.js → chunk-BRGLDWUP.js} +3 -1
  18. package/dist/chunk-CM5CWO4K.js +735 -0
  19. package/dist/{chunk-MI7P3NX3.js → chunk-DPM6V7YX.js} +2 -2
  20. package/dist/chunk-EJP263OP.js +186 -0
  21. package/dist/{chunk-G247QXWW.js → chunk-EL6QPF6I.js} +1 -1
  22. package/dist/{chunk-SMLXZUBH.js → chunk-EYX4JMAU.js} +4 -1
  23. package/dist/{chunk-AW3EHF3L.js → chunk-FC4IGH5Y.js} +1 -1
  24. package/dist/{chunk-PI4LLJG4.js → chunk-FPGXFD2M.js} +2 -2
  25. package/dist/{chunk-23LZLBJK.js → chunk-G6MHJDVT.js} +6 -2
  26. package/dist/{chunk-NWDF5HG3.js → chunk-G7ED5H2G.js} +1 -1
  27. package/dist/chunk-H5PTKYXL.js +101 -0
  28. package/dist/{chunk-LWFTHJIE.js → chunk-HHBD4SQ6.js} +1 -1
  29. package/dist/{chunk-PP2UHLBA.js → chunk-HJQNK3J5.js} +8 -0
  30. package/dist/{chunk-JC5UNIVM.js → chunk-HS6FIOLP.js} +2 -0
  31. package/dist/chunk-IHE6KVC3.js +13 -0
  32. package/dist/{chunk-BLRW2UU6.js → chunk-J53ERF6K.js} +2 -2
  33. package/dist/{chunk-MQ747UCR.js → chunk-JNNNBEUH.js} +65 -2
  34. package/dist/{chunk-LDDCNPHD.js → chunk-K5NJBTE2.js} +1 -1
  35. package/dist/{chunk-4ISR76DH.js → chunk-KSTV7J2U.js} +9 -3
  36. package/dist/chunk-LBEXLN6I.js +91 -0
  37. package/dist/{chunk-UBBKSYBY.js → chunk-LHZXYFBU.js} +30 -1
  38. package/dist/{chunk-OYUEUKKF.js → chunk-LVX6TQ3R.js} +12 -8
  39. package/dist/{chunk-R747YKS7.js → chunk-M2OWVAZG.js} +1 -1
  40. package/dist/{chunk-7YU4NPKR.js → chunk-MC5YJ4PB.js} +1 -1
  41. package/dist/{chunk-JCEV7KYN.js → chunk-MUIU7RZ3.js} +1 -1
  42. package/dist/{chunk-JSZ4H6AQ.js → chunk-MWCCGPG3.js} +1 -1
  43. package/dist/{chunk-R2ZV233X.js → chunk-MYY2C5MB.js} +3 -3
  44. package/dist/{chunk-S56D6B6C.js → chunk-PLOSP4XQ.js} +3 -3
  45. package/dist/{chunk-JANNRGJC.js → chunk-PX25R3DK.js} +1 -1
  46. package/dist/{chunk-V373TRJE.js → chunk-Q5XTEYHD.js} +191 -125
  47. package/dist/{chunk-MAH6DCRI.js → chunk-Q6UOHCCT.js} +1 -1
  48. package/dist/{chunk-HLQAFZKQ.js → chunk-QEO7LYTG.js} +216 -95
  49. package/dist/{chunk-PJMG5XV3.js → chunk-QSBJ6NEM.js} +1 -1
  50. package/dist/{chunk-BL3VELKP.js → chunk-R2V5LN3I.js} +1 -1
  51. package/dist/{chunk-4DOMDEBZ.js → chunk-RQNJXADQ.js} +1 -1
  52. package/dist/{chunk-GFZ7PITJ.js → chunk-S3YUXDSC.js} +6 -1
  53. package/dist/chunk-T5GZBKIQ.js +927 -0
  54. package/dist/{chunk-PZCE7DJM.js → chunk-UE6LKRXQ.js} +15 -1
  55. package/dist/{chunk-5N2GW72F.js → chunk-UZXG6QSY.js} +2 -1
  56. package/dist/{chunk-QHMWA3SZ.js → chunk-VDPRBUU5.js} +1 -1
  57. package/dist/{chunk-4XTNPNQB.js → chunk-VPYBK2MG.js} +1 -1
  58. package/dist/{chunk-V6LJFP4R.js → chunk-X7VZY4ON.js} +2 -2
  59. package/dist/{chunk-HZA7OE7N.js → chunk-XCFC7LGF.js} +2 -1
  60. package/dist/{chunk-BIA32MQ5.js → chunk-XJRNEQPD.js} +1 -1
  61. package/dist/{chunk-OZP6JFGT.js → chunk-XY6X2APM.js} +3 -1
  62. package/dist/{chunk-UIRMA5KM.js → chunk-YDGMBMYI.js} +1 -1
  63. package/dist/{chunk-6X4KUDMU.js → chunk-ZCTUYGNV.js} +7 -2
  64. package/dist/{chunk-VQAXTIBW.js → chunk-ZDAEGJH4.js} +2 -0
  65. package/dist/{chunk-XTRDCSJB.js → chunk-ZMJQUZQH.js} +4 -1
  66. package/dist/chunk-ZUQW5VBZ.js +89 -0
  67. package/dist/class/class.codec.js +7 -7
  68. package/dist/class/class.parser.js +6 -6
  69. package/dist/class/class.schema.d.ts +10 -0
  70. package/dist/class/class.schema.js +5 -5
  71. package/dist/entities/base-item-resolver.js +2 -2
  72. package/dist/entities/slug.d.ts +18 -8
  73. package/dist/entities/slug.js +3 -1
  74. package/dist/feat/feat.codec.js +5 -5
  75. package/dist/feat/feat.parser.js +4 -4
  76. package/dist/feat/feat.schema.d.ts +16 -3
  77. package/dist/feat/feat.schema.js +3 -3
  78. package/dist/index.js +5277 -2017
  79. package/dist/item/item.actions-map.d.ts +40 -5
  80. package/dist/item/item.actions-map.js +5 -84
  81. package/dist/item/item.attunement.js +3 -9
  82. package/dist/item/item.bonuses.js +5 -2
  83. package/dist/item/item.codec.js +3 -3
  84. package/dist/item/item.conditions.js +4 -1
  85. package/dist/item/item.conditions.types.d.ts +4 -0
  86. package/dist/item/item.cost.d.ts +3 -0
  87. package/dist/item/item.cost.js +29 -0
  88. package/dist/item/item.icon.d.ts +15 -0
  89. package/dist/item/item.icon.js +211 -0
  90. package/dist/item/item.parser.js +2 -2
  91. package/dist/item/item.schema.d.ts +16 -1
  92. package/dist/item/item.schema.js +3 -1
  93. package/dist/item/item.types.d.ts +9 -2
  94. package/dist/monster/monster.parser.js +5 -5
  95. package/dist/monster/monster.schema.js +4 -4
  96. package/dist/optional-feature/optional-feature.codec.js +4 -4
  97. package/dist/optional-feature/optional-feature.parser.js +3 -3
  98. package/dist/optional-feature/optional-feature.schema.d.ts +229 -3
  99. package/dist/optional-feature/optional-feature.schema.js +6 -2
  100. package/dist/pc/pc.additional-spells.js +4 -4
  101. package/dist/pc/pc.asi-flatten.d.ts +62 -1
  102. package/dist/pc/pc.asi-flatten.js +16 -0
  103. package/dist/pc/pc.conditions.js +1 -1
  104. package/dist/pc/pc.containment.d.ts +45 -0
  105. package/dist/pc/pc.containment.js +24 -0
  106. package/dist/pc/pc.decision-engine.d.ts +21 -3
  107. package/dist/pc/pc.decision-engine.js +23 -14
  108. package/dist/pc/pc.entry-overrides.d.ts +79 -0
  109. package/dist/pc/pc.entry-overrides.js +40 -0
  110. package/dist/pc/pc.equipment.d.ts +2 -2
  111. package/dist/pc/pc.equipment.js +18 -7
  112. package/dist/pc/pc.feature-effects.js +2 -2
  113. package/dist/pc/pc.infusions.d.ts +220 -0
  114. package/dist/pc/pc.infusions.js +64 -0
  115. package/dist/pc/pc.parser.js +18 -1
  116. package/dist/pc/pc.pools.d.ts +1 -1
  117. package/dist/pc/pc.pools.js +11 -3
  118. package/dist/pc/pc.proficiencies.js +21 -14
  119. package/dist/pc/pc.recalc.d.ts +39 -36
  120. package/dist/pc/pc.recalc.js +60 -32
  121. package/dist/pc/pc.resolver.js +21 -14
  122. package/dist/pc/pc.resource-seed.js +1 -1
  123. package/dist/pc/pc.resources.d.ts +6 -1
  124. package/dist/pc/pc.resources.js +3 -1
  125. package/dist/pc/pc.rest.d.ts +21 -1
  126. package/dist/pc/pc.rest.js +52 -19
  127. package/dist/pc/pc.schema.d.ts +14 -0
  128. package/dist/pc/pc.schema.js +1 -1
  129. package/dist/pc/pc.slotting.d.ts +36 -3
  130. package/dist/pc/pc.slotting.js +13 -5
  131. package/dist/pc/pc.tool-picks.d.ts +51 -0
  132. package/dist/pc/pc.tool-picks.js +18 -0
  133. package/dist/pc/pc.types.d.ts +70 -12
  134. package/dist/pc/pool-layout.d.ts +14 -0
  135. package/dist/pc/pool-layout.js +7 -3
  136. package/dist/race/race.codec.js +6 -6
  137. package/dist/race/race.parser.js +5 -5
  138. package/dist/race/race.schema.js +4 -4
  139. package/dist/schemas/attack-schema.d.ts +1 -1
  140. package/dist/schemas/choice-schema.js +2 -2
  141. package/dist/schemas/feature-effect-schema.d.ts +16 -3
  142. package/dist/schemas/feature-effect-schema.js +1 -1
  143. package/dist/schemas/feature-schema.js +3 -3
  144. package/dist/schemas/selection-pool-schema.d.ts +10 -0
  145. package/dist/schemas/selection-pool-schema.js +1 -1
  146. package/dist/spell/spell.codec.js +3 -3
  147. package/dist/spell/spell.parser.js +2 -2
  148. package/dist/spell/spell.scaling.d.ts +34 -10
  149. package/dist/spell/spell.scaling.js +36 -4
  150. package/dist/spell/spell.schema.d.ts +1 -0
  151. package/dist/spell/spell.schema.js +1 -1
  152. package/dist/spell/spell.types.d.ts +4 -0
  153. package/dist/srd/retired-items.d.ts +14 -0
  154. package/dist/srd/retired-items.js +11 -0
  155. package/dist/subclass/subclass.codec.js +7 -7
  156. package/dist/subclass/subclass.parser.js +6 -6
  157. package/dist/subclass/subclass.schema.d.ts +10 -0
  158. package/dist/subclass/subclass.schema.js +5 -5
  159. package/dist/types/choice.d.ts +8 -0
  160. package/dist/types/equipment-grant.d.ts +18 -1
  161. package/dist/types/equipment-grant.js +12 -0
  162. package/dist/types/feature-effect.d.ts +6 -1
  163. package/dist/types/optional-feature.types.d.ts +79 -1
  164. package/dist/types/selection-pool.d.ts +16 -1
  165. package/dist/weapon/weapon.classify.d.ts +10 -8
  166. package/dist/weapon/weapon.classify.js +2 -2
  167. package/dist/weapon/weapon.codec.js +3 -3
  168. package/dist/weapon/weapon.parser.js +2 -2
  169. package/dist/weapon/weapon.schema.d.ts +1 -0
  170. package/dist/weapon/weapon.schema.js +1 -1
  171. package/dist/weapon/weapon.types.d.ts +2 -0
  172. package/package.json +1 -1
  173. package/dist/chunk-O4SRD3J5.js +0 -165
  174. package/dist/chunk-WXWPK3LI.js +0 -55
@@ -1,34 +1,43 @@
1
1
  import {
2
2
  classifyWeaponRange
3
- } from "./chunk-UIRMA5KM.js";
4
- import {
5
- defaultSlotForType,
6
- effectiveArmor,
7
- isItemEntity,
8
- isWeaponEntity,
9
- resolveEntityForEntry
10
- } from "./chunk-UBBKSYBY.js";
3
+ } from "./chunk-YDGMBMYI.js";
11
4
  import {
12
5
  normKey
13
6
  } from "./chunk-RLGQ5PZZ.js";
7
+ import {
8
+ WEAPON_DEFAULT_ACTION_COST,
9
+ resolveEntryEntity
10
+ } from "./chunk-T5GZBKIQ.js";
11
+ import {
12
+ resolveContainment
13
+ } from "./chunk-EJP263OP.js";
14
14
  import {
15
15
  readNumericBonus
16
- } from "./chunk-LWFTHJIE.js";
16
+ } from "./chunk-HHBD4SQ6.js";
17
+ import {
18
+ defaultSlotForType,
19
+ effectiveArmor,
20
+ effectiveWeapon,
21
+ isItemEntity,
22
+ isShieldArmor,
23
+ isTwoHandedWeapon,
24
+ slotAcTerms
25
+ } from "./chunk-LHZXYFBU.js";
17
26
  import {
18
27
  resolveBaseItem
19
- } from "./chunk-WXWPK3LI.js";
28
+ } from "./chunk-CM5CWO4K.js";
20
29
  import {
21
30
  bareEntitySlug
22
- } from "./chunk-6X4KUDMU.js";
31
+ } from "./chunk-ZCTUYGNV.js";
23
32
 
24
33
  // src/weapon/weapon-mastery.ts
25
34
  var MASTERY = {
26
35
  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
36
  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
37
  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" },
38
+ 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
39
  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" },
40
+ 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
41
  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
42
  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
43
  };
@@ -75,13 +84,15 @@ function unwrapClassSlug(maybeWiki) {
75
84
  const m = /^\[\[([^\]]+)\]\]$/.exec(maybeWiki);
76
85
  return (m ? m[1] : maybeWiki).toLowerCase();
77
86
  }
78
- function buildConditionContext(resolved, equippedSlots) {
87
+ function buildConditionContext(resolved, equippedSlots, registry) {
79
88
  var _a, _b;
80
89
  return {
81
90
  derived: { equippedSlots },
82
91
  classList: (_a = resolved.definition.class) != null ? _a : [],
83
92
  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)
93
+ subclasses: ((_b = resolved.definition.class) != null ? _b : []).map((c) => c.subclass).filter((s) => typeof s === "string" && s.length > 0).map(unwrapClassSlug),
94
+ // H234 H2: `wielding_two_handed` reads a magic main-hand weapon's base through it.
95
+ registry
85
96
  };
86
97
  }
87
98
  function pushApply(outcome, field, source, pool, onApply) {
@@ -92,29 +103,30 @@ function pushApply(outcome, field, source, pool, onApply) {
92
103
  }
93
104
  }
94
105
  function computeAppliedBonuses(resolved, _profs, registry, warnings) {
95
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
96
107
  const out = emptyAppliedBonuses();
97
108
  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);
109
+ const ctx = buildConditionContext(resolved, {}, registry);
110
+ for (let index = 0; index < equipment.length; index++) {
111
+ const entry = equipment[index];
112
+ const { entity, entityType } = resolveEntryEntity(entry, index, registry, resolved.infusions);
101
113
  if (!entity) {
102
114
  const slug = unwrapSlug(entry.item);
103
- if (slug && entry.equipped) warnings.push(`Equipped item [[${slug}]] not found in compendium.`);
115
+ if (slug && entry.equipped && !((_b = resolved.infusions) == null ? void 0 : _b.views.has(index))) warnings.push(`Equipped item [[${slug}]] not found in compendium.`);
104
116
  continue;
105
117
  }
106
118
  if (!isAttunedActive(entry, entity)) continue;
107
119
  if (entityType !== "item") continue;
108
120
  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;
121
+ (_c = item.resist) == null ? void 0 : _c.forEach((s) => out.defenses.resistances.push(s));
122
+ (_d = item.immune) == null ? void 0 : _d.forEach((s) => out.defenses.immunities.push(s));
123
+ (_e = item.vulnerable) == null ? void 0 : _e.forEach((s) => out.defenses.vulnerabilities.push(s));
124
+ (_f = item.condition_immune) == null ? void 0 : _f.forEach((s) => out.defenses.condition_immunities.push(s));
125
+ (_h = (_g = entry.overrides) == null ? void 0 : _g.resist) == null ? void 0 : _h.forEach((s) => out.defenses.resistances.push(s));
126
+ (_j = (_i = entry.overrides) == null ? void 0 : _i.immune) == null ? void 0 : _j.forEach((s) => out.defenses.immunities.push(s));
127
+ (_l = (_k = entry.overrides) == null ? void 0 : _k.vulnerable) == null ? void 0 : _l.forEach((s) => out.defenses.vulnerabilities.push(s));
128
+ (_n = (_m = entry.overrides) == null ? void 0 : _m.condition_immune) == null ? void 0 : _n.forEach((s) => out.defenses.condition_immunities.push(s));
129
+ const gs = (_o = item.grants) == null ? void 0 : _o.senses;
118
130
  if (gs) {
119
131
  if (typeof gs.darkvision === "number") out.senses.darkvision = Math.max(out.senses.darkvision, gs.darkvision);
120
132
  if (typeof gs.blindsight === "number") out.senses.blindsight = Math.max(out.senses.blindsight, gs.blindsight);
@@ -150,7 +162,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
150
162
  out.spell_save_dc += v;
151
163
  }
152
164
  );
153
- if ((_o = b.ability_scores) == null ? void 0 : _o.bonus) {
165
+ if ((_p = b.ability_scores) == null ? void 0 : _p.bonus) {
154
166
  for (const [k, v] of Object.entries(b.ability_scores.bonus)) {
155
167
  if (!isAbilityKey(k)) continue;
156
168
  pushApply(
@@ -165,7 +177,7 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
165
177
  );
166
178
  }
167
179
  }
168
- if ((_p = b.ability_scores) == null ? void 0 : _p.static) {
180
+ if ((_q = b.ability_scores) == null ? void 0 : _q.static) {
169
181
  for (const [k, n] of Object.entries(b.ability_scores.static)) {
170
182
  if (!isAbilityKey(k) || typeof n !== "number") continue;
171
183
  const prev = out.ability_statics[k];
@@ -227,28 +239,22 @@ function computeAppliedBonuses(resolved, _profs, registry, warnings) {
227
239
  }
228
240
  return out;
229
241
  }
230
- function isTwoHanded(weapon) {
231
- return weapon.properties.some((p) => p === "two_handed");
232
- }
233
242
  function assignSlots(resolved, registry, warnings) {
234
- var _a, _b;
243
+ var _a;
235
244
  const slots = {};
236
245
  const eq = (_a = resolved.definition.equipment) != null ? _a : [];
237
246
  for (let i = 0; i < eq.length; i++) {
238
247
  const entry = eq[i];
239
248
  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
- }
249
+ const { entity, entityType } = resolveEntryEntity(entry, i, registry, resolved.infusions);
250
+ if (slots[entry.slot]) continue;
245
251
  const placed = { index: i, entity, entityType, entry };
246
252
  slots[entry.slot] = placed;
247
253
  }
248
254
  for (let i = 0; i < eq.length; i++) {
249
255
  const entry = eq[i];
250
256
  if (!entry.equipped || entry.slot) continue;
251
- const { entity, entityType } = resolveEntityForEntry(entry.item, registry);
257
+ const { entity, entityType } = resolveEntryEntity(entry, i, registry, resolved.infusions);
252
258
  if (!entity || !entityType) continue;
253
259
  const defaultSlot = defaultSlotForType(entityType, entity, registry);
254
260
  if (!defaultSlot) {
@@ -263,23 +269,45 @@ function assignSlots(resolved, registry, warnings) {
263
269
  if (defaultSlot === "mainhand") {
264
270
  if (!slots.mainhand) slots.mainhand = placed;
265
271
  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
- }
272
+ } else if (!slots[defaultSlot]) {
273
+ slots[defaultSlot] = placed;
273
274
  }
274
275
  }
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
276
  return slots;
280
277
  }
278
+ function pickShield(equippedSlots, equipment, registry, infusions) {
279
+ const slotted = equippedSlots.shield;
280
+ const slottedArmor = effectiveArmor(slotted == null ? void 0 : slotted.entity, registry);
281
+ if (slotted && slottedArmor && isShieldArmor(slottedArmor)) {
282
+ return { index: slotted.index, shield: slottedArmor, entity: slotted.entity, entry: slotted.entry };
283
+ }
284
+ for (let i = 0; i < equipment.length; i++) {
285
+ const entry = equipment[i];
286
+ if (!entry.equipped) continue;
287
+ const { entity } = resolveEntryEntity(entry, i, registry, infusions);
288
+ const armor = effectiveArmor(entity, registry);
289
+ if (armor && isShieldArmor(armor)) return { index: i, shield: armor, entity, entry };
290
+ }
291
+ return null;
292
+ }
293
+ function twoHandedShieldWarnings(equipment, registry, warnings, infusions) {
294
+ const equipped = equipment.flatMap((entry, i) => {
295
+ if (!entry.equipped) return [];
296
+ const { entity } = resolveEntryEntity(entry, i, registry, infusions);
297
+ return [{ entry, entity }];
298
+ });
299
+ const isShield = (e) => {
300
+ const armor = effectiveArmor(e.entity, registry);
301
+ return !!armor && isShieldArmor(armor);
302
+ };
303
+ for (const e of equipped) {
304
+ if (!e.entity || !isTwoHandedWeapon(e.entity, registry)) continue;
305
+ if (!equipped.some((other) => other !== e && isShield(other))) continue;
306
+ warnings.push(`${e.entity.name} is two-handed and a Shield is also equipped.`);
307
+ }
308
+ }
281
309
  function computeAC(equippedSlots, resolved, mods, registry, warnings) {
282
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
310
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
283
311
  const breakdown = [];
284
312
  const armorSlot = equippedSlots.armor;
285
313
  const armorEntity = (_a = armorSlot == null ? void 0 : armorSlot.entity) != null ? _a : null;
@@ -289,13 +317,25 @@ function computeAC(equippedSlots, resolved, mods, registry, warnings) {
289
317
  `Magic armor "${armorEntity.name}" base_item ${armorEntity.base_item} did not resolve to a base armor; AC not applied.`
290
318
  );
291
319
  }
320
+ const acCtx = buildConditionContext(resolved, equippedSlots, registry);
321
+ const skip = /* @__PURE__ */ new Set();
322
+ const slotBonus = (slot) => {
323
+ var _a2, _b2;
324
+ const view = slot ? (_a2 = resolved.infusions) == null ? void 0 : _a2.views.get(slot.index) : void 0;
325
+ if (!slot || !(view == null ? void 0 : view.entity) || !isItemEntity(view.entity) || !isAttunedActive(slot.entry, view.entity)) return 0;
326
+ const out = readNumericBonus((_b2 = view.entity.bonuses) == null ? void 0 : _b2.ac, acCtx);
327
+ if ((out == null ? void 0 : out.kind) !== "applied") return 0;
328
+ skip.add(slot.index);
329
+ return out.value;
330
+ };
331
+ const armorTerms = slotAcTerms(armor, armorSlot == null ? void 0 : armorSlot.entry);
292
332
  let ac = 10;
293
- if (armor) {
294
- const armorBase = armor.ac.base + ((_b = armor.ac.flat) != null ? _b : 0);
333
+ if (armor && armorTerms.armor !== null) {
334
+ const armorBase = armorTerms.armor + slotBonus(armorSlot);
295
335
  ac = armorBase;
296
- breakdown.push({ source: (_c = armorEntity == null ? void 0 : armorEntity.name) != null ? _c : armor.name, amount: armorBase, kind: "armor" });
336
+ breakdown.push({ source: (_b = armorEntity == null ? void 0 : armorEntity.name) != null ? _b : armor.name, amount: armorBase, kind: "armor" });
297
337
  if (armor.ac.add_dex) {
298
- const dexCap = (_d = armor.ac.dex_max) != null ? _d : Number.POSITIVE_INFINITY;
338
+ const dexCap = (_c = armor.ac.dex_max) != null ? _c : Number.POSITIVE_INFINITY;
299
339
  const dexAdd = Math.min(mods.dex, dexCap);
300
340
  ac += dexAdd;
301
341
  const capped = mods.dex > dexCap;
@@ -306,28 +346,34 @@ function computeAC(equippedSlots, resolved, mods, registry, warnings) {
306
346
  breakdown.push({ source: "Base", amount: 10, kind: "unarmored" });
307
347
  breakdown.push({ source: "DEX modifier", amount: mods.dex, kind: "dex" });
308
348
  }
309
- const acBonus = (_e = armorSlot == null ? void 0 : armorSlot.entry.overrides) == null ? void 0 : _e.ac_bonus;
310
- if (typeof acBonus === "number" && acBonus !== 0) {
349
+ const acBonus = armorTerms.override;
350
+ if (acBonus !== 0) {
311
351
  ac += acBonus;
312
- breakdown.push({ source: `${(_f = armorEntity == null ? void 0 : armorEntity.name) != null ? _f : "Armor"} (override)`, amount: acBonus, kind: "override" });
352
+ breakdown.push({ source: `${(_d = armorEntity == null ? void 0 : armorEntity.name) != null ? _d : "Armor"} (override)`, amount: acBonus, kind: "override" });
313
353
  }
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);
354
+ const picked = pickShield(equippedSlots, (_e = resolved.definition.equipment) != null ? _e : [], registry, resolved.infusions);
355
+ if (picked) {
356
+ const { shield, entity: shieldEntity } = picked;
357
+ const shieldTerms = slotAcTerms(shield, picked.entry);
358
+ const n = shieldTerms.armor + slotBonus(picked);
320
359
  ac += n;
321
- breakdown.push({ source: (_k = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _k : shield.name, amount: n, kind: "shield" });
360
+ breakdown.push({ source: (_f = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _f : shield.name, amount: n, kind: "shield" });
361
+ const shieldAcBonus = shieldTerms.override;
362
+ if (shieldAcBonus !== 0) {
363
+ ac += shieldAcBonus;
364
+ breakdown.push({ source: `${(_g = shieldEntity == null ? void 0 : shieldEntity.name) != null ? _g : shield.name} (override)`, amount: shieldAcBonus, kind: "shield" });
365
+ }
322
366
  }
323
367
  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);
368
+ const acEquipment = (_h = resolved.definition.equipment) != null ? _h : [];
369
+ for (let index = 0; index < acEquipment.length; index++) {
370
+ if (skip.has(index)) continue;
371
+ const entry = acEquipment[index];
372
+ const { entity, entityType } = resolveEntryEntity(entry, index, registry, resolved.infusions);
327
373
  if (!entity || entityType !== "item") continue;
328
374
  if (!isAttunedActive(entry, entity)) continue;
329
375
  const item = entity;
330
- const out = readNumericBonus((_m = item.bonuses) == null ? void 0 : _m.ac, acCtx);
376
+ const out = readNumericBonus((_i = item.bonuses) == null ? void 0 : _i.ac, acCtx);
331
377
  if (!out) continue;
332
378
  if (out.kind === "applied") {
333
379
  ac += out.value;
@@ -373,9 +419,9 @@ function isWeaponSlugProficient(weapon, weaponSlug, profs) {
373
419
  }
374
420
  return false;
375
421
  }
376
- function magicBonusesForWeaponEntry(entry, registry, ctx) {
422
+ function magicBonusesForWeaponEntry(entry, registry, ctx, index, infusions) {
377
423
  var _a;
378
- const { entity } = resolveEntityForEntry(entry.item, registry);
424
+ const { entity } = resolveEntryEntity(entry, index, registry, infusions);
379
425
  const ovr = (_a = entry.overrides) != null ? _a : {};
380
426
  const entryAttack = typeof ovr.bonus === "number" ? ovr.bonus : 0;
381
427
  const entryDamage = typeof ovr.damage_bonus === "number" ? ovr.damage_bonus : 0;
@@ -440,8 +486,8 @@ function buildAttackRow(args) {
440
486
  { source: magicSource, amount: magic.dmg, kind: "item" }
441
487
  ];
442
488
  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;
489
+ const fmtRanged = (r) => `${r.normal}/${r.long} ft.`;
490
+ const range = modes.melee ? `${modes.melee.reach} ft.` : modes.ranged ? fmtRanged(modes.ranged) : void 0;
445
491
  const thrownRange = modes.melee && modes.ranged ? fmtRanged(modes.ranged) : void 0;
446
492
  const stringProps = weapon.properties.filter(
447
493
  (p) => typeof p === "string"
@@ -455,14 +501,17 @@ function buildAttackRow(args) {
455
501
  toHit,
456
502
  damageDice,
457
503
  damageType: (_b = magic.damageTypeOverride) != null ? _b : weapon.damage.type,
458
- // Riders: item damage_riders (Task 2) + the migrated manual override string.
504
+ // Riders: item damage_riders (Task 2) + the entry's overrides.extra_damage string. The override
505
+ // rider carries NO source: the player typed it on this very row, so the weapons table attributes it
506
+ // to nothing (no "(manual)" in a caption, no hover title on its chip).
459
507
  ...(() => {
460
508
  const riders = [
461
509
  ...magic.riders,
462
- ...magic.extra ? [{ amount: magic.extra, source: "manual" }] : []
510
+ ...magic.extra ? [{ amount: magic.extra }] : []
463
511
  ];
464
512
  return riders.length ? { damageRiders: riders } : {};
465
513
  })(),
514
+ weaponCategory: modes.melee ? "melee" : "ranged",
466
515
  properties: finalProps,
467
516
  proficient,
468
517
  breakdown: { toHit: toHitBreakdown, damage: damageBreakdown },
@@ -496,7 +545,7 @@ function buildUnarmedRow(mods, proficiencyBonus, spec) {
496
545
  id: "unarmed-strike",
497
546
  name: "Unarmed Strike",
498
547
  unarmed: true,
499
- range: "5 ft",
548
+ range: "5 ft.",
500
549
  toHit,
501
550
  damageDice,
502
551
  damageType: "bludgeoning",
@@ -507,8 +556,10 @@ function buildUnarmedRow(mods, proficiencyBonus, spec) {
507
556
  { source: label, amount: abilityMod, kind: "ability" },
508
557
  { source: "Proficiency bonus", amount: proficiencyBonus, kind: "ability" }
509
558
  ],
559
+ // 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
560
+ // (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
561
  damage: [
511
- { source: "Base damage", amount: 0, kind: "ability" },
562
+ { source: "Base damage", amount: (spec == null ? void 0 : spec.dice) ? 0 : 1, kind: "ability" },
512
563
  { source: label, amount: abilityMod, kind: "ability" }
513
564
  ]
514
565
  },
@@ -528,45 +579,22 @@ function formatWeaponSubLabel(weapon, properties, modes) {
528
579
  if (properties.length > 0) parts.push(properties.map(humanizeWeaponToken).join(", "));
529
580
  return parts.join(" \xB7 ");
530
581
  }
531
- function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities = []) {
532
- var _a, _b, _c, _d, _e;
582
+ function computeAttacks(equippedSlots, equipment, mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities = [], infusions) {
583
+ var _a, _b;
533
584
  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;
585
+ const rowFor = (index, entry, weapon, slotKey, versatileDice) => {
586
+ var _a2, _b2, _c, _d, _e;
587
+ const slugFromEntry = (_a2 = unwrapSlug(entry.item)) != null ? _a2 : weapon.slug;
558
588
  const proficient = isWeaponSlugProficient(weapon, slugFromEntry, profs) || isWeaponSlugProficient(weapon, weapon.slug, profs);
559
589
  if (!proficient) {
560
590
  warnings.push(`Character not proficient with ${weapon.name}; proficiency bonus excluded.`);
561
591
  }
562
592
  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,
593
+ const magic = magicBonusesForWeaponEntry(entry, registry, ctx, index, infusions);
594
+ const ovr = (_b2 = entry.overrides) != null ? _b2 : {};
595
+ return buildAttackRow({
596
+ id: `${index}:standard`,
597
+ name: (_d = (_c = ovr.name) != null ? _c : magic.itemName) != null ? _d : weapon.name,
570
598
  weapon,
571
599
  baseDice: weapon.damage.dice,
572
600
  ability,
@@ -574,13 +602,38 @@ function computeAttacks(equippedSlots, mods, profs, registry, warnings, proficie
574
602
  proficient,
575
603
  proficiencyBonus,
576
604
  magic,
577
- slotKey: key,
578
- actionCost: (_e = ovr.action) != null ? _e : "action",
605
+ slotKey,
606
+ actionCost: (_e = ovr.action) != null ? _e : WEAPON_DEFAULT_ACTION_COST,
579
607
  versatileDice,
580
608
  weaponMasteries
581
609
  });
582
- rows.push(baseRow);
610
+ };
611
+ const handedSlots = [
612
+ { key: "mainhand", placed: equippedSlots.mainhand },
613
+ { key: "offhand", placed: equippedSlots.offhand }
614
+ ];
615
+ for (const { key, placed } of handedSlots) {
616
+ if (!placed) continue;
617
+ const { entity, entry } = placed;
618
+ if (!entity) continue;
619
+ const weapon = effectiveWeapon(entity, registry);
620
+ if (!weapon) {
621
+ if (isItemEntity(entity) && typeof entity.base_item === "string") {
622
+ warnings.push(`Magic weapon ${entity.name} references missing base_item ${entity.base_item}.`);
623
+ }
624
+ continue;
625
+ }
626
+ const versatileDice = key === "mainhand" && hasProperty(weapon, "versatile") && typeof weapon.damage.versatile_dice === "string" && !equippedSlots.offhand ? weapon.damage.versatile_dice : void 0;
627
+ rows.push(rowFor(placed.index, entry, weapon, key, versatileDice));
583
628
  }
629
+ const handIndex = /* @__PURE__ */ new Set([(_a = equippedSlots.mainhand) == null ? void 0 : _a.index, (_b = equippedSlots.offhand) == null ? void 0 : _b.index]);
630
+ equipment.forEach((entry, index) => {
631
+ if (!entry.equipped || handIndex.has(index)) return;
632
+ const { entity } = resolveEntryEntity(entry, index, registry, infusions);
633
+ const weapon = effectiveWeapon(entity, registry);
634
+ if (!weapon) return;
635
+ rows.push(rowFor(index, entry, weapon));
636
+ });
584
637
  return rows;
585
638
  }
586
639
  function coerceWeight(raw) {
@@ -593,25 +646,38 @@ function coerceWeight(raw) {
593
646
  }
594
647
  function computeCarriedWeight(resolved, registry) {
595
648
  var _a;
649
+ const equipment = (_a = resolved.definition.equipment) != null ? _a : [];
650
+ const view = resolveContainment(equipment, registry);
651
+ const weightlessContainer = equipment.map((entry) => {
652
+ var _a2, _b, _c;
653
+ const data = (_a2 = resolveBaseItem(entry.item, registry)) == null ? void 0 : _a2.data;
654
+ return ((_c = (_b = data == null ? void 0 : data.container) == null ? void 0 : _b.capacity) == null ? void 0 : _c.weightless) === true;
655
+ });
656
+ const exempt = (i) => {
657
+ for (let p = view.parentOf[i]; p !== null; p = view.parentOf[p]) if (weightlessContainer[p]) return true;
658
+ return false;
659
+ };
596
660
  let total = 0;
597
- for (const entry of (_a = resolved.definition.equipment) != null ? _a : []) {
661
+ equipment.forEach((entry, i) => {
662
+ if (exempt(i)) return;
598
663
  const found = resolveBaseItem(entry.item, registry);
599
- if (!found) continue;
664
+ if (!found) return;
600
665
  const entity = found.data;
601
666
  const w = coerceWeight(entity.weight);
602
- if (w === 0) continue;
667
+ if (w === 0) return;
603
668
  const qty = typeof entry.qty === "number" && entry.qty >= 0 ? entry.qty : 1;
604
669
  total += w * qty;
605
- }
670
+ });
606
671
  return total;
607
672
  }
608
673
  function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, proficiencyBonus, weaponAbilities = [], weaponMasteries = [], attunementFloor = 0) {
609
- var _a, _b, _c;
674
+ var _a, _b, _c, _d, _e;
610
675
  const equippedSlots = assignSlots(resolved, registry, warnings);
611
- const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
676
+ twoHandedShieldWarnings((_a = resolved.definition.equipment) != null ? _a : [], registry, warnings, resolved.infusions);
677
+ const overrides = (_b = resolved.definition.overrides) != null ? _b : {};
612
678
  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);
679
+ const ctx = buildConditionContext(resolved, equippedSlots, registry);
680
+ const attacks = computeAttacks(equippedSlots, (_c = resolved.definition.equipment) != null ? _c : [], mods, profs, registry, warnings, proficiencyBonus, ctx, weaponMasteries, weaponAbilities, resolved.infusions);
615
681
  return {
616
682
  ac: acOut.ac,
617
683
  acBreakdown: acOut.breakdown,
@@ -620,10 +686,10 @@ function computeSlotsAndAttacks(resolved, mods, profs, registry, warnings, profi
620
686
  equippedSlots,
621
687
  carriedWeight: computeCarriedWeight(resolved, registry),
622
688
  // 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,
689
+ attunementUsed: ((_d = resolved.definition.equipment) != null ? _d : []).filter((e) => e.attuned).length,
624
690
  // PRECEDENCE: an explicit character override wins outright (a number the player typed is intent);
625
691
  // otherwise the baseline 3 is raised — never lowered — by whatever features granted.
626
- attunementLimit: (_c = overrides.attunement_limit) != null ? _c : Math.max(3, attunementFloor)
692
+ attunementLimit: (_e = overrides.attunement_limit) != null ? _e : Math.max(3, attunementFloor)
627
693
  };
628
694
  }
629
695
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseBackground
3
- } from "./chunk-4DOMDEBZ.js";
3
+ } from "./chunk-RQNJXADQ.js";
4
4
 
5
5
  // src/background/background.codec.ts
6
6
  import yaml from "js-yaml";