@archivist-gg/dnd5e 0.2.0 → 0.3.1

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 (58) hide show
  1. package/dist/background/background.codec.js +3 -3
  2. package/dist/background/background.parser.js +2 -2
  3. package/dist/background/background.schema.d.ts +8 -0
  4. package/dist/background/background.schema.js +5 -3
  5. package/dist/chunk-353WXS6S.js +25 -0
  6. package/dist/{chunk-DC74TZNA.js → chunk-4LZJXJJS.js} +7 -2
  7. package/dist/{chunk-DZXSWSBP.js → chunk-5ZBE4CWV.js} +1 -1
  8. package/dist/{chunk-IXZXFFFW.js → chunk-6IRYTM5V.js} +6 -1
  9. package/dist/chunk-7TEK5KK7.js +49 -0
  10. package/dist/{chunk-V6SOFUJW.js → chunk-AIRFC5NQ.js} +3 -1
  11. package/dist/{chunk-VTYUBINW.js → chunk-BIK4DFWK.js} +1 -1
  12. package/dist/{chunk-TQZB4OCJ.js → chunk-D3CLOBE3.js} +49 -21
  13. package/dist/{chunk-3TRGRSCH.js → chunk-LV4SNWZQ.js} +7 -1
  14. package/dist/{chunk-UC4FE5X3.js → chunk-N6N74K6X.js} +1 -1
  15. package/dist/chunk-O5EYMKFH.js +6 -0
  16. package/dist/{chunk-TUIFSVLI.js → chunk-SE7AZDR3.js} +1 -0
  17. package/dist/{chunk-5WQD3WNZ.js → chunk-TN6ZLTNU.js} +6 -5
  18. package/dist/{chunk-R5SQHP2X.js → chunk-TNUFPIXI.js} +48 -30
  19. package/dist/{chunk-J2RYSZMQ.js → chunk-VTTA2ALZ.js} +2 -2
  20. package/dist/class/class.slug.d.ts +7 -5
  21. package/dist/class/class.slug.js +1 -1
  22. package/dist/entities/base-item-resolver.d.ts +9 -0
  23. package/dist/entities/base-item-resolver.js +6 -4
  24. package/dist/entities/slug.d.ts +7 -0
  25. package/dist/entities/slug.js +3 -1
  26. package/dist/index.js +3902 -3623
  27. package/dist/item/item.actions-map.d.ts +8 -7
  28. package/dist/item/item.actions-map.js +3 -4
  29. package/dist/item/item.ai-schema.d.ts +1 -1
  30. package/dist/pc/pc.decision-engine.d.ts +13 -3
  31. package/dist/pc/pc.decision-engine.js +9 -9
  32. package/dist/pc/pc.equipment.js +6 -12
  33. package/dist/pc/pc.feature-effects.d.ts +5 -0
  34. package/dist/pc/pc.feature-effects.js +2 -11
  35. package/dist/pc/pc.parser.js +1 -1
  36. package/dist/pc/pc.pools.js +7 -7
  37. package/dist/pc/pc.proficiencies.d.ts +31 -0
  38. package/dist/pc/pc.proficiencies.js +96 -23
  39. package/dist/pc/pc.proficiency-normalize.d.ts +5 -0
  40. package/dist/pc/pc.proficiency-query.js +5 -1
  41. package/dist/pc/pc.recalc.d.ts +7 -0
  42. package/dist/pc/pc.recalc.js +112 -58
  43. package/dist/pc/pc.resolver.js +7 -7
  44. package/dist/pc/pc.rest.d.ts +1 -1
  45. package/dist/pc/pc.rest.js +20 -11
  46. package/dist/pc/pc.schema.d.ts +10 -4
  47. package/dist/pc/pc.schema.js +1 -1
  48. package/dist/pc/pc.slotting.js +3 -3
  49. package/dist/pc/pc.spellcasting.d.ts +5 -1
  50. package/dist/pc/pc.spellcasting.js +4 -2
  51. package/dist/pc/pc.types.d.ts +30 -4
  52. package/dist/spell/spell.access.js +1 -1
  53. package/dist/types/choice.d.ts +5 -0
  54. package/dist/types/choice.js +9 -3
  55. package/dist/weapon/weapon.classify.d.ts +21 -0
  56. package/dist/weapon/weapon.classify.js +7 -0
  57. package/package.json +1 -1
  58. package/dist/chunk-BH6AMZVY.js +0 -25
@@ -1,32 +1,35 @@
1
1
  import {
2
2
  computeConditionEffects
3
3
  } from "../chunk-R2ZV233X.js";
4
- import {
5
- computeAppliedBonuses,
6
- computeSlotsAndAttacks,
7
- emptyAppliedBonuses
8
- } from "../chunk-TQZB4OCJ.js";
9
- import {
10
- computeFeatureEffects
11
- } from "../chunk-V6SOFUJW.js";
12
4
  import {
13
5
  collectChosenAbilityPoints,
14
6
  collectChosenProficiencies
15
- } from "../chunk-R5SQHP2X.js";
16
- import "../chunk-BH6AMZVY.js";
17
- import "../chunk-UC4FE5X3.js";
7
+ } from "../chunk-TNUFPIXI.js";
8
+ import "../chunk-7TEK5KK7.js";
18
9
  import {
19
10
  computeSpellLimits,
20
11
  deriveSpellSlots,
12
+ effectiveSpellcastingAbility,
21
13
  resolveSpellcasting
22
- } from "../chunk-IXZXFFFW.js";
14
+ } from "../chunk-6IRYTM5V.js";
23
15
  import "../chunk-5XUXXAQJ.js";
24
16
  import "../chunk-JEYQU3JT.js";
17
+ import {
18
+ computeAppliedBonuses,
19
+ computeSlotsAndAttacks,
20
+ emptyAppliedBonuses
21
+ } from "../chunk-D3CLOBE3.js";
22
+ import "../chunk-353WXS6S.js";
23
+ import "../chunk-O5EYMKFH.js";
24
+ import "../chunk-N6N74K6X.js";
25
+ import {
26
+ computeFeatureEffects
27
+ } from "../chunk-AIRFC5NQ.js";
25
28
  import "../chunk-LWFTHJIE.js";
26
29
  import "../chunk-DNAJRMNN.js";
27
- import "../chunk-DC74TZNA.js";
28
- import "../chunk-3TRGRSCH.js";
29
- import "../chunk-J2RYSZMQ.js";
30
+ import "../chunk-4LZJXJJS.js";
31
+ import "../chunk-LV4SNWZQ.js";
32
+ import "../chunk-VTTA2ALZ.js";
30
33
  import {
31
34
  abilityModifier,
32
35
  attackBonus,
@@ -117,7 +120,7 @@ function abilityBonusBreakdown(resolved) {
117
120
  }
118
121
  return out;
119
122
  }
120
- function multiclassMaxHP(classes, conMod) {
123
+ function hitDiceAverageSum(classes) {
121
124
  var _a;
122
125
  let total = 0;
123
126
  let firstLevelCounted = false;
@@ -126,14 +129,27 @@ function multiclassMaxHP(classes, conMod) {
126
129
  if (!c.entity || die == null || c.level < 1) continue;
127
130
  for (let lvl = 1; lvl <= c.level; lvl++) {
128
131
  if (!firstLevelCounted) {
129
- total += die + conMod;
132
+ total += die;
130
133
  firstLevelCounted = true;
131
134
  } else {
132
- total += Math.floor(die / 2) + 1 + conMod;
135
+ total += Math.floor(die / 2) + 1;
133
136
  }
134
137
  }
135
138
  }
136
- return Math.max(1, total);
139
+ return total;
140
+ }
141
+ function hpLevelCount(classes) {
142
+ var _a;
143
+ let count = 0;
144
+ for (const c of classes) {
145
+ const die = parseDieSize((_a = c.entity) == null ? void 0 : _a.hit_die);
146
+ if (!c.entity || die == null || c.level < 1) continue;
147
+ count += c.level;
148
+ }
149
+ return count;
150
+ }
151
+ function multiclassMaxHP(classes, conMod) {
152
+ return Math.max(1, hitDiceAverageSum(classes) + conMod * hpLevelCount(classes));
137
153
  }
138
154
  function unarmoredAC(resolved, mods, warnings) {
139
155
  return unarmoredACBreakdown(resolved, mods, warnings).total;
@@ -294,12 +310,18 @@ function computeAbilityScores(resolved, overrides) {
294
310
  }
295
311
  return out;
296
312
  }
297
- function normalizeProfList(input) {
313
+ function normalizeArmorProf(input) {
298
314
  var _a, _b;
299
315
  if (!input) return { categories: [], specific: [] };
300
- if (Array.isArray(input)) return { categories: [], specific: input };
316
+ if (Array.isArray(input)) return { categories: input, specific: [] };
301
317
  return { categories: (_a = input.categories) != null ? _a : [], specific: (_b = input.specific) != null ? _b : [] };
302
318
  }
319
+ function normalizeWeaponToolProf(input) {
320
+ var _a, _b, _c;
321
+ if (!input) return { categories: [], specific: [] };
322
+ if (Array.isArray(input)) return { categories: [], specific: input };
323
+ return { categories: (_a = input.categories) != null ? _a : [], specific: ((_b = input.fixed) != null ? _b : []).concat((_c = input.specific) != null ? _c : []) };
324
+ }
303
325
  function mergeInto(target, source) {
304
326
  for (const c of source.categories) if (!target.categories.includes(c)) target.categories.push(c);
305
327
  for (const s of source.specific) if (!target.specific.includes(s)) target.specific.push(s);
@@ -326,31 +348,31 @@ function computeProficiencies(resolved) {
326
348
  for (const c of resolved.classes) {
327
349
  const p = (_a = c.entity) == null ? void 0 : _a.proficiencies;
328
350
  if (!p) continue;
329
- mergeInto(armor, normalizeProfList(p.armor));
330
- mergeInto(weapons, normalizeProfList(p.weapons));
331
- mergeInto(tools, normalizeProfList(p.tools));
351
+ mergeInto(armor, normalizeArmorProf(p.armor));
352
+ mergeInto(weapons, normalizeWeaponToolProf(p.weapons));
353
+ mergeInto(tools, normalizeWeaponToolProf(p.tools));
332
354
  (_b = p.languages) == null ? void 0 : _b.forEach((l) => languages.add(l));
333
355
  }
334
356
  const racePr = (_c = resolved.race) == null ? void 0 : _c.proficiencies;
335
357
  if (racePr) {
336
- mergeInto(armor, normalizeProfList(racePr.armor));
337
- mergeInto(weapons, normalizeProfList(racePr.weapons));
338
- mergeInto(tools, normalizeProfList(racePr.tools));
358
+ mergeInto(armor, normalizeArmorProf(racePr.armor));
359
+ mergeInto(weapons, normalizeWeaponToolProf(racePr.weapons));
360
+ mergeInto(tools, normalizeWeaponToolProf(racePr.tools));
339
361
  (_d = racePr.languages) == null ? void 0 : _d.forEach((l) => languages.add(l));
340
362
  }
341
363
  const bgPr = (_e = resolved.background) == null ? void 0 : _e.proficiencies;
342
364
  if (bgPr) {
343
- mergeInto(armor, normalizeProfList(bgPr.armor));
344
- mergeInto(weapons, normalizeProfList(bgPr.weapons));
345
- mergeInto(tools, normalizeProfList(bgPr.tools));
365
+ mergeInto(armor, normalizeArmorProf(bgPr.armor));
366
+ mergeInto(weapons, normalizeWeaponToolProf(bgPr.weapons));
367
+ mergeInto(tools, normalizeWeaponToolProf(bgPr.tools));
346
368
  (_f = bgPr.languages) == null ? void 0 : _f.forEach((l) => languages.add(l));
347
369
  }
348
370
  for (const f of resolved.feats) {
349
371
  const grants = f.grants_proficiency;
350
372
  if (!grants) continue;
351
- mergeInto(armor, normalizeProfList(grants.armor));
352
- mergeInto(weapons, normalizeProfList(grants.weapons));
353
- mergeInto(tools, normalizeProfList(grants.tools));
373
+ mergeInto(armor, normalizeArmorProf(grants.armor));
374
+ mergeInto(weapons, normalizeWeaponToolProf(grants.weapons));
375
+ mergeInto(tools, normalizeWeaponToolProf(grants.tools));
354
376
  (_g = grants.languages) == null ? void 0 : _g.forEach((l) => languages.add(l));
355
377
  }
356
378
  return {
@@ -362,7 +384,7 @@ function computeProficiencies(resolved) {
362
384
  };
363
385
  }
364
386
  function recalc(resolved, registry) {
365
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W;
387
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y;
366
388
  const warnings = [];
367
389
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
368
390
  const chosenProfs = collectChosenProficiencies(resolved);
@@ -484,9 +506,36 @@ function recalc(resolved, registry) {
484
506
  investigation: (_t = (_s = overrides.passives) == null ? void 0 : _s.investigation) != null ? _t : passive(scores.int, investigationTri, proficiencyBonus),
485
507
  insight: (_v = (_u = overrides.passives) == null ? void 0 : _u.insight) != null ? _v : passive(scores.wis, insightTri, proficiencyBonus)
486
508
  };
487
- const hpMaxDerived = multiclassMaxHP(resolved.classes, mods.con) + featureEffects.hp_per_level_bonus * totalLevel;
488
- const hpMaxAfterConditions = Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier);
489
- const hpMax = (_x = (_w = overrides.hp) == null ? void 0 : _w.max) != null ? _x : hpMaxAfterConditions;
509
+ const hpRolled = (_x = (_w = overrides.hp) == null ? void 0 : _w.rolled) != null ? _x : null;
510
+ const hpModifier = (_z = (_y = overrides.hp) == null ? void 0 : _y.modifier) != null ? _z : null;
511
+ const averageDiceSum = hitDiceAverageSum(resolved.classes);
512
+ const conLevels = hpLevelCount(resolved.classes);
513
+ const diceSum = hpRolled != null ? hpRolled : averageDiceSum;
514
+ const diceConRaw = diceSum + mods.con * conLevels;
515
+ const diceConClamped = Math.max(1, diceConRaw);
516
+ const hpMaxDerived = diceConClamped + featureEffects.hp_per_level_bonus * totalLevel + (hpModifier != null ? hpModifier : 0);
517
+ const hpMaxAfterConditions = Math.max(0, Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier));
518
+ const hpMax = (_B = (_A = overrides.hp) == null ? void 0 : _A.max) != null ? _B : hpMaxAfterConditions;
519
+ const hpBreakdown = {
520
+ diceSum,
521
+ diceSource: hpRolled != null ? "rolled" : "average",
522
+ averageDiceSum,
523
+ conMod: mods.con,
524
+ conLevels,
525
+ clampApplied: diceConClamped !== diceConRaw,
526
+ perLevelTerms: featureEffects.hp_per_level_terms.map((t) => ({
527
+ label: t.label,
528
+ perLevel: t.value,
529
+ levels: totalLevel,
530
+ total: t.value * totalLevel
531
+ })),
532
+ modifier: hpModifier,
533
+ exhaustionMultiplier: conditionEffects.hp_max_multiplier,
534
+ exhaustionLevel: conditionEffects.exhaustion_level,
535
+ derivedMax: hpMaxAfterConditions,
536
+ override: (_D = (_C = overrides.hp) == null ? void 0 : _C.max) != null ? _D : null,
537
+ final: hpMax
538
+ };
490
539
  const featureAcTermsFor = (hasArmor) => featureEffects.ac_terms.filter((t) => !t.requires_armor || hasArmor).map((t) => ({ source: t.label, amount: t.value, kind: "feature" }));
491
540
  const sumTerms = (terms) => terms.reduce((s, t) => s + t.amount, 0);
492
541
  const weaponAbilities = [...featureEffects.weaponAbilities];
@@ -500,7 +549,7 @@ function recalc(resolved, registry) {
500
549
  if (!c.entity) continue;
501
550
  const profile = resolveSpellcasting(c);
502
551
  if (profile) {
503
- primaryCasterAbility = profile.ability;
552
+ primaryCasterAbility = effectiveSpellcastingAbility(c.entity.slug, profile.ability, overrides);
504
553
  break;
505
554
  }
506
555
  }
@@ -511,7 +560,7 @@ function recalc(resolved, registry) {
511
560
  let acBreakdownDerived = [];
512
561
  let acInformationalDerived = [];
513
562
  if (registry) {
514
- derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_y = resolved.weaponMasteries) != null ? _y : []);
563
+ derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_E = resolved.weaponMasteries) != null ? _E : []);
515
564
  if (derivedEquipment.equippedSlots.armor) {
516
565
  const featTerms = featureAcTermsFor(true);
517
566
  acDerived = derivedEquipment.ac + sumTerms(featTerms);
@@ -534,16 +583,16 @@ function recalc(resolved, registry) {
534
583
  acDerived = total + sumTerms(featTerms);
535
584
  acBreakdownDerived = [...terms, ...featTerms];
536
585
  }
537
- const ac = (_z = overrides.ac) != null ? _z : acDerived;
586
+ const ac = (_F = overrides.ac) != null ? _F : acDerived;
538
587
  const additiveSpeed = speedFromRace(resolved) + applied.speed_bonuses.walk + featureEffects.speed_walk_bonus;
539
588
  const baseSpeed = Math.max(featureEffects.speed_walk_set, additiveSpeed);
540
589
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
541
590
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
542
- const speed = (_A = overrides.speed) != null ? _A : conditionSpeed;
591
+ const speed = (_G = overrides.speed) != null ? _G : conditionSpeed;
543
592
  if (!resolved.race) warnings.push("No race resolved; speed defaulted to 30.");
544
- const init = (_B = overrides.initiative) != null ? _B : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
593
+ const init = (_H = overrides.initiative) != null ? _H : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
545
594
  const senses = {
546
- darkvision: Math.max((_E = (_D = (_C = resolved.race) == null ? void 0 : _C.vision) == null ? void 0 : _D.darkvision) != null ? _E : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
595
+ darkvision: Math.max((_K = (_J = (_I = resolved.race) == null ? void 0 : _I.vision) == null ? void 0 : _J.darkvision) != null ? _K : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
547
596
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
548
597
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
549
598
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -555,19 +604,21 @@ function recalc(resolved, registry) {
555
604
  if (!c.entity) continue;
556
605
  const profile = resolveSpellcasting(c);
557
606
  if (!profile) continue;
558
- const dc = saveDC(scores[profile.ability], proficiencyBonus) + applied.spell_save_dc;
559
- const atk = attackBonus(scores[profile.ability], proficiencyBonus) + applied.spell_attack;
607
+ const ab = effectiveSpellcastingAbility(c.entity.slug, profile.ability, overrides);
608
+ const dc = saveDC(scores[ab], proficiencyBonus) + applied.spell_save_dc;
609
+ const atk = attackBonus(scores[ab], proficiencyBonus) + applied.spell_attack;
560
610
  spellcastingClasses.push({
561
611
  classSlug: c.entity.slug,
562
612
  className: c.entity.name,
563
- ability: profile.ability,
564
- saveDC: (_G = (_F = overrides.spellcasting) == null ? void 0 : _F.saveDC) != null ? _G : dc,
565
- attackBonus: (_I = (_H = overrides.spellcasting) == null ? void 0 : _H.attackBonus) != null ? _I : atk,
613
+ ability: ab,
614
+ defaultAbility: profile.ability,
615
+ saveDC: dc,
616
+ attackBonus: atk,
566
617
  casterType: profile.casterType,
567
618
  preparation: profile.preparation
568
619
  });
569
620
  slotInputs.push({ casterType: profile.casterType, level: c.level });
570
- limitInputs.push({ classSlug: c.entity.slug, level: c.level, profile, abilityScore: scores[profile.ability] });
621
+ limitInputs.push({ classSlug: c.entity.slug, level: c.level, profile, abilityScore: scores[ab] });
571
622
  }
572
623
  const spellcasting = spellcastingClasses.length > 0 ? {
573
624
  ability: spellcastingClasses[0].ability,
@@ -587,20 +638,20 @@ function recalc(resolved, registry) {
587
638
  const spellLimits = computeSpellLimits(limitInputs);
588
639
  const defenses = {
589
640
  resistances: dedupeDefenseList([
590
- (_K = (_J = resolved.definition.defenses) == null ? void 0 : _J.resistances) != null ? _K : [],
641
+ (_M = (_L = resolved.definition.defenses) == null ? void 0 : _L.resistances) != null ? _M : [],
591
642
  applied.defenses.resistances,
592
643
  featureEffects.resistances
593
644
  ]),
594
645
  immunities: dedupeDefenseList([
595
- (_M = (_L = resolved.definition.defenses) == null ? void 0 : _L.immunities) != null ? _M : [],
646
+ (_O = (_N = resolved.definition.defenses) == null ? void 0 : _N.immunities) != null ? _O : [],
596
647
  applied.defenses.immunities
597
648
  ]),
598
649
  vulnerabilities: dedupeDefenseList([
599
- (_O = (_N = resolved.definition.defenses) == null ? void 0 : _N.vulnerabilities) != null ? _O : [],
650
+ (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.vulnerabilities) != null ? _Q : [],
600
651
  applied.defenses.vulnerabilities
601
652
  ]),
602
653
  condition_immunities: dedupeDefenseList([
603
- (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.condition_immunities) != null ? _Q : [],
654
+ (_S = (_R = resolved.definition.defenses) == null ? void 0 : _R.condition_immunities) != null ? _S : [],
604
655
  applied.defenses.condition_immunities,
605
656
  featureEffects.condition_immunities
606
657
  ])
@@ -620,6 +671,7 @@ function recalc(resolved, registry) {
620
671
  current: resolved.state.hp.current,
621
672
  temp: resolved.state.hp.temp
622
673
  },
674
+ hpBreakdown,
623
675
  ac,
624
676
  speed,
625
677
  initiative: init,
@@ -643,7 +695,7 @@ function recalc(resolved, registry) {
643
695
  // untouched rows keep `critRange`/`attackNotes` ABSENT (not 20 / not []).
644
696
  // crit-range: folded weapon crit threshold, only when an effect lowered it.
645
697
  // attackNotes: reroll-damage / attack-rule captions, only when non-empty.
646
- attacks: ((_R = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _R : []).map((a) => {
698
+ attacks: ((_T = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _T : []).map((a) => {
647
699
  var _a2;
648
700
  const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses];
649
701
  return {
@@ -654,10 +706,10 @@ function recalc(resolved, registry) {
654
706
  ...riders.length ? { damageRiders: riders } : {}
655
707
  };
656
708
  }),
657
- equippedSlots: (_S = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _S : {},
658
- carriedWeight: (_T = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _T : 0,
659
- attunementUsed: (_U = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _U : 0,
660
- attunementLimit: (_W = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _W : (_V = overrides.attunement_limit) != null ? _V : 3,
709
+ equippedSlots: (_U = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _U : {},
710
+ carriedWeight: (_V = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _V : 0,
711
+ attunementUsed: (_W = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _W : 0,
712
+ attunementLimit: (_Y = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _Y : (_X = overrides.attunement_limit) != null ? _X : 3,
661
713
  conditionEffects,
662
714
  rollModifiers: featureEffects.rollModifiers
663
715
  };
@@ -669,6 +721,8 @@ export {
669
721
  computeAbilityScores,
670
722
  computeProficiencies,
671
723
  flattenRaceAsi,
724
+ hitDiceAverageSum,
725
+ hpLevelCount,
672
726
  initiativeBonus,
673
727
  multiclassMaxHP,
674
728
  parseDieSize,
@@ -9,15 +9,15 @@ import {
9
9
  dedupeResolvedSpells,
10
10
  resolveOriginFeat,
11
11
  stripSlug
12
- } from "../chunk-R5SQHP2X.js";
13
- import "../chunk-BH6AMZVY.js";
14
- import "../chunk-UC4FE5X3.js";
15
- import "../chunk-IXZXFFFW.js";
12
+ } from "../chunk-TNUFPIXI.js";
13
+ import "../chunk-7TEK5KK7.js";
14
+ import "../chunk-6IRYTM5V.js";
16
15
  import "../chunk-5XUXXAQJ.js";
17
16
  import "../chunk-JEYQU3JT.js";
18
- import "../chunk-DC74TZNA.js";
19
- import "../chunk-3TRGRSCH.js";
20
- import "../chunk-J2RYSZMQ.js";
17
+ import "../chunk-N6N74K6X.js";
18
+ import "../chunk-4LZJXJJS.js";
19
+ import "../chunk-LV4SNWZQ.js";
20
+ import "../chunk-VTTA2ALZ.js";
21
21
  import "../chunk-NAEPSZAM.js";
22
22
  import "../chunk-WP2CX2JO.js";
23
23
  export {
@@ -1,7 +1,7 @@
1
1
  import type { EntityRegistry } from "@archivist-gg/core";
2
2
  import type { Character, DerivedStats, ResolvedCharacter } from "./pc.types.js";
3
3
  export type RestType = "short" | "long";
4
- export type RestCategoryId = "hp-to-max" | "hd-regain" | "spell-slots" | "pact-slots" | "exhaustion" | `feature:${string}` | `item:${number}`;
4
+ export type RestCategoryId = "hp-to-max" | "hd-regain" | "spell-slots" | "pact-slots" | "exhaustion" | "hp-modifier-reset" | `feature:${string}` | `item:${number}`;
5
5
  export interface RestCategory {
6
6
  id: RestCategoryId;
7
7
  label: string;
@@ -16,7 +16,7 @@ function findResourceById(resolved, id) {
16
16
  return void 0;
17
17
  }
18
18
  function computeRestPlan(character, resolved, derived, registry, type) {
19
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
19
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
20
20
  const cats = [];
21
21
  let hdRegainDist;
22
22
  const pact = character.state.spell_slots_pact;
@@ -38,16 +38,25 @@ function computeRestPlan(character, resolved, derived, registry, type) {
38
38
  preview: `${character.state.exhaustion} \u2192 ${character.state.exhaustion - 1}`
39
39
  });
40
40
  }
41
- const slotsUsed = Object.values((_a = character.state.spell_slots) != null ? _a : {}).reduce((s, slot) => {
41
+ const hpModifier = (_b = (_a = character.overrides) == null ? void 0 : _a.hp) == null ? void 0 : _b.modifier;
42
+ if (hpModifier !== void 0) {
43
+ const signed = hpModifier > 0 ? `+${hpModifier}` : `${hpModifier}`;
44
+ cats.push({
45
+ id: "hp-modifier-reset",
46
+ label: "Max HP Modifier",
47
+ preview: `${signed} \u2192 cleared`
48
+ });
49
+ }
50
+ const slotsUsed = Object.values((_c = character.state.spell_slots) != null ? _c : {}).reduce((s, slot) => {
42
51
  var _a2;
43
52
  return s + ((_a2 = slot.used) != null ? _a2 : 0);
44
53
  }, 0);
45
54
  if (slotsUsed > 0) {
46
55
  cats.push({ id: "spell-slots", label: "Spell Slots", preview: "all reset" });
47
56
  }
48
- const totalLevel = (_b = resolved.totalLevel) != null ? _b : 0;
57
+ const totalLevel = (_d = resolved.totalLevel) != null ? _d : 0;
49
58
  const regainBudget = Math.max(1, Math.floor(totalLevel / 2));
50
- const pools = Object.entries((_c = character.state.hit_dice) != null ? _c : {}).map(([die, hd]) => ({ die, used: hd.used, total: hd.total })).filter((p) => p.used > 0).sort((a, b) => b.used - a.used);
59
+ const pools = Object.entries((_e = character.state.hit_dice) != null ? _e : {}).map(([die, hd]) => ({ die, used: hd.used, total: hd.total })).filter((p) => p.used > 0).sort((a, b) => b.used - a.used);
51
60
  if (pools.length > 0) {
52
61
  let left = regainBudget;
53
62
  const dist = [];
@@ -68,14 +77,14 @@ function computeRestPlan(character, resolved, derived, registry, type) {
68
77
  hdRegainDist = dist.map((d) => ({ die: d.die, targetUsed: d.targetUsed }));
69
78
  }
70
79
  }
71
- for (const [key, fu] of Object.entries((_d = character.state.feature_uses) != null ? _d : {})) {
80
+ for (const [key, fu] of Object.entries((_f = character.state.feature_uses) != null ? _f : {})) {
72
81
  if (fu.used <= 0) continue;
73
82
  const res = findResourceById(resolved, key);
74
- const reset = (_e = res == null ? void 0 : res.reset) != null ? _e : "long-rest";
83
+ const reset = (_g = res == null ? void 0 : res.reset) != null ? _g : "long-rest";
75
84
  if (reset !== "short-rest" && reset !== "long-rest" && reset !== "dawn" && reset !== "dusk") continue;
76
85
  cats.push({
77
86
  id: `feature:${key}`,
78
- label: (_f = res == null ? void 0 : res.label) != null ? _f : key,
87
+ label: (_h = res == null ? void 0 : res.label) != null ? _h : key,
79
88
  preview: `${fu.used}/${fu.max} restored`
80
89
  });
81
90
  }
@@ -95,13 +104,13 @@ function computeRestPlan(character, resolved, derived, registry, type) {
95
104
  });
96
105
  }
97
106
  if (type === "short") {
98
- for (const [key, fu] of Object.entries((_g = character.state.feature_uses) != null ? _g : {})) {
107
+ for (const [key, fu] of Object.entries((_i = character.state.feature_uses) != null ? _i : {})) {
99
108
  if (fu.used <= 0) continue;
100
109
  const res = findResourceById(resolved, key);
101
- if (((_h = res == null ? void 0 : res.reset) != null ? _h : "long-rest") !== "short-rest") continue;
110
+ if (((_j = res == null ? void 0 : res.reset) != null ? _j : "long-rest") !== "short-rest") continue;
102
111
  cats.push({
103
112
  id: `feature:${key}`,
104
- label: (_i = res == null ? void 0 : res.label) != null ? _i : key,
113
+ label: (_k = res == null ? void 0 : res.label) != null ? _k : key,
105
114
  preview: `${fu.used}/${fu.max} restored`
106
115
  });
107
116
  }
@@ -120,7 +129,7 @@ function computeRestPlan(character, resolved, derived, registry, type) {
120
129
  });
121
130
  });
122
131
  }
123
- const hdAvailable = type === "short" ? Object.entries((_j = character.state.hit_dice) != null ? _j : {}).filter(([, hd]) => hd.used < hd.total).map(([die, hd]) => ({ die, remaining: hd.total - hd.used })) : [];
132
+ const hdAvailable = type === "short" ? Object.entries((_l = character.state.hit_dice) != null ? _l : {}).filter(([, hd]) => hd.used < hd.total).map(([die, hd]) => ({ die, remaining: hd.total - hd.used })) : [];
124
133
  return { type, categories: cats, hdAvailable, hdRegainDist };
125
134
  }
126
135
  export {
@@ -221,14 +221,20 @@ export declare const characterSchema: z.ZodObject<{
221
221
  }, z.core.$strip>>;
222
222
  hp: z.ZodOptional<z.ZodObject<{
223
223
  max: z.ZodOptional<z.ZodNumber>;
224
+ rolled: z.ZodOptional<z.ZodNumber>;
225
+ modifier: z.ZodOptional<z.ZodNumber>;
224
226
  }, z.core.$strip>>;
225
227
  ac: z.ZodOptional<z.ZodNumber>;
226
228
  speed: z.ZodOptional<z.ZodNumber>;
227
229
  initiative: z.ZodOptional<z.ZodNumber>;
228
- spellcasting: z.ZodOptional<z.ZodObject<{
229
- saveDC: z.ZodOptional<z.ZodNumber>;
230
- attackBonus: z.ZodOptional<z.ZodNumber>;
231
- }, z.core.$strip>>;
230
+ spellcasting_ability_by_class: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
231
+ str: "str";
232
+ dex: "dex";
233
+ con: "con";
234
+ int: "int";
235
+ wis: "wis";
236
+ cha: "cha";
237
+ }>>>;
232
238
  spellcasting_ability: z.ZodOptional<z.ZodEnum<{
233
239
  str: "str";
234
240
  dex: "dex";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  characterSchema
3
- } from "../chunk-5WQD3WNZ.js";
3
+ } from "../chunk-TN6ZLTNU.js";
4
4
  import "../chunk-TZK36BU7.js";
5
5
  export {
6
6
  characterSchema
@@ -6,9 +6,9 @@ import {
6
6
  isShieldArmor,
7
7
  isWeaponEntity,
8
8
  resolveEntityForEntry
9
- } from "../chunk-UC4FE5X3.js";
10
- import "../chunk-DC74TZNA.js";
11
- import "../chunk-3TRGRSCH.js";
9
+ } from "../chunk-N6N74K6X.js";
10
+ import "../chunk-4LZJXJJS.js";
11
+ import "../chunk-LV4SNWZQ.js";
12
12
  export {
13
13
  defaultSlotForType,
14
14
  effectiveArmor,
@@ -1,5 +1,5 @@
1
1
  import type { Ability } from "@archivist-gg/dnd5e";
2
- import type { KnownSpellEntry, ResolvedClass } from "./pc.types.js";
2
+ import type { CharacterOverrides, KnownSpellEntry, ResolvedClass } from "./pc.types.js";
3
3
  import type { CasterType } from "@archivist-gg/dnd5e/class/class.types";
4
4
  export interface SpellcastingProfile {
5
5
  ability: Ability;
@@ -18,6 +18,10 @@ export interface SpellcastingProfile {
18
18
  * non-casters. No hardcoded class knowledge — everything comes from the data.
19
19
  */
20
20
  export declare function resolveSpellcasting(rc: ResolvedClass): SpellcastingProfile | null;
21
+ /** The ability a class actually casts with: a per-class override wins, else the
22
+ * data ability from resolveSpellcasting. `dataAbility` is non-nullable by
23
+ * contract: resolve caster-ness (a non-null SpellcastingProfile) BEFORE calling. */
24
+ export declare function effectiveSpellcastingAbility(classSlug: string, dataAbility: Ability, overrides: CharacterOverrides): Ability;
21
25
  export interface NormalizedKnownSpell {
22
26
  slug: string;
23
27
  classSlug: string | null;
@@ -1,16 +1,18 @@
1
1
  import {
2
2
  computeSpellLimits,
3
3
  deriveSpellSlots,
4
+ effectiveSpellcastingAbility,
4
5
  normalizeKnownSpell,
5
6
  resolveSpellcasting
6
- } from "../chunk-IXZXFFFW.js";
7
+ } from "../chunk-6IRYTM5V.js";
7
8
  import "../chunk-5XUXXAQJ.js";
8
- import "../chunk-J2RYSZMQ.js";
9
+ import "../chunk-VTTA2ALZ.js";
9
10
  import "../chunk-NAEPSZAM.js";
10
11
  import "../chunk-WP2CX2JO.js";
11
12
  export {
12
13
  computeSpellLimits,
13
14
  deriveSpellSlots,
15
+ effectiveSpellcastingAbility,
14
16
  normalizeKnownSpell,
15
17
  resolveSpellcasting
16
18
  };
@@ -120,14 +120,13 @@ export interface CharacterOverrides {
120
120
  }>;
121
121
  hp?: {
122
122
  max?: number;
123
+ rolled?: number;
124
+ modifier?: number;
123
125
  };
124
126
  ac?: number;
125
127
  speed?: number;
126
128
  initiative?: number;
127
- spellcasting?: {
128
- saveDC?: number;
129
- attackBonus?: number;
130
- };
129
+ spellcasting_ability_by_class?: Partial<Record<string, Ability>>;
131
130
  /** Character-level spellcasting ability for spells that carry no ability of
132
131
  * their own (e.g. a Spell Scroll cast by a non-caster): the DC-ability fallback
133
132
  * after a per-instance override and the character's own class ability. */
@@ -339,6 +338,27 @@ export interface ACTerm {
339
338
  amount: number;
340
339
  kind: "armor" | "shield" | "item" | "unarmored" | "override" | "dex" | "ability" | "feature";
341
340
  }
341
+ /** Structured max-HP math for the Max HP modal. Spec: P5 2026-07-21. */
342
+ export interface HPBreakdown {
343
+ diceSum: number;
344
+ diceSource: "rolled" | "average";
345
+ averageDiceSum: number;
346
+ conMod: number;
347
+ conLevels: number;
348
+ clampApplied: boolean;
349
+ perLevelTerms: {
350
+ label: string;
351
+ perLevel: number;
352
+ levels: number;
353
+ total: number;
354
+ }[];
355
+ modifier: number | null;
356
+ exhaustionMultiplier: number;
357
+ exhaustionLevel: number;
358
+ derivedMax: number;
359
+ override: number | null;
360
+ final: number;
361
+ }
342
362
  /** An additive on-hit damage rider (dice or flat) applied to an attack, from a
343
363
  * feature (global — all weapon attacks) or a magic item (that weapon only).
344
364
  * `amount` is a dice/flat string ("2d6", "1d8", "2"); `damage_type` optional
@@ -353,6 +373,10 @@ export interface AttackRow {
353
373
  id: string;
354
374
  name: string;
355
375
  range?: string;
376
+ /** Secondary thrown-mode range ("20/60 ft") for a throwable melee weapon.
377
+ * Display-only; rendered as a stacked muted second line in the Range cell.
378
+ * Absent otherwise. */
379
+ thrownRange?: string;
356
380
  toHit: number;
357
381
  damageDice: string;
358
382
  damageType: string;
@@ -529,6 +553,7 @@ export interface DerivedStats {
529
553
  condition_immunities: string[];
530
554
  };
531
555
  acBreakdown: ACTerm[];
556
+ hpBreakdown: HPBreakdown;
532
557
  acInformational: import("@archivist-gg/dnd5e/item/item.conditions.types").InformationalBonus[];
533
558
  /** Situational saving-throw bonuses (e.g. +1 vs spells) for save tooltips. */
534
559
  savesInformational: import("@archivist-gg/dnd5e/item/item.conditions.types").InformationalBonus[];
@@ -557,6 +582,7 @@ export interface SpellcastingClassInfo {
557
582
  classSlug: string;
558
583
  className: string;
559
584
  ability: Ability;
585
+ defaultAbility: Ability;
560
586
  saveDC: number;
561
587
  attackBonus: number;
562
588
  casterType: "full" | "half" | "third" | "pact";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  baseClassName
3
- } from "../chunk-J2RYSZMQ.js";
3
+ } from "../chunk-VTTA2ALZ.js";
4
4
 
5
5
  // src/spell/spell.access.ts
6
6
  function classSpellCandidates(registry, classSlugs, maxLevel, knownSlugs, showAll = false, query = "") {
@@ -3,6 +3,11 @@ import type { FeatureEffect } from "./feature-effect.js";
3
3
  export type Ability = keyof Abilities;
4
4
  export type SkillSlug = "acrobatics" | "animal-handling" | "arcana" | "athletics" | "deception" | "history" | "insight" | "intimidation" | "investigation" | "medicine" | "nature" | "perception" | "performance" | "persuasion" | "religion" | "sleight-of-hand" | "stealth" | "survival";
5
5
  export declare const ALL_SKILL_SLUGS: SkillSlug[];
6
+ /** The SRD language set: 8 standard + 8 exotic. Authoritative and reused as
7
+ * KNOWN_LANGUAGES by the proficiency aggregate; slugs are edition-agnostic. */
8
+ export declare const STANDARD_LANGUAGES: string[];
9
+ export declare const EXOTIC_LANGUAGES: string[];
10
+ export declare const ALL_LANGUAGES: string[];
6
11
  export type FeatCategory = "origin" | "general" | "fighting-style" | "epic-boon";
7
12
  /** Closed, enumerated registry filter — YAML can never express a query the
8
13
  * engine would apply unsafely. `"self"` resolves against the owning
@@ -1,6 +1,12 @@
1
1
  import {
2
- ALL_SKILL_SLUGS
3
- } from "../chunk-BH6AMZVY.js";
2
+ ALL_LANGUAGES,
3
+ ALL_SKILL_SLUGS,
4
+ EXOTIC_LANGUAGES,
5
+ STANDARD_LANGUAGES
6
+ } from "../chunk-7TEK5KK7.js";
4
7
  export {
5
- ALL_SKILL_SLUGS
8
+ ALL_LANGUAGES,
9
+ ALL_SKILL_SLUGS,
10
+ EXOTIC_LANGUAGES,
11
+ STANDARD_LANGUAGES
6
12
  };