@archivist-gg/dnd5e 0.3.1 → 0.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/LICENSES/SRD.md +25 -6
  2. package/dist/armor/armor.codec.js +4 -3
  3. package/dist/armor/armor.parser.js +3 -2
  4. package/dist/armor/armor.schema.d.ts +4 -0
  5. package/dist/armor/armor.schema.js +2 -1
  6. package/dist/armor/armor.types.d.ts +8 -0
  7. package/dist/background/background.codec.js +7 -6
  8. package/dist/background/background.parser.js +6 -5
  9. package/dist/background/background.schema.d.ts +26 -0
  10. package/dist/background/background.schema.js +5 -4
  11. package/dist/background/background.types.d.ts +22 -0
  12. package/dist/{chunk-4TIJKN6O.js → chunk-23LZLBJK.js} +1 -1
  13. package/dist/{chunk-AFKTJXRA.js → chunk-2DFENQIJ.js} +18 -0
  14. package/dist/chunk-2FRUSVZS.js +489 -0
  15. package/dist/chunk-2VDTW7QO.js +1580 -0
  16. package/dist/{chunk-ZZGEVJKX.js → chunk-3JOTQW7A.js} +1 -1
  17. package/dist/{chunk-5ZBE4CWV.js → chunk-3PZHBLFG.js} +1 -1
  18. package/dist/chunk-4U55VNC7.js +22 -0
  19. package/dist/{chunk-4JHOHWBI.js → chunk-4XTNPNQB.js} +1 -1
  20. package/dist/{chunk-HCP3GMHS.js → chunk-5N2GW72F.js} +15 -2
  21. package/dist/{chunk-42Y5IJKT.js → chunk-5RKLL2AD.js} +5 -1
  22. package/dist/{chunk-SE7AZDR3.js → chunk-63XQXPZL.js} +29 -3
  23. package/dist/{chunk-4F6AIZ36.js → chunk-6BFWZW6T.js} +1 -1
  24. package/dist/{chunk-GJOI2GHP.js → chunk-6GNXYAYP.js} +1 -1
  25. package/dist/{chunk-66XXW2Z2.js → chunk-6PXTNCBP.js} +2 -2
  26. package/dist/chunk-6X2NV665.js +33 -0
  27. package/dist/{chunk-LV4SNWZQ.js → chunk-6X4KUDMU.js} +8 -1
  28. package/dist/{chunk-ZMR77DDL.js → chunk-AW3EHF3L.js} +1 -1
  29. package/dist/{chunk-TLYDBT5F.js → chunk-CGRLQ34U.js} +64 -7
  30. package/dist/chunk-CJYCVNW2.js +7 -0
  31. package/dist/{chunk-XLSVNUTK.js → chunk-CV5XDJKU.js} +1 -1
  32. package/dist/{chunk-RAWJTA45.js → chunk-DEEHHLAP.js} +1 -1
  33. package/dist/{chunk-6IRYTM5V.js → chunk-DPUJDOKV.js} +119 -28
  34. package/dist/{chunk-GE4TLPWM.js → chunk-EHDATXP7.js} +1 -1
  35. package/dist/chunk-EVMUJYUD.js +195 -0
  36. package/dist/{chunk-K6Q5OUGK.js → chunk-GFZ7PITJ.js} +86 -10
  37. package/dist/{chunk-6NK2MUD3.js → chunk-HZA7OE7N.js} +9 -2
  38. package/dist/{chunk-TN6ZLTNU.js → chunk-I2NDWFDD.js} +51 -4
  39. package/dist/{chunk-3DZ74AKK.js → chunk-IN4M4X7P.js} +8 -2
  40. package/dist/chunk-IUAAXXNO.js +58 -0
  41. package/dist/{chunk-NXSWH3AE.js → chunk-IWRVOCT5.js} +1 -1
  42. package/dist/{chunk-XJNECUPT.js → chunk-JC5UNIVM.js} +19 -0
  43. package/dist/{chunk-24GFQU7T.js → chunk-JSZ4H6AQ.js} +1 -1
  44. package/dist/{chunk-XTIQWSFM.js → chunk-KADJZGZY.js} +1 -1
  45. package/dist/{chunk-L7E2UT5A.js → chunk-KK33PIDN.js} +5 -1
  46. package/dist/chunk-KPEJMNRD.js +302 -0
  47. package/dist/chunk-KU3YLF6D.js +106 -0
  48. package/dist/{chunk-5INR4NSL.js → chunk-LDDCNPHD.js} +1 -1
  49. package/dist/chunk-LVQLWRCU.js +15 -0
  50. package/dist/chunk-MI7P3NX3.js +161 -0
  51. package/dist/{chunk-PHQRGDRQ.js → chunk-N3A5ICBO.js} +5 -1
  52. package/dist/chunk-O4SRD3J5.js +165 -0
  53. package/dist/chunk-OAXWSVJB.js +81 -0
  54. package/dist/chunk-OZP6JFGT.js +162 -0
  55. package/dist/{chunk-NAEPSZAM.js → chunk-PDJSUH24.js} +24 -2
  56. package/dist/chunk-PP2UHLBA.js +50 -0
  57. package/dist/chunk-PVCEA4HZ.js +6 -0
  58. package/dist/{chunk-RSDRMH54.js → chunk-RF4TYCA2.js} +1 -1
  59. package/dist/chunk-RLGQ5PZZ.js +16 -0
  60. package/dist/chunk-RVXC6ZHY.js +89 -0
  61. package/dist/chunk-S7REMWW4.js +21 -0
  62. package/dist/{chunk-7VJ6BOA5.js → chunk-SMLXZUBH.js} +9 -1
  63. package/dist/chunk-TOM66P2P.js +38 -0
  64. package/dist/chunk-UA5KS2PL.js +26 -0
  65. package/dist/{chunk-N6N74K6X.js → chunk-UBBKSYBY.js} +1 -1
  66. package/dist/{chunk-353WXS6S.js → chunk-UIRMA5KM.js} +1 -1
  67. package/dist/{chunk-BIK4DFWK.js → chunk-ULCQ73LA.js} +1 -1
  68. package/dist/{chunk-2BWAID3Y.js → chunk-UMWIPLLM.js} +29 -3
  69. package/dist/chunk-UQ3ZFCWD.js +178 -0
  70. package/dist/chunk-UXPGW4TI.js +101 -0
  71. package/dist/chunk-V2MJE6NC.js +133 -0
  72. package/dist/{chunk-D3CLOBE3.js → chunk-V373TRJE.js} +48 -10
  73. package/dist/chunk-VQAXTIBW.js +100 -0
  74. package/dist/chunk-W74BCA7V.js +159 -0
  75. package/dist/{chunk-WP2CX2JO.js → chunk-WELIKLZF.js} +22 -1
  76. package/dist/{chunk-MDEJHMKK.js → chunk-WHVLNFTG.js} +26 -5
  77. package/dist/{chunk-GZ46OVGZ.js → chunk-WSVMLNTO.js} +1 -1
  78. package/dist/{chunk-4LZJXJJS.js → chunk-WXWPK3LI.js} +6 -2
  79. package/dist/chunk-X3D6LXUU.js +185 -0
  80. package/dist/chunk-XJ2F2WO6.js +8 -0
  81. package/dist/{chunk-73HOFQQ5.js → chunk-Y4AGLCY6.js} +1 -1
  82. package/dist/chunk-YBLDE5CG.js +42 -0
  83. package/dist/{chunk-JEYQU3JT.js → chunk-YHYTW5QA.js} +2 -18
  84. package/dist/{chunk-PZOWBI3B.js → chunk-YLL2QXY2.js} +7 -2
  85. package/dist/class/class.codec.js +12 -9
  86. package/dist/class/class.parser.js +11 -8
  87. package/dist/class/class.schema.d.ts +55 -3
  88. package/dist/class/class.schema.js +9 -7
  89. package/dist/class/class.types.d.ts +48 -3
  90. package/dist/condition/condition.codec.d.ts +9 -0
  91. package/dist/condition/condition.entity-type.d.ts +2 -0
  92. package/dist/condition/condition.parser.d.ts +13 -0
  93. package/dist/condition/condition.parser.js +7 -0
  94. package/dist/condition/condition.schema.d.ts +29 -0
  95. package/dist/condition/condition.types.d.ts +15 -0
  96. package/dist/condition/condition.types.js +0 -0
  97. package/dist/dnd/constants.d.ts +22 -0
  98. package/dist/dnd/constants.js +9 -3
  99. package/dist/dnd/formula-tags.js +2 -2
  100. package/dist/dnd/math.d.ts +26 -0
  101. package/dist/dnd/math.js +12 -2
  102. package/dist/dnd/prose-tags.js +1 -1
  103. package/dist/dnd/resource-formula.d.ts +36 -10
  104. package/dist/dnd/resource-formula.js +10 -155
  105. package/dist/dnd/srd-tag-converter.js +3 -3
  106. package/dist/dnd/tag-grammar.js +1 -1
  107. package/dist/dnd/warn-once.d.ts +2 -0
  108. package/dist/dnd/warn-once.js +8 -0
  109. package/dist/entities/base-item-resolver.js +2 -2
  110. package/dist/entities/slug.d.ts +13 -0
  111. package/dist/entities/slug.js +5 -3
  112. package/dist/entities/wikilink-display.d.ts +3 -0
  113. package/dist/entities/wikilink-display.js +10 -0
  114. package/dist/feat/feat.category-codes.d.ts +32 -0
  115. package/dist/feat/feat.category-codes.js +14 -0
  116. package/dist/feat/feat.codec.js +7 -5
  117. package/dist/feat/feat.parser.js +6 -4
  118. package/dist/feat/feat.schema.d.ts +239 -0
  119. package/dist/feat/feat.schema.js +5 -3
  120. package/dist/feat/feat.types.d.ts +37 -1
  121. package/dist/index.js +2033 -6907
  122. package/dist/item/item.codec.js +4 -3
  123. package/dist/item/item.enrichment.js +4 -4
  124. package/dist/item/item.parser.js +3 -2
  125. package/dist/item/item.schema.d.ts +69 -3
  126. package/dist/item/item.schema.js +2 -1
  127. package/dist/item/item.types.d.ts +69 -3
  128. package/dist/monster/monster.codec.d.ts +7 -6
  129. package/dist/monster/monster.enrichment.js +4 -4
  130. package/dist/monster/monster.format.d.ts +135 -0
  131. package/dist/monster/monster.format.js +78 -0
  132. package/dist/monster/monster.parser.d.ts +6 -1
  133. package/dist/monster/monster.parser.js +10 -1
  134. package/dist/monster/monster.schema.d.ts +369 -0
  135. package/dist/monster/monster.schema.js +34 -0
  136. package/dist/monster/monster.types.d.ts +200 -14
  137. package/dist/optional-feature/optional-feature.codec.js +6 -5
  138. package/dist/optional-feature/optional-feature.parser.js +5 -4
  139. package/dist/optional-feature/optional-feature.schema.d.ts +185 -0
  140. package/dist/optional-feature/optional-feature.schema.js +4 -3
  141. package/dist/pack.d.ts +1 -1
  142. package/dist/pc/conditions.constants.d.ts +0 -1
  143. package/dist/pc/conditions.constants.js +1 -3
  144. package/dist/pc/decision-recognizer.js +1 -1
  145. package/dist/pc/pc.additional-spells.d.ts +47 -0
  146. package/dist/pc/pc.additional-spells.js +23 -0
  147. package/dist/pc/pc.asi-flatten.d.ts +18 -0
  148. package/dist/pc/pc.decision-engine.d.ts +105 -17
  149. package/dist/pc/pc.decision-engine.js +28 -12
  150. package/dist/pc/pc.defense-normalize.d.ts +11 -0
  151. package/dist/pc/pc.defense-normalize.js +6 -0
  152. package/dist/pc/pc.equipment.d.ts +31 -2
  153. package/dist/pc/pc.equipment.js +12 -8
  154. package/dist/pc/pc.feature-effects.d.ts +234 -11
  155. package/dist/pc/pc.feature-effects.js +21 -5
  156. package/dist/pc/pc.parser.js +2 -2
  157. package/dist/pc/pc.pools.d.ts +11 -3
  158. package/dist/pc/pc.pools.js +9 -13
  159. package/dist/pc/pc.proficiencies.d.ts +54 -29
  160. package/dist/pc/pc.proficiencies.js +74 -95
  161. package/dist/pc/pc.proficiency-grants.d.ts +58 -0
  162. package/dist/pc/pc.proficiency-normalize.d.ts +24 -0
  163. package/dist/pc/pc.proficiency-normalize.js +12 -0
  164. package/dist/pc/pc.proficiency-query.d.ts +13 -0
  165. package/dist/pc/pc.proficiency-query.js +1 -1
  166. package/dist/pc/pc.recalc.d.ts +69 -14
  167. package/dist/pc/pc.recalc.js +261 -122
  168. package/dist/pc/pc.resolver.d.ts +34 -8
  169. package/dist/pc/pc.resolver.js +27 -12
  170. package/dist/pc/pc.resource-seed.d.ts +3 -2
  171. package/dist/pc/pc.resource-seed.js +19 -17
  172. package/dist/pc/pc.resources.d.ts +87 -0
  173. package/dist/pc/pc.resources.js +21 -0
  174. package/dist/pc/pc.rest.d.ts +10 -1
  175. package/dist/pc/pc.rest.js +66 -12
  176. package/dist/pc/pc.schema.d.ts +139 -3
  177. package/dist/pc/pc.schema.js +4 -2
  178. package/dist/pc/pc.slotting.js +3 -3
  179. package/dist/pc/pc.spellcasting.d.ts +75 -6
  180. package/dist/pc/pc.spellcasting.js +16 -6
  181. package/dist/pc/pc.table-column.d.ts +23 -0
  182. package/dist/pc/pc.table-column.js +13 -3
  183. package/dist/pc/pc.types.d.ts +251 -12
  184. package/dist/pc/pool-layout.d.ts +47 -0
  185. package/dist/pc/pool-layout.js +16 -0
  186. package/dist/pc/roll-scope.d.ts +2 -0
  187. package/dist/pc/roll-scope.js +8 -0
  188. package/dist/pc/roll-tag-labels.d.ts +40 -0
  189. package/dist/pc/roll-tag-labels.js +17 -0
  190. package/dist/pc/spell-source.d.ts +21 -0
  191. package/dist/pc/spell-source.js +13 -0
  192. package/dist/race/race.codec.js +9 -7
  193. package/dist/race/race.parser.js +8 -6
  194. package/dist/race/race.schema.d.ts +51 -1
  195. package/dist/race/race.schema.js +8 -5
  196. package/dist/race/race.structural.d.ts +7 -0
  197. package/dist/race/race.structural.js +6 -0
  198. package/dist/race/race.types.d.ts +20 -0
  199. package/dist/schemas/attack-schema.d.ts +5 -0
  200. package/dist/schemas/caster-type-schema.d.ts +14 -0
  201. package/dist/schemas/caster-type-schema.js +6 -0
  202. package/dist/schemas/choice-schema.js +2 -2
  203. package/dist/schemas/entity-extras-schema.d.ts +53 -0
  204. package/dist/schemas/entity-extras-schema.js +10 -0
  205. package/dist/schemas/equipment-grant-schema.d.ts +2 -0
  206. package/dist/schemas/equipment-grant-schema.js +1 -1
  207. package/dist/schemas/feature-alias.d.ts +34 -0
  208. package/dist/schemas/feature-effect-schema.d.ts +133 -0
  209. package/dist/schemas/feature-effect-schema.js +1 -1
  210. package/dist/schemas/feature-schema.d.ts +8 -0
  211. package/dist/schemas/feature-schema.js +6 -4
  212. package/dist/schemas/resource-schema.d.ts +43 -0
  213. package/dist/schemas/resource-schema.js +1 -1
  214. package/dist/schemas/selection-pool-schema.d.ts +2 -0
  215. package/dist/schemas/selection-pool-schema.js +1 -1
  216. package/dist/spell/spell.access.js +23 -3
  217. package/dist/spell/spell.codec.js +4 -3
  218. package/dist/spell/spell.enrichment.js +4 -4
  219. package/dist/spell/spell.parser.d.ts +30 -0
  220. package/dist/spell/spell.parser.js +9 -2
  221. package/dist/spell/spell.scaling.d.ts +27 -6
  222. package/dist/spell/spell.scaling.js +25 -6
  223. package/dist/spell/spell.schema.d.ts +44 -2
  224. package/dist/spell/spell.schema.js +2 -1
  225. package/dist/spell/spell.types.d.ts +14 -0
  226. package/dist/subclass/subclass.codec.d.ts +1 -1
  227. package/dist/subclass/subclass.codec.js +11 -8
  228. package/dist/subclass/subclass.parser.js +10 -7
  229. package/dist/subclass/subclass.schema.d.ts +54 -7
  230. package/dist/subclass/subclass.schema.js +8 -6
  231. package/dist/subclass/subclass.types.d.ts +20 -2
  232. package/dist/types/choice.d.ts +53 -2
  233. package/dist/types/choice.js +13 -1
  234. package/dist/types/equipment-grant.d.ts +8 -1
  235. package/dist/types/feature-effect.d.ts +85 -23
  236. package/dist/types/feature.d.ts +70 -1
  237. package/dist/types/optional-feature.types.d.ts +28 -0
  238. package/dist/types/resource.d.ts +21 -1
  239. package/dist/types/selection-pool.d.ts +17 -2
  240. package/dist/weapon/weapon.classify.js +2 -2
  241. package/dist/weapon/weapon.codec.js +4 -3
  242. package/dist/weapon/weapon.parser.js +3 -2
  243. package/dist/weapon/weapon.schema.d.ts +4 -0
  244. package/dist/weapon/weapon.schema.js +2 -1
  245. package/dist/weapon/weapon.types.d.ts +8 -0
  246. package/package.json +2 -2
  247. package/dist/chunk-5XUXXAQJ.js +0 -30
  248. package/dist/chunk-7P65Q426.js +0 -158
  249. package/dist/chunk-7TEK5KK7.js +0 -49
  250. package/dist/chunk-AIRFC5NQ.js +0 -143
  251. package/dist/chunk-CZPMTQOY.js +0 -68
  252. package/dist/chunk-N2JE7BWL.js +0 -81
  253. package/dist/chunk-NXR3BD2V.js +0 -90
  254. package/dist/chunk-O5EYMKFH.js +0 -6
  255. package/dist/chunk-Q5K6LWBZ.js +0 -45
  256. package/dist/chunk-TNUFPIXI.js +0 -1110
  257. package/dist/chunk-TZK36BU7.js +0 -38
  258. package/dist/chunk-W7HWMMBF.js +0 -46
  259. package/dist/chunk-Y4I74YEG.js +0 -33
@@ -0,0 +1,165 @@
1
+ import {
2
+ derivePoolLayout
3
+ } from "./chunk-PP2UHLBA.js";
4
+ import {
5
+ readTableColumn
6
+ } from "./chunk-IUAAXXNO.js";
7
+ import {
8
+ warnOnce
9
+ } from "./chunk-LVQLWRCU.js";
10
+ import {
11
+ bareEntitySlug,
12
+ wikilinkTailSlug
13
+ } from "./chunk-6X4KUDMU.js";
14
+
15
+ // src/pc/pc.pools.ts
16
+ function levelPrereqMax(d) {
17
+ var _a;
18
+ return ((_a = d.prerequisites) != null ? _a : []).filter((p) => p.kind === "level").reduce((m, p) => Math.max(m, p.min), 0);
19
+ }
20
+ function resolvePool(rc, classIndex, pool, registry, index) {
21
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
22
+ const entity = rc.entity;
23
+ const level = rc.level;
24
+ const ownerBare = bareEntitySlug(entity.slug);
25
+ const ownerPrefix = entity.slug.split("_")[0];
26
+ const col = pool.count.column;
27
+ const count = (_a = readTableColumn(entity.table, level, [col])) != null ? _a : 0;
28
+ let anchorLevel = 1;
29
+ let columnSeen = false;
30
+ for (let l = 1; l <= 20; l++) {
31
+ const c = readTableColumn(entity.table, l, [col]);
32
+ if (c != null) columnSeen = true;
33
+ if (c != null && c >= 1) {
34
+ anchorLevel = l;
35
+ break;
36
+ }
37
+ }
38
+ if (!columnSeen) {
39
+ warnOnce(
40
+ `pool-column:${pool.id}`,
41
+ `Archivist: pool "${pool.id}" declares count column "${col}", which "${entity.slug}"'s class table carries at no level; the pool resolves count 0 at anchor level 1`
42
+ );
43
+ }
44
+ const ft = pool.source.where.feature_type;
45
+ const all = registry.search("", "optional-feature", Number.POSITIVE_INFINITY).slice().sort((a, b) => a.name.localeCompare(b.name) || a.slug.localeCompare(b.slug));
46
+ const byBare = /* @__PURE__ */ new Map();
47
+ const candidates = /* @__PURE__ */ new Map();
48
+ for (const e of all) {
49
+ const d = e.data;
50
+ const entry = { slug: e.slug, entity: d, ...e.compendium ? { compendium: e.compendium } : {} };
51
+ const bare = bareEntitySlug(e.slug);
52
+ byBare.set(bare, entry);
53
+ if (d.feature_type !== ft) continue;
54
+ if (!((_b = d.available_to) != null ? _b : []).some((l) => wikilinkTailSlug(l) === ownerBare)) continue;
55
+ if (levelPrereqMax(d) > level) continue;
56
+ const group = candidates.get(bare);
57
+ if (group) group.push(entry);
58
+ else candidates.set(bare, [entry]);
59
+ }
60
+ const available = [];
61
+ for (const [bare, group] of candidates) {
62
+ if (group.length === 1) {
63
+ available.push(group[0]);
64
+ continue;
65
+ }
66
+ const owned = group.find((e) => e.slug.split("_")[0] === ownerPrefix);
67
+ if (!owned) {
68
+ warnOnce(
69
+ `pool-collapse:${bare}`,
70
+ `Archivist: pool "${pool.id}" holds ${group.length} cross-edition entries for "${bare}" and none shares the owner's compendium prefix "${ownerPrefix}"; keeping "${group[0].slug}"`
71
+ );
72
+ }
73
+ available.push(owned != null ? owned : group[0]);
74
+ }
75
+ const grantDecls = [
76
+ ...(_d = (_c = rc.entity) == null ? void 0 : _c.pool_grants) != null ? _d : [],
77
+ ...(_f = (_e = rc.subclass) == null ? void 0 : _e.pool_grants) != null ? _f : []
78
+ ];
79
+ const grantsRaw = grantDecls.filter((g) => g.pool === pool.id).flatMap((g) => g.grants).filter((g) => g.at_level <= level).map((g) => byBare.get(wikilinkTailSlug(g.feature))).filter((e) => e != null);
80
+ const grantedBare = /* @__PURE__ */ new Set();
81
+ const grants = grantsRaw.filter((e) => {
82
+ const key = bareEntitySlug(e.slug);
83
+ if (grantedBare.has(key)) return false;
84
+ grantedBare.add(key);
85
+ return true;
86
+ });
87
+ const bySlugAvailable = new Map(available.map((e) => [e.slug, e]));
88
+ const byBareAvailable = new Map(available.map((e) => [bareEntitySlug(e.slug), e]));
89
+ const resolveStored = (s) => {
90
+ const exact = bySlugAvailable.get(s);
91
+ if (exact) return exact;
92
+ const survivor = byBareAvailable.get(bareEntitySlug(s));
93
+ if (survivor) return survivor;
94
+ const full = registry.getByTypeAndSlug("optional-feature", s);
95
+ if (full) {
96
+ const d = full.data;
97
+ return { slug: full.slug, entity: d, ...full.compendium ? { compendium: full.compendium } : {} };
98
+ }
99
+ return byBare.get(bareEntitySlug(s));
100
+ };
101
+ const raw = (_g = rc.choices[anchorLevel]) == null ? void 0 : _g[pool.id];
102
+ const selectedSlugs = Array.isArray(raw) ? raw : typeof raw === "string" ? [raw] : [];
103
+ const selected = [];
104
+ const seenBare = /* @__PURE__ */ new Set();
105
+ for (const s of selectedSlugs) {
106
+ const entry = resolveStored(s);
107
+ if (!entry) continue;
108
+ const bare = bareEntitySlug(entry.slug);
109
+ if (grantedBare.has(bare) || seenBare.has(bare)) continue;
110
+ seenBare.add(bare);
111
+ selected.push(entry);
112
+ }
113
+ const members = [...available, ...grants];
114
+ const layout = derivePoolLayout(members);
115
+ const votes = /* @__PURE__ */ new Map();
116
+ for (const e of members) {
117
+ const id = (_h = e.entity.consumes) == null ? void 0 : _h.resource;
118
+ if (!id || !index.has(id)) continue;
119
+ votes.set(id, ((_i = votes.get(id)) != null ? _i : 0) + 1);
120
+ }
121
+ let resource;
122
+ let bestN = 0;
123
+ for (const [id, n] of votes) if (n > bestN) {
124
+ resource = id;
125
+ bestN = n;
126
+ }
127
+ return {
128
+ id: pool.id,
129
+ label: pool.label,
130
+ classIndex,
131
+ count,
132
+ anchorLevel,
133
+ selected,
134
+ available,
135
+ grants,
136
+ ...layout ? { layout } : {},
137
+ ...resource ? { resource } : {}
138
+ };
139
+ }
140
+ function resolveAllPools(resolved, registry, index) {
141
+ const out = [];
142
+ resolved.classes.forEach((rc, classIndex) => {
143
+ var _a, _b, _c;
144
+ if (!rc.entity) return;
145
+ const decls = [...(_a = rc.entity.selection_pools) != null ? _a : [], ...(_c = (_b = rc.subclass) == null ? void 0 : _b.selection_pools) != null ? _c : []];
146
+ const seen = /* @__PURE__ */ new Set();
147
+ for (const pool of decls) {
148
+ if (seen.has(pool.id)) continue;
149
+ seen.add(pool.id);
150
+ out.push(resolvePool(rc, classIndex, pool, registry, index));
151
+ }
152
+ });
153
+ return out;
154
+ }
155
+ function strandedPicks(pool) {
156
+ const inAvailable = new Set(pool.available.map((e) => e.slug));
157
+ return pool.selected.filter((e) => !inAvailable.has(e.slug));
158
+ }
159
+
160
+ export {
161
+ levelPrereqMax,
162
+ resolvePool,
163
+ resolveAllPools,
164
+ strandedPicks
165
+ };
@@ -0,0 +1,81 @@
1
+ import {
2
+ poolGrantSchema,
3
+ selectionPoolSchema,
4
+ tabDeclSchema
5
+ } from "./chunk-23LZLBJK.js";
6
+ import {
7
+ casterTypeEnum
8
+ } from "./chunk-CJYCVNW2.js";
9
+ import {
10
+ featureSchema
11
+ } from "./chunk-W74BCA7V.js";
12
+ import {
13
+ resourceSchema
14
+ } from "./chunk-YLL2QXY2.js";
15
+ import {
16
+ additionalSpellsEntrySchema,
17
+ imageField,
18
+ progressionSchema
19
+ } from "./chunk-UA5KS2PL.js";
20
+
21
+ // src/subclass/subclass.schema.ts
22
+ import { z } from "zod";
23
+ var editionEnum = z.enum(["2014", "2024"]);
24
+ var wikilinkRegex = /^\[\[[^[\]]+\]\]$/;
25
+ var abilityEnum = z.enum(["str", "dex", "con", "int", "wis", "cha"]);
26
+ var spellcastingSchema = z.object({
27
+ caster_type: casterTypeEnum.optional(),
28
+ ability: abilityEnum,
29
+ preparation: z.enum(["known", "prepared"]).optional(),
30
+ spell_list: z.string().min(1).optional()
31
+ });
32
+ var subclassTableRowSchema = z.object({
33
+ columns: z.record(z.string(), z.union([z.string(), z.number()])).optional()
34
+ });
35
+ var subclassEntitySchema = z.object({
36
+ slug: z.string().min(1),
37
+ name: z.string().min(1),
38
+ parent_class: z.string().regex(wikilinkRegex, "parent_class must be a wikilink like [[rogue]]"),
39
+ edition: editionEnum,
40
+ source: z.string().min(1),
41
+ description: z.string(),
42
+ spellcasting: spellcastingSchema.nullable().optional(),
43
+ table: z.record(z.string(), subclassTableRowSchema).optional(),
44
+ features_by_level: z.record(z.string(), z.array(featureSchema)),
45
+ resources: z.array(resourceSchema),
46
+ selection_pools: z.array(selectionPoolSchema).optional(),
47
+ pool_grants: z.array(poolGrantSchema).optional(),
48
+ tabs: z.array(tabDeclSchema).optional(),
49
+ rendering_hint: z.string().optional(),
50
+ // 346
51
+ short_name: z.string().min(1).optional(),
52
+ // 346
53
+ has_fluff: z.boolean().optional(),
54
+ // 50
55
+ has_fluff_images: z.boolean().optional(),
56
+ // 346
57
+ fluff: z.unknown().optional(),
58
+ // 62 docs, single key-set {_subclassFluff:{...}} — 5etools-internal
59
+ table_col_labels: z.array(z.string().min(1)).optional(),
60
+ // 8
61
+ cantrip_progression: z.array(z.number()).optional(),
62
+ // 6
63
+ prepared_spells_change: z.string().min(1).optional(),
64
+ // 2
65
+ prepared_spells_progression: z.array(z.number()).optional(),
66
+ // 2
67
+ spells_known_progression: z.array(z.number()).optional(),
68
+ // 4
69
+ feat_progression: z.array(progressionSchema).optional(),
70
+ // 1
71
+ optionalfeature_progression: z.array(progressionSchema).optional(),
72
+ // 13 carriers; featureType
73
+ // on all 13, required on 2
74
+ additional_spells: z.array(additionalSpellsEntrySchema).optional(),
75
+ // 212
76
+ image: imageField
77
+ });
78
+
79
+ export {
80
+ subclassEntitySchema
81
+ };
@@ -0,0 +1,162 @@
1
+ import {
2
+ spellEntitySchema
3
+ } from "./chunk-VQAXTIBW.js";
4
+
5
+ // src/spell/spell.parser.ts
6
+ import { parseYaml, toStringSafe } from "@archivist-gg/core";
7
+ var KNOWN_KEYS = /* @__PURE__ */ new Set([
8
+ "name",
9
+ "level",
10
+ "school",
11
+ "casting_time",
12
+ "range",
13
+ "components",
14
+ "duration",
15
+ "concentration",
16
+ "ritual",
17
+ "classes",
18
+ "description",
19
+ "at_higher_levels",
20
+ "damage",
21
+ "saving_throw",
22
+ "casting_options",
23
+ // §2 · the fourteen converter keys. This gate and `spellEntitySchema` are independent: a key
24
+ // missing here is refused BEFORE zod ever sees it, so both must learn every new key.
25
+ "rendering_hint",
26
+ "misc_tags",
27
+ "area_tags",
28
+ "condition_inflict",
29
+ "affects_creature_type",
30
+ "spell_attack",
31
+ "ability_check",
32
+ "damage_resist",
33
+ "damage_immune",
34
+ "condition_immune",
35
+ "damage_vulnerable",
36
+ "has_fluff",
37
+ "image",
38
+ "has_fluff_images",
39
+ // Body-only metadata that's emitted to YAML but ignored at runtime — accept silently.
40
+ "slug",
41
+ "edition",
42
+ "source"
43
+ ]);
44
+ var DURATION_END_WORDS = { dispel: "dispelled", trigger: "triggered" };
45
+ function normalizeSpellComponents(value) {
46
+ if (typeof value === "string") return value;
47
+ if (value == null || typeof value !== "object" || Array.isArray(value)) return toStringSafe(value);
48
+ const c = value;
49
+ const parts = [];
50
+ if (c.v === true) parts.push("V");
51
+ if (c.s === true) parts.push("S");
52
+ if (typeof c.m === "string") parts.push(`M (${c.m})`);
53
+ else if (c.m === true) parts.push("M");
54
+ else if (c.m != null && typeof c.m === "object") {
55
+ const text = c.m.text;
56
+ parts.push(typeof text === "string" ? `M (${text})` : "M");
57
+ }
58
+ if (c.r === true) parts.push("R");
59
+ return parts.join(", ");
60
+ }
61
+ function normalizeSpellDurationEntry(entry) {
62
+ if (entry == null || typeof entry !== "object") return toStringSafe(entry);
63
+ const e = entry;
64
+ if (e.type === "permanent" && Array.isArray(e.ends)) {
65
+ return "until " + e.ends.map((w) => {
66
+ var _a;
67
+ return (_a = DURATION_END_WORDS[String(w)]) != null ? _a : String(w);
68
+ }).join(" or ");
69
+ }
70
+ if (e.type === "timed" && e.duration != null) {
71
+ const unit = e.duration.type;
72
+ const amount = e.duration.amount;
73
+ if (typeof unit === "string" && typeof amount === "number") {
74
+ const prefix = e.duration.up_to === true ? "up to " : "";
75
+ return `${prefix}${amount} ${unit}${amount > 1 ? "s" : ""}`;
76
+ }
77
+ }
78
+ return toStringSafe(entry);
79
+ }
80
+ function normalizeSpellDuration(value) {
81
+ if (typeof value === "string") return value;
82
+ if (!Array.isArray(value)) return toStringSafe(value);
83
+ return value.map((entry) => normalizeSpellDurationEntry(entry)).join("; ");
84
+ }
85
+ function mirrorSpellShapes(entity) {
86
+ return {
87
+ ...entity,
88
+ ...entity.components != null ? { components: normalizeSpellComponents(entity.components) } : {},
89
+ ...entity.duration != null ? { duration: normalizeSpellDuration(entity.duration) } : {}
90
+ };
91
+ }
92
+ function parseSpell(source) {
93
+ const result = parseYaml(source, ["name"]);
94
+ if (!result.success) return result;
95
+ const meta = {};
96
+ if (typeof result.data.source === "string") meta.source = result.data.source;
97
+ if (typeof result.data.edition === "string") meta.edition = result.data.edition;
98
+ const filtered = {};
99
+ for (const [k, v] of Object.entries(result.data)) {
100
+ if (k === "slug" || k === "edition" || k === "source") continue;
101
+ if (!KNOWN_KEYS.has(k)) {
102
+ return { success: false, error: `Unknown spell field: ${k}` };
103
+ }
104
+ filtered[k] = v;
105
+ }
106
+ const parsed = spellEntitySchema.safeParse(filtered);
107
+ if (!parsed.success) {
108
+ return { success: false, error: `spell schema validation failed: ${parsed.error.message}` };
109
+ }
110
+ const raw = parsed.data;
111
+ const spell = { name: raw.name };
112
+ if (raw.level != null) spell.level = raw.level;
113
+ if (raw.school != null) spell.school = toStringSafe(raw.school);
114
+ if (raw.casting_time != null) spell.casting_time = toStringSafe(raw.casting_time);
115
+ if (raw.range != null) spell.range = toStringSafe(raw.range);
116
+ if (raw.components != null) spell.components = normalizeSpellComponents(raw.components);
117
+ if (raw.duration != null) spell.duration = normalizeSpellDuration(raw.duration);
118
+ if (raw.concentration != null) spell.concentration = Boolean(raw.concentration);
119
+ if (raw.ritual != null) spell.ritual = Boolean(raw.ritual);
120
+ if (raw.classes) spell.classes = raw.classes.map(String);
121
+ if (raw.description) spell.description = raw.description;
122
+ if (raw.at_higher_levels) spell.at_higher_levels = raw.at_higher_levels.map(String);
123
+ if (raw.damage) spell.damage = { types: raw.damage.types.map(String) };
124
+ if (raw.saving_throw) spell.saving_throw = { ability: raw.saving_throw.ability };
125
+ if (raw.casting_options) {
126
+ spell.casting_options = raw.casting_options.map((opt) => {
127
+ const co = { type: opt.type };
128
+ if (opt.damage_roll !== void 0) co.damage_roll = opt.damage_roll;
129
+ if (opt.target_count !== void 0) co.target_count = opt.target_count;
130
+ if (opt.duration !== void 0) co.duration = opt.duration;
131
+ if (opt.range !== void 0) co.range = opt.range;
132
+ if (opt.concentration !== void 0) co.concentration = opt.concentration;
133
+ if (opt.shape_size !== void 0) co.shape_size = opt.shape_size;
134
+ if (opt.desc !== void 0) co.desc = opt.desc;
135
+ return co;
136
+ });
137
+ }
138
+ if (raw.rendering_hint != null) spell.rendering_hint = raw.rendering_hint;
139
+ if (raw.misc_tags != null) spell.misc_tags = raw.misc_tags;
140
+ if (raw.area_tags != null) spell.area_tags = raw.area_tags;
141
+ if (raw.condition_inflict != null) spell.condition_inflict = raw.condition_inflict;
142
+ if (raw.affects_creature_type != null) spell.affects_creature_type = raw.affects_creature_type;
143
+ if (raw.spell_attack != null) spell.spell_attack = raw.spell_attack;
144
+ if (raw.ability_check != null) spell.ability_check = raw.ability_check;
145
+ if (raw.damage_resist != null) spell.damage_resist = raw.damage_resist;
146
+ if (raw.damage_immune != null) spell.damage_immune = raw.damage_immune;
147
+ if (raw.condition_immune != null) spell.condition_immune = raw.condition_immune;
148
+ if (raw.damage_vulnerable != null) spell.damage_vulnerable = raw.damage_vulnerable;
149
+ if (raw.has_fluff != null) spell.has_fluff = raw.has_fluff;
150
+ if (raw.image != null) spell.image = raw.image;
151
+ if (raw.has_fluff_images != null) spell.has_fluff_images = raw.has_fluff_images;
152
+ if (meta.source) spell.source = meta.source;
153
+ if (meta.edition) spell.edition = meta.edition;
154
+ return { success: true, data: spell };
155
+ }
156
+
157
+ export {
158
+ normalizeSpellComponents,
159
+ normalizeSpellDuration,
160
+ mirrorSpellShapes,
161
+ parseSpell
162
+ };
@@ -2,8 +2,9 @@ import {
2
2
  ABILITY_KEYS,
3
3
  CR_PROFICIENCY,
4
4
  CR_XP,
5
+ DAMAGE_TYPES,
5
6
  SIZE_HIT_DICE
6
- } from "./chunk-WP2CX2JO.js";
7
+ } from "./chunk-WELIKLZF.js";
7
8
 
8
9
  // src/dnd/math.ts
9
10
  function abilityModifier(score) {
@@ -68,6 +69,22 @@ function abilityNameToKey(name) {
68
69
  }
69
70
  return null;
70
71
  }
72
+ var CANONICAL_DAMAGE_TYPES = new Set(DAMAGE_TYPES.map((t) => t.toLowerCase()));
73
+ function isCanonicalDamageType(type) {
74
+ return CANONICAL_DAMAGE_TYPES.has(type.trim().toLowerCase());
75
+ }
76
+ var CHOSEN_DAMAGE_TYPE = "chosen";
77
+ var CHOSEN_DAMAGE_TYPE_NOTE = "damage type of your choice";
78
+ function isChosenDamageType(type) {
79
+ return type !== void 0 && type.trim().toLowerCase() === CHOSEN_DAMAGE_TYPE;
80
+ }
81
+ function isRenderableDamageText(text) {
82
+ var _a;
83
+ const m = /^(?:\d*d\d+(?:\s*[+-]\s*\d+)?|[+-]?\d+)(?:\s+(.*))?$/i.exec(text.trim());
84
+ if (!m) return false;
85
+ const type = ((_a = m[1]) != null ? _a : "").trim();
86
+ return type === "" || isCanonicalDamageType(type);
87
+ }
71
88
 
72
89
  export {
73
90
  abilityModifier,
@@ -84,5 +101,10 @@ export {
84
101
  passivePerception,
85
102
  attackBonus,
86
103
  saveDC,
87
- abilityNameToKey
104
+ abilityNameToKey,
105
+ isCanonicalDamageType,
106
+ CHOSEN_DAMAGE_TYPE,
107
+ CHOSEN_DAMAGE_TYPE_NOTE,
108
+ isChosenDamageType,
109
+ isRenderableDamageText
88
110
  };
@@ -0,0 +1,50 @@
1
+ // src/pc/pool-layout.ts
2
+ var RENDERING_HINT_LAYOUT = {
3
+ "dice-pool": "dice-pool",
4
+ "point-pool": "point-pool"
5
+ };
6
+ function derivePoolLayout(entries) {
7
+ var _a, _b;
8
+ const votes = /* @__PURE__ */ new Map();
9
+ for (const e of entries) {
10
+ const hint = (_a = e.entity.rendering_hint) != null ? _a : "";
11
+ if (!Object.prototype.hasOwnProperty.call(RENDERING_HINT_LAYOUT, hint)) continue;
12
+ const layout = RENDERING_HINT_LAYOUT[hint];
13
+ votes.set(layout, ((_b = votes.get(layout)) != null ? _b : 0) + 1);
14
+ }
15
+ let best;
16
+ let bestN = 0;
17
+ let tied = false;
18
+ for (const [layout, n] of votes) {
19
+ if (n > bestN) {
20
+ best = layout;
21
+ bestN = n;
22
+ tied = false;
23
+ } else if (n === bestN) tied = true;
24
+ }
25
+ return tied ? void 0 : best;
26
+ }
27
+ var RENDERING_HINT_AFFORDANCE = {
28
+ "granted-die-to-ally": "granted-die"
29
+ };
30
+ function deriveEntryAffordance(entity) {
31
+ var _a;
32
+ const hint = (_a = entity.rendering_hint) != null ? _a : "";
33
+ if (!Object.prototype.hasOwnProperty.call(RENDERING_HINT_AFFORDANCE, hint)) return void 0;
34
+ return RENDERING_HINT_AFFORDANCE[hint];
35
+ }
36
+ var AFFORDANCE_CAPTIONS = {
37
+ "granted-die": "{amount}{die} to an ally"
38
+ };
39
+ function formatAffordanceCaption(affordance, values) {
40
+ return AFFORDANCE_CAPTIONS[affordance].replace(/\{(\w+)\}/g, (whole, key) => Object.prototype.hasOwnProperty.call(values, key) ? String(values[key]) : whole);
41
+ }
42
+
43
+ export {
44
+ RENDERING_HINT_LAYOUT,
45
+ derivePoolLayout,
46
+ RENDERING_HINT_AFFORDANCE,
47
+ deriveEntryAffordance,
48
+ AFFORDANCE_CAPTIONS,
49
+ formatAffordanceCaption
50
+ };
@@ -0,0 +1,6 @@
1
+ // src/race/race.structural.ts
2
+ var RACE_STRUCTURAL_PSEUDO = /* @__PURE__ */ new Set(["size", "speed", "darkvision"]);
3
+
4
+ export {
5
+ RACE_STRUCTURAL_PSEUDO
6
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  parseOptionalFeature
3
- } from "./chunk-4F6AIZ36.js";
3
+ } from "./chunk-6BFWZW6T.js";
4
4
 
5
5
  // src/optional-feature/optional-feature.codec.ts
6
6
  import yaml from "js-yaml";
@@ -0,0 +1,16 @@
1
+ // src/pc/pc.proficiency-normalize.ts
2
+ var normKey = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim().split(/\s+/).filter(Boolean).map((w) => w.endsWith("s") ? w.slice(0, -1) : w).sort().join(" ");
3
+ var toProfSlug = (s) => s.toLowerCase().replace(/’/g, "'").trim().replace(/\s+/g, "-");
4
+ var humanizeProficiency = (s) => s.replace(/-/g, " ").replace(/(^|\s)\w/g, (c) => c.toUpperCase());
5
+ var proficiencyLabel = (raw) => {
6
+ const text = raw.replace(/’/g, "'").trim().replace(/\s+/g, " ");
7
+ if (!/\s/.test(text) || text === text.toLowerCase()) return humanizeProficiency(toProfSlug(raw));
8
+ return text.charAt(0).toUpperCase() + text.slice(1);
9
+ };
10
+
11
+ export {
12
+ normKey,
13
+ toProfSlug,
14
+ humanizeProficiency,
15
+ proficiencyLabel
16
+ };
@@ -0,0 +1,89 @@
1
+ import {
2
+ actionCostEnum,
3
+ resourceSchema
4
+ } from "./chunk-YLL2QXY2.js";
5
+ import {
6
+ choiceSchema
7
+ } from "./chunk-IWRVOCT5.js";
8
+ import {
9
+ featureEffectSchema
10
+ } from "./chunk-X3D6LXUU.js";
11
+ import {
12
+ additionalSpellsEntrySchema,
13
+ imageField,
14
+ progressionSchema
15
+ } from "./chunk-UA5KS2PL.js";
16
+
17
+ // src/feat/feat.schema.ts
18
+ import { z } from "zod";
19
+ var abilityEnum = z.enum(["str", "dex", "con", "int", "wis", "cha"]);
20
+ var editionEnum = z.enum(["2014", "2024"]);
21
+ var categoryEnum = z.enum(["origin", "general", "fighting-style", "epic-boon"]);
22
+ var prerequisiteSchema = z.discriminatedUnion("kind", [
23
+ z.object({ kind: z.literal("ability"), ability: abilityEnum, min: z.number().int().positive() }),
24
+ z.object({ kind: z.literal("level"), min: z.number().int().positive() }),
25
+ z.object({ kind: z.literal("spellcaster") }),
26
+ z.object({
27
+ kind: z.literal("proficiency"),
28
+ proficiency_type: z.enum(["armor", "weapon", "tool", "skill", "saving-throw"]),
29
+ value: z.string().min(1)
30
+ }),
31
+ z.object({ kind: z.literal("race"), slug: z.string().min(1) }),
32
+ z.object({ kind: z.literal("class"), slug: z.string().min(1) }),
33
+ // The exclusive-feat-category and feat-category arms carry a raw 5etools category code, not a
34
+ // slug; featCategoryLabel names it. The rest carry slugs the renderer humanizes, except other,
35
+ // which carries free prose that prereqText returns verbatim.
36
+ z.object({ kind: z.literal("feat"), slug: z.string().min(1) }),
37
+ z.object({ kind: z.literal("campaign"), slug: z.string().min(1) }),
38
+ z.object({ kind: z.literal("exclusive-feat-category"), slug: z.string().min(1) }),
39
+ z.object({ kind: z.literal("feature"), slug: z.string().min(1) }),
40
+ z.object({ kind: z.literal("other"), detail: z.string().min(1) }),
41
+ z.object({ kind: z.literal("feat-category"), slug: z.string().min(1) }),
42
+ z.object({ kind: z.literal("background"), slug: z.string().min(1) })
43
+ ]);
44
+ var featEntitySchema = z.object({
45
+ slug: z.string().min(1),
46
+ name: z.string().min(1),
47
+ edition: editionEnum,
48
+ source: z.string().min(1),
49
+ category: categoryEnum,
50
+ description: z.string(),
51
+ prerequisites: z.array(prerequisiteSchema),
52
+ benefits: z.array(z.string()),
53
+ effects: z.array(featureEffectSchema),
54
+ grants_asi: z.object({
55
+ amount: z.number().int().positive(),
56
+ pool: z.array(abilityEnum).optional()
57
+ }).nullable(),
58
+ repeatable: z.boolean(),
59
+ choices: z.array(choiceSchema),
60
+ rendering_hint: z.string().optional(),
61
+ additional_spells: z.array(additionalSpellsEntrySchema).optional(),
62
+ // 71
63
+ has_fluff: z.boolean().optional(),
64
+ // 0 carriers — symmetry, §9.4
65
+ has_fluff_images: z.boolean().optional(),
66
+ // 41
67
+ trait_tags: z.unknown().optional(),
68
+ // 7, nullable measured — same passthrough family
69
+ optionalfeature_progression: z.array(progressionSchema).optional(),
70
+ // 4
71
+ resources: z.array(resourceSchema).optional(),
72
+ // closes the feat.types.ts `Feat.resources` schema/type asymmetry (C);
73
+ // ZERO converter/bundle carriers (no census row) — the only behaviour delta is AUTHORED feats,
74
+ // where the type has promised the field all along. Import resourceSchema.
75
+ action_cost: actionCostEnum.optional(),
76
+ // ruling R-G1b-5 (gate1-r1 f1): a TOP-LEVEL bundle key on ONE
77
+ // feat (`SRD 2024/Feats/Boon of the Night Spirit.md`, `action_cost: bonus-action` at entity top
78
+ // level) — the ninth SRD-control non-kept row: top-level on the ENTITY, not featureSchema-shaped
79
+ // (finding 14's nine rows split 4 featureSchema / 4 §2.8-arity / this one, which needed its own
80
+ // declaration — gate1-r4 R4-1). `actionCostEnum` is exported from
81
+ // `schemas/resource-schema.ts` (optionalFeatureEntitySchema already imports it). MAPPED since
82
+ // R4-G3a §10.2.3: the resolver aliases it onto the resolved feature's `action`, which is what
83
+ // draws the feat note's Action line and files the row under that economy.
84
+ image: imageField
85
+ });
86
+
87
+ export {
88
+ featEntitySchema
89
+ };
@@ -0,0 +1,21 @@
1
+ // src/pc/conditions.constants.ts
2
+ var CONDITION_SLUGS = [
3
+ "blinded",
4
+ "charmed",
5
+ "deafened",
6
+ "frightened",
7
+ "grappled",
8
+ "incapacitated",
9
+ "invisible",
10
+ "paralyzed",
11
+ "petrified",
12
+ "poisoned",
13
+ "prone",
14
+ "restrained",
15
+ "stunned",
16
+ "unconscious"
17
+ ];
18
+
19
+ export {
20
+ CONDITION_SLUGS
21
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  itemEntitySchema
3
- } from "./chunk-K6Q5OUGK.js";
3
+ } from "./chunk-GFZ7PITJ.js";
4
4
 
5
5
  // src/item/item.parser.ts
6
6
  import { parseYaml } from "@archivist-gg/core";
@@ -41,6 +41,14 @@ var KNOWN_KEYS = /* @__PURE__ */ new Set([
41
41
  "scroll_level",
42
42
  "unidentified",
43
43
  "masked_category",
44
+ // Modelled top-level converter keys (spec §4). The schema declaring them is NOT
45
+ // enough: this set is the second, independent gate — a key missing here is
46
+ // copied into `raw` as well, so the two lists must move together.
47
+ "modify_speed",
48
+ "rendering_hint",
49
+ "has_fluff",
50
+ "has_fluff_images",
51
+ "image",
44
52
  // Legacy fields kept (removed in Slice 7 after grep verifies no consumer)
45
53
  "damage_dice",
46
54
  "damage_type",