@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,6 +1,6 @@
1
1
  import {
2
2
  parseSpell
3
- } from "./chunk-XY6X2APM.js";
3
+ } from "./chunk-7Q2VPKCD.js";
4
4
 
5
5
  // src/spell/spell.codec.ts
6
6
  import yaml from "js-yaml";
@@ -9,7 +9,8 @@ var spellCodec = {
9
9
  return parseSpell(doc.body);
10
10
  },
11
11
  serialize(spell) {
12
- return yaml.dump(spell, { lineWidth: -1, sortKeys: false });
12
+ const { material: _material, ...doc } = spell;
13
+ return yaml.dump(doc, { lineWidth: -1, sortKeys: false });
13
14
  }
14
15
  };
15
16
 
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-ZJXSXVFP.js";
5
5
  import {
6
6
  choiceSchema
7
- } from "./chunk-2M34FLAY.js";
7
+ } from "./chunk-5MXFW4O3.js";
8
8
  import {
9
9
  featureEffectSchema
10
- } from "./chunk-XTRDCSJB.js";
10
+ } from "./chunk-2JSQE3DD.js";
11
11
  import {
12
12
  additionalSpellsEntrySchema,
13
13
  imageField,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  optionalFeatureEntitySchema
3
- } from "./chunk-MQ747UCR.js";
3
+ } from "./chunk-DOXSFYLH.js";
4
4
 
5
5
  // src/optional-feature/optional-feature.parser.ts
6
6
  import { parseYaml } from "@archivist-gg/core";
@@ -0,0 +1,84 @@
1
+ import {
2
+ spellSource
3
+ } from "./chunk-KR6JF3BF.js";
4
+ import {
5
+ resourceLevelFor
6
+ } from "./chunk-KSTV7J2U.js";
7
+ import {
8
+ baseClassName
9
+ } from "./chunk-VTTA2ALZ.js";
10
+
11
+ // src/pc/pc.amount-bindings.ts
12
+ function ownerClassSlug(source, resolved) {
13
+ var _a, _b, _c;
14
+ if (!source) return null;
15
+ if (source.kind === "class") return source.slug;
16
+ if (source.kind === "subclass") return (_c = (_b = (_a = resolved.classes.find((c) => {
17
+ var _a2;
18
+ return ((_a2 = c.subclass) == null ? void 0 : _a2.slug) === source.slug;
19
+ })) == null ? void 0 : _a.entity) == null ? void 0 : _b.slug) != null ? _c : null;
20
+ if (source.kind === "feat" && source.via) {
21
+ if (source.via.kind === "class") return source.via.slug;
22
+ if (source.via.kind === "pool") return source.via.classSlug;
23
+ }
24
+ return null;
25
+ }
26
+ function casterRow(classSlug, derived) {
27
+ var _a, _b;
28
+ const rows = (_a = derived.spellcastingClasses) != null ? _a : [];
29
+ const own = classSlug ? rows.find((c) => baseClassName(c.classSlug) === baseClassName(classSlug)) : void 0;
30
+ return (_b = own != null ? own : rows[0]) != null ? _b : null;
31
+ }
32
+ function amountBindingsFor(owner, resolved, derived) {
33
+ const classSlug = ownerClassSlug(owner, resolved);
34
+ const classSource = classSlug ? { kind: "class", slug: classSlug, level: 0 } : owner;
35
+ const classLevel = classSource ? resourceLevelFor(classSource, resolved) : resolved.totalLevel;
36
+ const row = casterRow(classSlug, derived);
37
+ return {
38
+ level: resolved.totalLevel,
39
+ class_level: classLevel,
40
+ prof: derived.proficiencyBonus,
41
+ str_mod: derived.mods.str,
42
+ dex_mod: derived.mods.dex,
43
+ con_mod: derived.mods.con,
44
+ int_mod: derived.mods.int,
45
+ wis_mod: derived.mods.wis,
46
+ cha_mod: derived.mods.cha,
47
+ columns: {},
48
+ ...row ? { spell_mod: derived.mods[row.ability], spell_dc: row.saveDC } : {}
49
+ };
50
+ }
51
+ function spellcastingFor(spell, derived) {
52
+ var _a, _b;
53
+ if ((spellSource(spell).ownAbility || spell.classSlug == null) && spell.ability) {
54
+ const own = (_a = derived.abilitySpellcasting) == null ? void 0 : _a[spell.ability];
55
+ if (own) return { ability: spell.ability, saveDC: own.saveDC, attackBonus: own.attackBonus };
56
+ }
57
+ const row = casterRow((_b = spell.classSlug) != null ? _b : null, derived);
58
+ return row ? { ability: row.ability, saveDC: row.saveDC, attackBonus: row.attackBonus } : null;
59
+ }
60
+ function spellAmountBindings(spell, resolved, derived) {
61
+ const cast = spellcastingFor(spell, derived);
62
+ const base = amountBindingsFor(spell.classSlug ? { kind: "class", slug: spell.classSlug, level: 0 } : void 0, resolved, derived);
63
+ const out = { ...base };
64
+ delete out.spell_mod;
65
+ delete out.spell_dc;
66
+ return cast ? { ...out, spell_mod: derived.mods[cast.ability], spell_dc: cast.saveDC } : out;
67
+ }
68
+ function spellRollBonus(spell) {
69
+ var _a;
70
+ const roll = (_a = spell.damage_roll) == null ? void 0 : _a.trim();
71
+ const text = spell.description;
72
+ if (!roll || !text) return null;
73
+ const esc = roll.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
74
+ const re = new RegExp(`(?<![\\w])${esc}\`?\\s*(?:plus|\\+)\\s*your\\s+spellcasting\\s+(?:ability\\s+)?modifier`, "i");
75
+ return re.test(text) ? "{spell_mod}" : null;
76
+ }
77
+
78
+ export {
79
+ ownerClassSlug,
80
+ amountBindingsFor,
81
+ spellcastingFor,
82
+ spellAmountBindings,
83
+ spellRollBonus
84
+ };
@@ -0,0 +1,158 @@
1
+ import {
2
+ evaluateMaxFormula,
3
+ isValidMaxFormula
4
+ } from "./chunk-EVMUJYUD.js";
5
+
6
+ // src/dnd/amount-text.ts
7
+ var ABILITY_WORD = {
8
+ strength: "str",
9
+ dexterity: "dex",
10
+ constitution: "con",
11
+ intelligence: "int",
12
+ wisdom: "wis",
13
+ charisma: "cha",
14
+ str: "str",
15
+ dex: "dex",
16
+ con: "con",
17
+ int: "int",
18
+ wis: "wis",
19
+ cha: "cha"
20
+ };
21
+ var ABILITY_RE = "(Strength|Dexterity|Constitution|Intelligence|Wisdom|Charisma)";
22
+ var CLASS_RE = "(Artificer|Barbarian|Bard|Cleric|Druid|Fighter|Monk|Paladin|Ranger|Rogue|Sorcerer|Warlock|Wizard)";
23
+ var TOKEN_ALIAS = {
24
+ prof_bonus: "prof",
25
+ proficiency_bonus: "prof",
26
+ spellcasting_mod: "spell_mod",
27
+ spell_save_dc: "spell_dc"
28
+ };
29
+ var IDENT_LABEL = {
30
+ level: "level",
31
+ class_level: "class level",
32
+ prof: "PB",
33
+ str_mod: "STR mod",
34
+ dex_mod: "DEX mod",
35
+ con_mod: "CON mod",
36
+ int_mod: "INT mod",
37
+ wis_mod: "WIS mod",
38
+ cha_mod: "CHA mod",
39
+ spell_mod: "spellcasting mod",
40
+ spell_dc: "spell save DC"
41
+ };
42
+ var abilityToken = (word) => `{${ABILITY_WORD[word.toLowerCase()]}_mod}`;
43
+ var PHRASES = [
44
+ // Save DCs: "your spell save DC", "your sorcerer spell save DC", "the spell save DC from this class's Spellcasting feature".
45
+ [/\b(?:your|the)\s+(?:[a-z]+\s+)?spell save DC(?:\s+from this class's Spellcasting feature)?/gi, "{spell_dc}"],
46
+ // "8 plus your Wisdom modifier and Proficiency Bonus" (2024) / the 2014 order is caught by the rows below.
47
+ [
48
+ new RegExp(`\\b8 plus your ${ABILITY_RE} modifier and (?:your )?Proficiency Bonus`, "gi"),
49
+ (_m, a) => `8 + ${abilityToken(a)} + {prof}`
50
+ ],
51
+ // The spellcasting modifier, in every spelling the notes carry.
52
+ [/\b(?:your\s+)?spellcasting ability modifier\b/gi, "{spell_mod}"],
53
+ [/\b(?:your\s+)?spellcasting modifier\b/gi, "{spell_mod}"],
54
+ [/\b(?:your\s+)?spell(?:casting)? mod\b/gi, "{spell_mod}"],
55
+ // An ability modifier: "your Wisdom modifier", "Intelligence modifier", "WIS mod".
56
+ [new RegExp(`\\b(?:your\\s+)?${ABILITY_RE} modifier\\b`, "gi"), (_m, a) => abilityToken(a)],
57
+ [/\b(STR|DEX|CON|INT|WIS|CHA) mod(?:ifier)?\b/g, (_m, a) => abilityToken(a)],
58
+ // Class level: "half your Warlock level", "your fighter level"; the character's level.
59
+ [new RegExp(`\\bhalf your ${CLASS_RE} level(?:\\s*\\(round(?:ed)? up\\))`, "gi"), "ceil({class_level} / 2)"],
60
+ [new RegExp(`\\bhalf your ${CLASS_RE} level(?:\\s*\\(round(?:ed)? down\\))?`, "gi"), "floor({class_level} / 2)"],
61
+ [/\bhalf your level in this class(?:\s*\(round(?:ed)? up\))/gi, "ceil({class_level} / 2)"],
62
+ [/\bhalf your level in this class(?:\s*\(round(?:ed)? down\))?/gi, "floor({class_level} / 2)"],
63
+ [new RegExp(`\\byour ${CLASS_RE} level\\b`, "gi"), "{class_level}"],
64
+ [/\byour level in this class\b/gi, "{class_level}"],
65
+ [/\byour (?:character )?level\b/gi, "{level}"],
66
+ // Proficiency bonus.
67
+ [/\b(?:your\s+)?proficiency bonus\b/gi, "{prof}"],
68
+ [/\bPB\b/g, "{prof}"]
69
+ ];
70
+ function normalizeAmountPhrases(text) {
71
+ let out = text;
72
+ for (const [re, to] of PHRASES) out = out.replace(re, to);
73
+ if (out === text) return text;
74
+ out = out.replace(/\s+plus\s+/gi, " + ").replace(/\s+minus\s+/gi, " - ").replace(/\btwice (\{[a-z_]+\})/gi, "2 * $1");
75
+ return out;
76
+ }
77
+ var TRAILING_MIN = /\s*\(minimum(?: bonus)? of \+?(\d+)[^)]*\)\s*$/i;
78
+ var DICE = /^\d*d\d+$/i;
79
+ function tidySigns(s) {
80
+ return s.replace(/\+\s*-\s*/g, "- ").replace(/-\s*-\s*/g, "+ ");
81
+ }
82
+ function foldDice(expr) {
83
+ const parts = expr.replace(/\s+/g, "").match(/[+-]?[^+-]+/g);
84
+ if (!parts) return null;
85
+ const dice = [];
86
+ let sum = 0;
87
+ for (const raw of parts) {
88
+ const sign = raw.startsWith("-") ? -1 : 1;
89
+ const body = raw.replace(/^[+-]/, "");
90
+ if (DICE.test(body)) {
91
+ if (sign < 0) return null;
92
+ dice.push(body.toLowerCase());
93
+ continue;
94
+ }
95
+ if (!isValidMaxFormula(body)) return null;
96
+ sum += sign * evaluateMaxFormula(body, ZERO_BINDINGS);
97
+ }
98
+ if (dice.length === 0) return null;
99
+ const n = Math.trunc(sum);
100
+ return `${dice.join("+")}${n > 0 ? `+${n}` : n < 0 ? `${n}` : ""}`;
101
+ }
102
+ var ZERO_BINDINGS = {
103
+ level: 0,
104
+ class_level: 0,
105
+ prof: 0,
106
+ str_mod: 0,
107
+ dex_mod: 0,
108
+ con_mod: 0,
109
+ int_mod: 0,
110
+ wis_mod: 0,
111
+ cha_mod: 0,
112
+ columns: {}
113
+ };
114
+ function resolveAmountText(text, b) {
115
+ const normalized = normalizeAmountPhrases(text);
116
+ if (!normalized.includes("{")) return text;
117
+ const values = b;
118
+ let unbound = false;
119
+ const substitute = (numeric2) => normalized.replace(/\{([a-z_]+)\}/g, (_m, raw) => {
120
+ var _a, _b;
121
+ const id = (_a = TOKEN_ALIAS[raw]) != null ? _a : raw;
122
+ const v = values[id];
123
+ if (typeof v !== "number" || !Number.isFinite(v)) {
124
+ unbound = true;
125
+ return (_b = IDENT_LABEL[id]) != null ? _b : raw;
126
+ }
127
+ return numeric2 && v < 0 ? `(0 - ${-v})` : String(v);
128
+ });
129
+ const display = tidySigns(substitute(false));
130
+ if (unbound) return text.includes("{") ? display : text;
131
+ const min = TRAILING_MIN.exec(display);
132
+ const minText = min ? display.slice(min.index) : "";
133
+ const numeric = substitute(true);
134
+ const numericCore = numeric.replace(TRAILING_MIN, "");
135
+ if (isValidMaxFormula(numericCore)) {
136
+ const v = evaluateMaxFormula(numericCore, ZERO_BINDINGS);
137
+ return String(Math.trunc(min ? Math.max(Number(min[1]), v) : v));
138
+ }
139
+ const roll = foldDice(min ? display.slice(0, min.index) : display);
140
+ if (roll) return `${roll}${minText}`;
141
+ if (/\b(?:floor|ceil|max|min)\(/.test(display)) return text;
142
+ return display;
143
+ }
144
+ function diceRollOf(resolved) {
145
+ var _a, _b;
146
+ return (_b = (_a = diceRollPrefix(resolved)) == null ? void 0 : _a.notation) != null ? _b : null;
147
+ }
148
+ function diceRollPrefix(text) {
149
+ const m = /^(\d*d\d+(?:\s*[+-]\s*\d+)*)(?=\s|$)/i.exec(text);
150
+ return m ? { raw: m[1], notation: m[1].replace(/\s+/g, "") } : null;
151
+ }
152
+
153
+ export {
154
+ normalizeAmountPhrases,
155
+ resolveAmountText,
156
+ diceRollOf,
157
+ diceRollPrefix
158
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseSubclass
3
- } from "./chunk-J77CKYV3.js";
3
+ } from "./chunk-OFCSP6MT.js";
4
4
 
5
5
  // src/subclass/subclass.codec.ts
6
6
  import yaml from "js-yaml";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseFeat
3
- } from "./chunk-T2SNEJOE.js";
3
+ } from "./chunk-7QN7XSAK.js";
4
4
 
5
5
  // src/feat/feat.codec.ts
6
6
  import yaml from "js-yaml";
@@ -174,8 +174,9 @@ var containerCapacitySchema = z.strictObject({
174
174
  });
175
175
  var containerSchema = z.object({
176
176
  capacity_weight: z.number().optional(),
177
- weightless: z.boolean().optional(),
177
+ holds_items: z.boolean().optional(),
178
178
  pack_contents: z.array(z.string()).optional(),
179
+ pack_atomic: z.boolean().optional(),
179
180
  capacity: containerCapacitySchema.optional()
180
181
  });
181
182
  var lightSchema = z.object({
@@ -206,6 +207,7 @@ var itemEntitySchema = z.object({
206
207
  light: z.union([lightSchema, z.array(lightEntrySchema).nonempty()]).optional(),
207
208
  cursed: z.boolean().optional(),
208
209
  sentient: z.boolean().optional(),
210
+ tattoo: z.boolean().optional(),
209
211
  // 54 docs carry a LIST of classes that may use the item as a focus
210
212
  // (e.g. ["Druid", "Ranger"]); 26 carry a single string, 2 a boolean.
211
213
  focus: z.union([z.boolean(), z.string(), z.array(z.string())]).optional(),
@@ -254,6 +256,8 @@ var itemEntitySchema = z.object({
254
256
  // Carried by all 6,046 converter item docs, ALWAYS as the empty string today:
255
257
  // `.min(1)` is forbidden here.
256
258
  rendering_hint: z.string().optional(),
259
+ // The icon key (I3): a key of the renderer's icon set or a Lucide name; itemIconKey reads it first.
260
+ icon: z.string().optional(),
257
261
  has_fluff: z.boolean().optional(),
258
262
  has_fluff_images: z.boolean().optional(),
259
263
  // Already `.optional()` at its source — never append a second one.
@@ -269,5 +273,6 @@ var itemEntitySchema = z.object({
269
273
 
270
274
  export {
271
275
  conditionSchema,
276
+ containerSchema,
272
277
  itemEntitySchema
273
278
  };
@@ -65,6 +65,17 @@ var equipmentEntryStateSchema = z.object({
65
65
  effect: z.string()
66
66
  }).optional()
67
67
  }).strict();
68
+ var entryRefField = z.preprocess(
69
+ (v) => typeof v === "number" ? String(v) : typeof v === "string" && v.length > 0 ? v : void 0,
70
+ z.string().optional()
71
+ );
72
+ var infusionMarkerSchema = z.object({
73
+ kind: z.enum(["infused", "created"]),
74
+ by: z.string().min(1),
75
+ seq: z.number().int().min(1),
76
+ choice: z.string().min(1).optional(),
77
+ charges: z.object({ current: z.number().int().nonnegative() }).optional()
78
+ });
68
79
  var equipmentEntrySchema = z.object({
69
80
  item: z.string().min(1),
70
81
  equipped: z.boolean().optional(),
@@ -77,7 +88,10 @@ var equipmentEntrySchema = z.object({
77
88
  // Build-only provenance for Equipment-step-seeded gear (e.g. "builder:starting",
78
89
  // "builder:gold-buy"). Permissive plain string; stripped by finishBuild so a
79
90
  // finished file never carries it.
80
- granted_by: z.string().optional()
91
+ granted_by: z.string().optional(),
92
+ id: entryRefField,
93
+ in: entryRefField,
94
+ infusion: infusionMarkerSchema.optional()
81
95
  });
82
96
  var characterOverridesShape = z.object({
83
97
  scores: z.partialRecord(abilityEnum, z.number().int()).optional(),
@@ -237,6 +251,21 @@ var knownSpellObjectSchema = z.object({
237
251
  always_prepared: z.boolean().optional()
238
252
  }).strict();
239
253
  var knownSpellEntrySchema = z.union([z.string().min(1), knownSpellObjectSchema]);
254
+ var sheetViewFilterSchema = z.object({
255
+ show: z.array(z.string().min(1)).optional(),
256
+ hide: z.array(z.string().min(1)).optional()
257
+ });
258
+ var sheetPoolViewSchema = z.object({
259
+ show: z.enum(["known", "granted", "not-known"]).optional().catch(void 0),
260
+ off: z.record(z.string(), z.array(z.string())).optional(),
261
+ folded: z.array(z.string().min(1)).optional()
262
+ });
263
+ var sheetStateSchema = z.object({
264
+ layout: z.object({ saves: z.enum(["section"]).optional().catch(void 0) }).optional(),
265
+ favorites: z.array(z.string().min(1)).optional(),
266
+ filters: z.object({ actions: sheetViewFilterSchema.optional(), passive: sheetViewFilterSchema.optional() }).optional(),
267
+ pools: z.record(z.string(), sheetPoolViewSchema).optional()
268
+ });
240
269
  var characterSchema = z.object({
241
270
  name: z.string().min(1),
242
271
  edition: z.enum(["2014", "2024"]),
@@ -309,6 +338,7 @@ var characterSchema = z.object({
309
338
  vulnerabilities: z.array(z.string()).default([]),
310
339
  condition_immunities: z.array(z.string()).default([])
311
340
  }).partial().optional(),
341
+ sheet: sheetStateSchema.optional(),
312
342
  state: characterStateSchema
313
343
  });
314
344
 
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-LVQLWRCU.js";
10
10
  import {
11
11
  bareEntitySlug
12
- } from "./chunk-6X4KUDMU.js";
12
+ } from "./chunk-ZCTUYGNV.js";
13
13
  import {
14
14
  normalizeAbility
15
15
  } from "./chunk-WELIKLZF.js";
@@ -20,6 +20,7 @@ function emptyFeatureEffectTotals() {
20
20
  initiative_bonus: 0,
21
21
  initiative_terms: [],
22
22
  skill_bonus_terms: [],
23
+ save_bonus_terms: [],
23
24
  half_proficiency_terms: [],
24
25
  hp_per_level_bonus: 0,
25
26
  hp_per_level_terms: [],
@@ -88,7 +89,7 @@ function assembleEffectFeatures(resolved) {
88
89
  const pushBoon = (item, pool) => {
89
90
  var _a2, _b2, _c2, _d2, _e2, _f2, _g2;
90
91
  const e = item.entity;
91
- if (!e || ((_b2 = (_a2 = e.effects) == null ? void 0 : _a2.length) != null ? _b2 : 0) === 0) return;
92
+ if (!e || item.itemBound === true || ((_b2 = (_a2 = e.effects) == null ? void 0 : _a2.length) != null ? _b2 : 0) === 0) return;
92
93
  buffFeatures.push({
93
94
  feature: { id: item.slug, name: e.name, activatable: (_c2 = e.activatable) != null ? _c2 : false, effects: e.effects },
94
95
  // source is inert for the fold; attribute to the pool's owning class
@@ -118,7 +119,7 @@ function computeFeatureEffects(features, opts) {
118
119
  if (!foldsNow(rf, (_a = opts == null ? void 0 : opts.activeBuffs) != null ? _a : /* @__PURE__ */ new Set())) continue;
119
120
  const level = (_b = opts == null ? void 0 : opts.levelFor) == null ? void 0 : _b.call(opts, rf.source);
120
121
  for (const eff of selfEffectsOf(rf.feature)) {
121
- applyEffect(out, eff, (_c = rf.feature.name) != null ? _c : "Feature", level);
122
+ applyEffect(out, columnScaledRider(eff, rf, level, opts == null ? void 0 : opts.tableDiceFor), (_c = rf.feature.name) != null ? _c : "Feature", level, rf.source);
122
123
  }
123
124
  }
124
125
  return out;
@@ -182,8 +183,23 @@ function scaled(base, key, scalesAt, level) {
182
183
  }
183
184
  return best;
184
185
  }
185
- function applyEffect(out, eff, label, level) {
186
- var _a, _b, _c, _d, _e, _f, _g, _h;
186
+ function columnScaledRider(eff, rf, level, tableDiceFor) {
187
+ if (eff.kind !== "damage-bonus" || level === void 0 || !tableDiceFor) return eff;
188
+ const src = rf.source;
189
+ const column = rf.feature.name;
190
+ if (src.kind !== "class" && src.kind !== "subclass" || !column) return eff;
191
+ const atGain = tableDiceFor(src, column, src.level);
192
+ if (!atGain || atGain.toLowerCase() !== eff.amount.trim().toLowerCase()) return eff;
193
+ const now = tableDiceFor(src, column, level);
194
+ return now ? { ...eff, amount: now } : eff;
195
+ }
196
+ function riderScope(appliesTo) {
197
+ if (appliesTo === void 0 || appliesTo === "all" || appliesTo === "spell") return void 0;
198
+ const words = Array.isArray(appliesTo) ? appliesTo : [appliesTo];
199
+ return words.includes("weapon") ? void 0 : [...words];
200
+ }
201
+ function applyEffect(out, eff, label, level, owner) {
202
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
187
203
  switch (eff.kind) {
188
204
  case "initiative-bonus":
189
205
  out.initiative_bonus += eff.value;
@@ -197,10 +213,19 @@ function applyEffect(out, eff, label, level) {
197
213
  label
198
214
  });
199
215
  break;
216
+ case "save-bonus":
217
+ out.save_bonus_terms.push({
218
+ saves: [...(_b = eff.saves) != null ? _b : []],
219
+ ability: eff.ability,
220
+ minimum: (_c = eff.minimum) != null ? _c : 0,
221
+ ...eff.inactive_while ? { inactiveWhile: eff.inactive_while } : {},
222
+ label
223
+ });
224
+ break;
200
225
  case "half-proficiency":
201
226
  out.half_proficiency_terms.push({
202
- skills: ((_b = eff.skills) != null ? _b : []).map(toProfSlug),
203
- round: (_c = eff.round) != null ? _c : "down",
227
+ skills: ((_d = eff.skills) != null ? _d : []).map(toProfSlug),
228
+ round: (_e = eff.round) != null ? _e : "down",
204
229
  label
205
230
  });
206
231
  break;
@@ -267,7 +292,7 @@ function applyEffect(out, eff, label, level) {
267
292
  }
268
293
  case "roll-modifier": {
269
294
  const rolls = eff.roll === "any" ? ["ability-check", "saving-throw", "attack"] : [eff.roll];
270
- const scopes = (_d = normalizeRollScope(eff.scope, rolls[0])) != null ? _d : [eff.scope];
295
+ const scopes = (_f = normalizeRollScope(eff.scope, rolls[0])) != null ? _f : [eff.scope];
271
296
  for (const roll of rolls) for (const scope of scopes)
272
297
  out.rollModifiers.push({ mode: eff.mode, roll, scope, condition: eff.condition, label });
273
298
  break;
@@ -277,13 +302,13 @@ function applyEffect(out, eff, label, level) {
277
302
  ability: eff.ability === "any" ? void 0 : eff.ability,
278
303
  on_success: eff.on_success,
279
304
  on_failure: eff.on_failure,
280
- appliesTo: (_e = eff.applies_to) != null ? _e : void 0,
305
+ appliesTo: (_g = eff.applies_to) != null ? _g : void 0,
281
306
  condition: eff.condition,
282
307
  label
283
308
  });
284
309
  break;
285
310
  case "crit-range":
286
- if (((_f = eff.applies_to) != null ? _f : "weapon") !== "spell") out.critRange = Math.min(out.critRange, eff.min_roll);
311
+ if (((_h = eff.applies_to) != null ? _h : "weapon") !== "spell") out.critRange = Math.min(out.critRange, eff.min_roll);
287
312
  break;
288
313
  case "extra-attack":
289
314
  out.extraAttack = Math.max(out.extraAttack, scaled(eff.count, "count", eff.scales_at, level));
@@ -295,18 +320,21 @@ function applyEffect(out, eff, label, level) {
295
320
  if (eff.flag === "no-ranged-in-melee-disadvantage") out.attackNotes.push("No disadvantage firing in melee");
296
321
  break;
297
322
  case "damage-bonus":
298
- if (((_g = eff.applies_to) != null ? _g : "weapon") !== "spell") {
323
+ if (((_i = eff.applies_to) != null ? _i : "weapon") !== "spell") {
324
+ const scope = riderScope(eff.applies_to);
299
325
  out.damageBonuses.push({
300
326
  amount: eff.amount,
301
327
  damage_type: eff.damage_type,
302
328
  source: label,
303
- ...eff.condition ? { condition: eff.condition } : {}
329
+ ...eff.condition ? { condition: eff.condition } : {},
330
+ ...scope ? { scope } : {},
331
+ ...owner ? { owner } : {}
304
332
  });
305
333
  }
306
334
  break;
307
335
  case "ability-score-increase":
308
336
  if (eff.abilities === "chosen") break;
309
- for (const ab of eff.abilities) out.ability_bonus[ab] = ((_h = out.ability_bonus[ab]) != null ? _h : 0) + eff.amount;
337
+ for (const ab of eff.abilities) out.ability_bonus[ab] = ((_j = out.ability_bonus[ab]) != null ? _j : 0) + eff.amount;
310
338
  break;
311
339
  default:
312
340
  break;
@@ -2,13 +2,13 @@ import {
2
2
  poolGrantSchema,
3
3
  selectionPoolSchema,
4
4
  tabDeclSchema
5
- } from "./chunk-23LZLBJK.js";
5
+ } from "./chunk-G6MHJDVT.js";
6
6
  import {
7
7
  casterTypeEnum
8
8
  } from "./chunk-CJYCVNW2.js";
9
9
  import {
10
10
  featureSchema
11
- } from "./chunk-PI4LLJG4.js";
11
+ } from "./chunk-YD2VAHA6.js";
12
12
  import {
13
13
  resourceSchema
14
14
  } from "./chunk-ZJXSXVFP.js";
@@ -18,7 +18,7 @@ import {
18
18
  } from "./chunk-IN4M4X7P.js";
19
19
  import {
20
20
  choiceSchema
21
- } from "./chunk-2M34FLAY.js";
21
+ } from "./chunk-5MXFW4O3.js";
22
22
  import {
23
23
  additionalSpellsEntrySchema,
24
24
  imageField,
@@ -110,6 +110,15 @@ var classEntitySchema = z.object({
110
110
  description: z.string(),
111
111
  hit_die: hitDieEnum,
112
112
  primary_abilities: z.array(abilityEnum).nonempty(),
113
+ // D2b-A (A-1): the class's recommended Standard Array (SRD 5.2 "Standard Array by Class"); absent on 2014 classes.
114
+ standard_array: z.strictObject({
115
+ str: z.number().int(),
116
+ dex: z.number().int(),
117
+ con: z.number().int(),
118
+ int: z.number().int(),
119
+ wis: z.number().int(),
120
+ cha: z.number().int()
121
+ }).optional(),
113
122
  saving_throws: z.array(abilityEnum).length(2),
114
123
  proficiencies: z.object({
115
124
  armor: z.array(armorCategoryEnum),
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  armorEntitySchema
3
- } from "./chunk-JC5UNIVM.js";
3
+ } from "./chunk-HS6FIOLP.js";
4
4
 
5
5
  // src/armor/armor.parser.ts
6
6
  import { parseYaml } from "@archivist-gg/core";
@@ -23,6 +23,7 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
23
23
  // enough: this set is the second, independent gate — a key missing here is copied into
24
24
  // `raw` as well, so the two lists must move together.
25
25
  "rendering_hint",
26
+ "icon",
26
27
  "has_fluff",
27
28
  "has_fluff_images",
28
29
  "image",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseItem
3
- } from "./chunk-SMLXZUBH.js";
3
+ } from "./chunk-EYX4JMAU.js";
4
4
 
5
5
  // src/item/item.codec.ts
6
6
  import yaml from "js-yaml";
@@ -6,10 +6,10 @@ import {
6
6
  } from "./chunk-LVQLWRCU.js";
7
7
  import {
8
8
  slugify
9
- } from "./chunk-6X4KUDMU.js";
9
+ } from "./chunk-ZCTUYGNV.js";
10
10
  import {
11
11
  mirrorSpellShapes
12
- } from "./chunk-XY6X2APM.js";
12
+ } from "./chunk-7Q2VPKCD.js";
13
13
  import {
14
14
  ABILITY_KEYS
15
15
  } from "./chunk-WELIKLZF.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  weaponEntitySchema
3
- } from "./chunk-2DFENQIJ.js";
3
+ } from "./chunk-5GKJAUMX.js";
4
4
 
5
5
  // src/weapon/weapon.parser.ts
6
6
  import { parseYaml } from "@archivist-gg/core";
@@ -26,6 +26,7 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
26
26
  // enough: this set is the second, independent gate — a key missing here is copied into
27
27
  // `raw` as well, so the two lists must move together.
28
28
  "rendering_hint",
29
+ "icon",
29
30
  "has_fluff",
30
31
  "has_fluff_images",
31
32
  "image"
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raceEntitySchema
3
- } from "./chunk-V6LJFP4R.js";
3
+ } from "./chunk-FANQVQ3D.js";
4
4
  import {
5
5
  aliasFeatureListActionCost
6
6
  } from "./chunk-4U55VNC7.js";
@@ -8,10 +8,10 @@ import {
8
8
  } from "./chunk-ZJXSXVFP.js";
9
9
  import {
10
10
  choiceSchema
11
- } from "./chunk-2M34FLAY.js";
11
+ } from "./chunk-5MXFW4O3.js";
12
12
  import {
13
13
  featureEffectSchema
14
- } from "./chunk-XTRDCSJB.js";
14
+ } from "./chunk-2JSQE3DD.js";
15
15
 
16
16
  // src/schemas/feature-schema.ts
17
17
  import { z as z2 } from "zod";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  bareEntitySlug
3
- } from "./chunk-6X4KUDMU.js";
3
+ } from "./chunk-ZCTUYGNV.js";
4
4
 
5
5
  // src/weapon/weapon.classify.ts
6
6
  var PURE_RANGED_THROWN_SLUGS = /* @__PURE__ */ new Set(["dart", "net"]);
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-4U55VNC7.js";
4
4
  import {
5
5
  classEntitySchema
6
- } from "./chunk-S56D6B6C.js";
6
+ } from "./chunk-UUBJCNQU.js";
7
7
 
8
8
  // src/class/class.parser.ts
9
9
  import { parseYaml } from "@archivist-gg/core";