@archivist-gg/dnd5e 0.2.0 → 0.3.0

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 (40) hide show
  1. package/dist/chunk-353WXS6S.js +25 -0
  2. package/dist/{chunk-DC74TZNA.js → chunk-4LZJXJJS.js} +7 -2
  3. package/dist/{chunk-R5SQHP2X.js → chunk-5MZSB6OM.js} +8 -11
  4. package/dist/{chunk-5WQD3WNZ.js → chunk-A4WENOUQ.js} +5 -1
  5. package/dist/{chunk-V6SOFUJW.js → chunk-AIRFC5NQ.js} +3 -1
  6. package/dist/{chunk-TQZB4OCJ.js → chunk-EMOORSQ7.js} +45 -20
  7. package/dist/{chunk-3TRGRSCH.js → chunk-LV4SNWZQ.js} +7 -1
  8. package/dist/{chunk-IXZXFFFW.js → chunk-M2EMFD6S.js} +1 -1
  9. package/dist/{chunk-UC4FE5X3.js → chunk-N6N74K6X.js} +1 -1
  10. package/dist/{chunk-J2RYSZMQ.js → chunk-VTTA2ALZ.js} +2 -2
  11. package/dist/class/class.slug.d.ts +7 -5
  12. package/dist/class/class.slug.js +1 -1
  13. package/dist/entities/base-item-resolver.d.ts +9 -0
  14. package/dist/entities/base-item-resolver.js +6 -4
  15. package/dist/entities/slug.d.ts +7 -0
  16. package/dist/entities/slug.js +3 -1
  17. package/dist/index.js +3812 -3604
  18. package/dist/item/item.actions-map.d.ts +8 -7
  19. package/dist/item/item.actions-map.js +3 -4
  20. package/dist/pc/pc.decision-engine.d.ts +0 -3
  21. package/dist/pc/pc.decision-engine.js +6 -8
  22. package/dist/pc/pc.equipment.js +5 -12
  23. package/dist/pc/pc.feature-effects.d.ts +5 -0
  24. package/dist/pc/pc.feature-effects.js +2 -11
  25. package/dist/pc/pc.parser.js +1 -1
  26. package/dist/pc/pc.pools.js +6 -6
  27. package/dist/pc/pc.recalc.d.ts +7 -0
  28. package/dist/pc/pc.recalc.js +82 -38
  29. package/dist/pc/pc.resolver.js +6 -6
  30. package/dist/pc/pc.rest.d.ts +1 -1
  31. package/dist/pc/pc.rest.js +20 -11
  32. package/dist/pc/pc.schema.d.ts +2 -0
  33. package/dist/pc/pc.schema.js +1 -1
  34. package/dist/pc/pc.slotting.js +3 -3
  35. package/dist/pc/pc.spellcasting.js +2 -2
  36. package/dist/pc/pc.types.d.ts +28 -0
  37. package/dist/spell/spell.access.js +1 -1
  38. package/dist/weapon/weapon.classify.d.ts +21 -0
  39. package/dist/weapon/weapon.classify.js +7 -0
  40. package/package.json +1 -1
@@ -21,14 +21,15 @@ export declare const ITEM_ACTIONS: Record<string, ItemAction>;
21
21
  * (`srd-5e_wand-of-fireballs`, `srd-2024_wand-of-fireballs`,
22
22
  * `homebrew_wand-of-fireballs`).
23
23
  *
24
- * Compendium-prefixed slugs follow the shape `<prefix>_<name-slug>` where
25
- * both prefix and name-slug are kebab-case (slugify strips underscores).
26
- * The first underscore is therefore the unambiguous prefix separator: we
27
- * try the bare slug after the first underscore first, then fall back to
28
- * the original slug for legacy bare-slug callers.
24
+ * Type-namespaced slugs follow the shape `<prefix>_<entity_type>_<name-slug>`
25
+ * (all kebab-case; slugify never emits `_`), so a slug splits on `_` into
26
+ * exactly 3 parts and the bare name is `parts.slice(2).join("_")`. This is
27
+ * arity-robust: it also recovers the bare name from a legacy 2-part
28
+ * `<prefix>_<name>` slug and an already-bare name. `ITEM_ACTIONS` is keyed by
29
+ * bare name.
29
30
  *
30
- * Returns `undefined` if no map entry matches either form. Does not crash
31
- * on slugs without an underscore — those are treated as already-bare.
31
+ * Returns `undefined` if no map entry matches. Does not crash on slugs
32
+ * without an underscore — those are treated as already-bare.
32
33
  */
33
34
  export declare function findItemAction(slug: string): ItemAction | undefined;
34
35
  /**
@@ -63,10 +63,9 @@ var ITEM_ACTIONS = {
63
63
  };
64
64
  function findItemAction(slug) {
65
65
  if (slug in ITEM_ACTIONS) return ITEM_ACTIONS[slug];
66
- const underscore = slug.indexOf("_");
67
- if (underscore < 0) return void 0;
68
- const bare = slug.slice(underscore + 1);
69
- return ITEM_ACTIONS[bare];
66
+ const p = slug.split("_");
67
+ const bare = p.length >= 3 ? p.slice(2).join("_") : p[p.length - 1];
68
+ return bare === slug ? void 0 : ITEM_ACTIONS[bare];
70
69
  }
71
70
  function resolveItemAction(slug, entry, itemType) {
72
71
  var _a, _b;
@@ -68,9 +68,6 @@ export interface DecisionContext {
68
68
  }
69
69
  /** "[[SRD 2024/Classes/Fighter]]" → "fighter" (tail segment, slugified). */
70
70
  export declare function wikilinkTailSlug(link: string): string;
71
- /** "srd-2024_fighter" → "fighter". Tolerates a nullish slug (degrades to "") so a
72
- * malformed entity can't hard-crash the builder; the resolver backfills real slugs. */
73
- export declare function bareEntitySlug(slug: string | null | undefined): string;
74
71
  declare function matchesFilter(e: RegisteredEntity, where: EntityFilter, ownerBare: string): boolean;
75
72
  /** Test-only export of {@link matchesFilter} (Task B2). */
76
73
  export declare const __matchesFilterForTest: typeof matchesFilter;
@@ -1,24 +1,22 @@
1
1
  import {
2
2
  __matchesFilterForTest,
3
- bareEntitySlug,
4
3
  buildDecisionLedger,
5
4
  collectChosenAbilityPoints,
6
5
  collectChosenProficiencies,
7
6
  wikilinkTailSlug
8
- } from "../chunk-R5SQHP2X.js";
7
+ } from "../chunk-5MZSB6OM.js";
9
8
  import "../chunk-BH6AMZVY.js";
10
- import "../chunk-UC4FE5X3.js";
11
- import "../chunk-IXZXFFFW.js";
9
+ import "../chunk-M2EMFD6S.js";
12
10
  import "../chunk-5XUXXAQJ.js";
13
11
  import "../chunk-JEYQU3JT.js";
14
- import "../chunk-DC74TZNA.js";
15
- import "../chunk-3TRGRSCH.js";
16
- import "../chunk-J2RYSZMQ.js";
12
+ import "../chunk-N6N74K6X.js";
13
+ import "../chunk-4LZJXJJS.js";
14
+ import "../chunk-LV4SNWZQ.js";
15
+ import "../chunk-VTTA2ALZ.js";
17
16
  import "../chunk-NAEPSZAM.js";
18
17
  import "../chunk-WP2CX2JO.js";
19
18
  export {
20
19
  __matchesFilterForTest,
21
- bareEntitySlug,
22
20
  buildDecisionLedger,
23
21
  collectChosenAbilityPoints,
24
22
  collectChosenProficiencies,
@@ -2,20 +2,13 @@ import {
2
2
  computeAppliedBonuses,
3
3
  computeSlotsAndAttacks,
4
4
  emptyAppliedBonuses
5
- } from "../chunk-TQZB4OCJ.js";
6
- import "../chunk-R5SQHP2X.js";
7
- import "../chunk-BH6AMZVY.js";
8
- import "../chunk-UC4FE5X3.js";
9
- import "../chunk-IXZXFFFW.js";
10
- import "../chunk-5XUXXAQJ.js";
11
- import "../chunk-JEYQU3JT.js";
5
+ } from "../chunk-EMOORSQ7.js";
6
+ import "../chunk-353WXS6S.js";
7
+ import "../chunk-N6N74K6X.js";
12
8
  import "../chunk-LWFTHJIE.js";
13
9
  import "../chunk-DNAJRMNN.js";
14
- import "../chunk-DC74TZNA.js";
15
- import "../chunk-3TRGRSCH.js";
16
- import "../chunk-J2RYSZMQ.js";
17
- import "../chunk-NAEPSZAM.js";
18
- import "../chunk-WP2CX2JO.js";
10
+ import "../chunk-4LZJXJJS.js";
11
+ import "../chunk-LV4SNWZQ.js";
19
12
  export {
20
13
  computeAppliedBonuses,
21
14
  computeSlotsAndAttacks,
@@ -24,6 +24,11 @@ export interface WeaponAbilityOverride {
24
24
  export interface FeatureEffectTotals {
25
25
  initiative_bonus: number;
26
26
  hp_per_level_bonus: number;
27
+ /** One term per hp-per-level-bonus effect, labeled with the owning feature's name. */
28
+ hp_per_level_terms: {
29
+ label: string;
30
+ value: number;
31
+ }[];
27
32
  speed_walk_bonus: number;
28
33
  /**
29
34
  * Absolute walk-speed FLOOR from `speed-bonus` effects with `set:true` (e.g.
@@ -1,17 +1,8 @@
1
1
  import {
2
2
  computeFeatureEffects,
3
3
  emptyFeatureEffectTotals
4
- } from "../chunk-V6SOFUJW.js";
5
- import "../chunk-R5SQHP2X.js";
6
- import "../chunk-BH6AMZVY.js";
7
- import "../chunk-UC4FE5X3.js";
8
- import "../chunk-IXZXFFFW.js";
9
- import "../chunk-5XUXXAQJ.js";
10
- import "../chunk-JEYQU3JT.js";
11
- import "../chunk-DC74TZNA.js";
12
- import "../chunk-3TRGRSCH.js";
13
- import "../chunk-J2RYSZMQ.js";
14
- import "../chunk-NAEPSZAM.js";
4
+ } from "../chunk-AIRFC5NQ.js";
5
+ import "../chunk-LV4SNWZQ.js";
15
6
  import "../chunk-WP2CX2JO.js";
16
7
  export {
17
8
  computeFeatureEffects,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  characterSchema
3
- } from "../chunk-5WQD3WNZ.js";
3
+ } from "../chunk-A4WENOUQ.js";
4
4
  import "../chunk-TZK36BU7.js";
5
5
 
6
6
  // src/pc/pc.parser.ts
@@ -2,15 +2,15 @@ import {
2
2
  levelPrereqMax,
3
3
  resolveAllPools,
4
4
  resolvePool
5
- } from "../chunk-R5SQHP2X.js";
5
+ } from "../chunk-5MZSB6OM.js";
6
6
  import "../chunk-BH6AMZVY.js";
7
- import "../chunk-UC4FE5X3.js";
8
- import "../chunk-IXZXFFFW.js";
7
+ import "../chunk-M2EMFD6S.js";
9
8
  import "../chunk-5XUXXAQJ.js";
10
9
  import "../chunk-JEYQU3JT.js";
11
- import "../chunk-DC74TZNA.js";
12
- import "../chunk-3TRGRSCH.js";
13
- import "../chunk-J2RYSZMQ.js";
10
+ import "../chunk-N6N74K6X.js";
11
+ import "../chunk-4LZJXJJS.js";
12
+ import "../chunk-LV4SNWZQ.js";
13
+ import "../chunk-VTTA2ALZ.js";
14
14
  import "../chunk-NAEPSZAM.js";
15
15
  import "../chunk-WP2CX2JO.js";
16
16
  export {
@@ -45,11 +45,18 @@ export declare function abilityBonusBreakdown(resolved: ResolvedCharacter): Reco
45
45
  class: number;
46
46
  feat: number;
47
47
  }>;
48
+ /** Dice-only portion of PC max HP: first VALID level anywhere = max(die),
49
+ * every later valid level = PHB average. Skip rule identical to hpLevelCount. */
50
+ export declare function hitDiceAverageSum(classes: ResolvedClass[]): number;
51
+ /** Count of levels that contribute to HP (valid class entries only). */
52
+ export declare function hpLevelCount(classes: ResolvedClass[]): number;
48
53
  /**
49
54
  * PC-oriented multiclass HP.
50
55
  * - First class's first level: max(hit_die) + conMod.
51
56
  * - Every subsequent level (in any class): phbAverageForDie(thatLevel'sClass) + conMod.
52
57
  * CON mod contributes once per total level.
58
+ * Decomposed (P5 T2) into hitDiceAverageSum (dice-only) + hpLevelCount (level count),
59
+ * so a later popup can render the two components separately.
53
60
  */
54
61
  export declare function multiclassMaxHP(classes: ResolvedClass[], conMod: number): number;
55
62
  /**
@@ -1,32 +1,33 @@
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";
7
+ } from "../chunk-5MZSB6OM.js";
16
8
  import "../chunk-BH6AMZVY.js";
17
- import "../chunk-UC4FE5X3.js";
18
9
  import {
19
10
  computeSpellLimits,
20
11
  deriveSpellSlots,
21
12
  resolveSpellcasting
22
- } from "../chunk-IXZXFFFW.js";
13
+ } from "../chunk-M2EMFD6S.js";
23
14
  import "../chunk-5XUXXAQJ.js";
24
15
  import "../chunk-JEYQU3JT.js";
16
+ import {
17
+ computeAppliedBonuses,
18
+ computeSlotsAndAttacks,
19
+ emptyAppliedBonuses
20
+ } from "../chunk-EMOORSQ7.js";
21
+ import "../chunk-353WXS6S.js";
22
+ import "../chunk-N6N74K6X.js";
23
+ import {
24
+ computeFeatureEffects
25
+ } from "../chunk-AIRFC5NQ.js";
25
26
  import "../chunk-LWFTHJIE.js";
26
27
  import "../chunk-DNAJRMNN.js";
27
- import "../chunk-DC74TZNA.js";
28
- import "../chunk-3TRGRSCH.js";
29
- import "../chunk-J2RYSZMQ.js";
28
+ import "../chunk-4LZJXJJS.js";
29
+ import "../chunk-LV4SNWZQ.js";
30
+ import "../chunk-VTTA2ALZ.js";
30
31
  import {
31
32
  abilityModifier,
32
33
  attackBonus,
@@ -117,7 +118,7 @@ function abilityBonusBreakdown(resolved) {
117
118
  }
118
119
  return out;
119
120
  }
120
- function multiclassMaxHP(classes, conMod) {
121
+ function hitDiceAverageSum(classes) {
121
122
  var _a;
122
123
  let total = 0;
123
124
  let firstLevelCounted = false;
@@ -126,14 +127,27 @@ function multiclassMaxHP(classes, conMod) {
126
127
  if (!c.entity || die == null || c.level < 1) continue;
127
128
  for (let lvl = 1; lvl <= c.level; lvl++) {
128
129
  if (!firstLevelCounted) {
129
- total += die + conMod;
130
+ total += die;
130
131
  firstLevelCounted = true;
131
132
  } else {
132
- total += Math.floor(die / 2) + 1 + conMod;
133
+ total += Math.floor(die / 2) + 1;
133
134
  }
134
135
  }
135
136
  }
136
- return Math.max(1, total);
137
+ return total;
138
+ }
139
+ function hpLevelCount(classes) {
140
+ var _a;
141
+ let count = 0;
142
+ for (const c of classes) {
143
+ const die = parseDieSize((_a = c.entity) == null ? void 0 : _a.hit_die);
144
+ if (!c.entity || die == null || c.level < 1) continue;
145
+ count += c.level;
146
+ }
147
+ return count;
148
+ }
149
+ function multiclassMaxHP(classes, conMod) {
150
+ return Math.max(1, hitDiceAverageSum(classes) + conMod * hpLevelCount(classes));
137
151
  }
138
152
  function unarmoredAC(resolved, mods, warnings) {
139
153
  return unarmoredACBreakdown(resolved, mods, warnings).total;
@@ -362,7 +376,7 @@ function computeProficiencies(resolved) {
362
376
  };
363
377
  }
364
378
  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;
379
+ 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, _Z, __, _$, _aa;
366
380
  const warnings = [];
367
381
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
368
382
  const chosenProfs = collectChosenProficiencies(resolved);
@@ -484,9 +498,36 @@ function recalc(resolved, registry) {
484
498
  investigation: (_t = (_s = overrides.passives) == null ? void 0 : _s.investigation) != null ? _t : passive(scores.int, investigationTri, proficiencyBonus),
485
499
  insight: (_v = (_u = overrides.passives) == null ? void 0 : _u.insight) != null ? _v : passive(scores.wis, insightTri, proficiencyBonus)
486
500
  };
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;
501
+ const hpRolled = (_x = (_w = overrides.hp) == null ? void 0 : _w.rolled) != null ? _x : null;
502
+ const hpModifier = (_z = (_y = overrides.hp) == null ? void 0 : _y.modifier) != null ? _z : null;
503
+ const averageDiceSum = hitDiceAverageSum(resolved.classes);
504
+ const conLevels = hpLevelCount(resolved.classes);
505
+ const diceSum = hpRolled != null ? hpRolled : averageDiceSum;
506
+ const diceConRaw = diceSum + mods.con * conLevels;
507
+ const diceConClamped = Math.max(1, diceConRaw);
508
+ const hpMaxDerived = diceConClamped + featureEffects.hp_per_level_bonus * totalLevel + (hpModifier != null ? hpModifier : 0);
509
+ const hpMaxAfterConditions = Math.max(0, Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier));
510
+ const hpMax = (_B = (_A = overrides.hp) == null ? void 0 : _A.max) != null ? _B : hpMaxAfterConditions;
511
+ const hpBreakdown = {
512
+ diceSum,
513
+ diceSource: hpRolled != null ? "rolled" : "average",
514
+ averageDiceSum,
515
+ conMod: mods.con,
516
+ conLevels,
517
+ clampApplied: diceConClamped !== diceConRaw,
518
+ perLevelTerms: featureEffects.hp_per_level_terms.map((t) => ({
519
+ label: t.label,
520
+ perLevel: t.value,
521
+ levels: totalLevel,
522
+ total: t.value * totalLevel
523
+ })),
524
+ modifier: hpModifier,
525
+ exhaustionMultiplier: conditionEffects.hp_max_multiplier,
526
+ exhaustionLevel: conditionEffects.exhaustion_level,
527
+ derivedMax: hpMaxAfterConditions,
528
+ override: (_D = (_C = overrides.hp) == null ? void 0 : _C.max) != null ? _D : null,
529
+ final: hpMax
530
+ };
490
531
  const featureAcTermsFor = (hasArmor) => featureEffects.ac_terms.filter((t) => !t.requires_armor || hasArmor).map((t) => ({ source: t.label, amount: t.value, kind: "feature" }));
491
532
  const sumTerms = (terms) => terms.reduce((s, t) => s + t.amount, 0);
492
533
  const weaponAbilities = [...featureEffects.weaponAbilities];
@@ -511,7 +552,7 @@ function recalc(resolved, registry) {
511
552
  let acBreakdownDerived = [];
512
553
  let acInformationalDerived = [];
513
554
  if (registry) {
514
- derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_y = resolved.weaponMasteries) != null ? _y : []);
555
+ derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_E = resolved.weaponMasteries) != null ? _E : []);
515
556
  if (derivedEquipment.equippedSlots.armor) {
516
557
  const featTerms = featureAcTermsFor(true);
517
558
  acDerived = derivedEquipment.ac + sumTerms(featTerms);
@@ -534,16 +575,16 @@ function recalc(resolved, registry) {
534
575
  acDerived = total + sumTerms(featTerms);
535
576
  acBreakdownDerived = [...terms, ...featTerms];
536
577
  }
537
- const ac = (_z = overrides.ac) != null ? _z : acDerived;
578
+ const ac = (_F = overrides.ac) != null ? _F : acDerived;
538
579
  const additiveSpeed = speedFromRace(resolved) + applied.speed_bonuses.walk + featureEffects.speed_walk_bonus;
539
580
  const baseSpeed = Math.max(featureEffects.speed_walk_set, additiveSpeed);
540
581
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
541
582
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
542
- const speed = (_A = overrides.speed) != null ? _A : conditionSpeed;
583
+ const speed = (_G = overrides.speed) != null ? _G : conditionSpeed;
543
584
  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;
585
+ const init = (_H = overrides.initiative) != null ? _H : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
545
586
  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),
587
+ 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
588
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
548
589
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
549
590
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -561,8 +602,8 @@ function recalc(resolved, registry) {
561
602
  classSlug: c.entity.slug,
562
603
  className: c.entity.name,
563
604
  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,
605
+ saveDC: (_M = (_L = overrides.spellcasting) == null ? void 0 : _L.saveDC) != null ? _M : dc,
606
+ attackBonus: (_O = (_N = overrides.spellcasting) == null ? void 0 : _N.attackBonus) != null ? _O : atk,
566
607
  casterType: profile.casterType,
567
608
  preparation: profile.preparation
568
609
  });
@@ -587,20 +628,20 @@ function recalc(resolved, registry) {
587
628
  const spellLimits = computeSpellLimits(limitInputs);
588
629
  const defenses = {
589
630
  resistances: dedupeDefenseList([
590
- (_K = (_J = resolved.definition.defenses) == null ? void 0 : _J.resistances) != null ? _K : [],
631
+ (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.resistances) != null ? _Q : [],
591
632
  applied.defenses.resistances,
592
633
  featureEffects.resistances
593
634
  ]),
594
635
  immunities: dedupeDefenseList([
595
- (_M = (_L = resolved.definition.defenses) == null ? void 0 : _L.immunities) != null ? _M : [],
636
+ (_S = (_R = resolved.definition.defenses) == null ? void 0 : _R.immunities) != null ? _S : [],
596
637
  applied.defenses.immunities
597
638
  ]),
598
639
  vulnerabilities: dedupeDefenseList([
599
- (_O = (_N = resolved.definition.defenses) == null ? void 0 : _N.vulnerabilities) != null ? _O : [],
640
+ (_U = (_T = resolved.definition.defenses) == null ? void 0 : _T.vulnerabilities) != null ? _U : [],
600
641
  applied.defenses.vulnerabilities
601
642
  ]),
602
643
  condition_immunities: dedupeDefenseList([
603
- (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.condition_immunities) != null ? _Q : [],
644
+ (_W = (_V = resolved.definition.defenses) == null ? void 0 : _V.condition_immunities) != null ? _W : [],
604
645
  applied.defenses.condition_immunities,
605
646
  featureEffects.condition_immunities
606
647
  ])
@@ -620,6 +661,7 @@ function recalc(resolved, registry) {
620
661
  current: resolved.state.hp.current,
621
662
  temp: resolved.state.hp.temp
622
663
  },
664
+ hpBreakdown,
623
665
  ac,
624
666
  speed,
625
667
  initiative: init,
@@ -643,7 +685,7 @@ function recalc(resolved, registry) {
643
685
  // untouched rows keep `critRange`/`attackNotes` ABSENT (not 20 / not []).
644
686
  // crit-range: folded weapon crit threshold, only when an effect lowered it.
645
687
  // attackNotes: reroll-damage / attack-rule captions, only when non-empty.
646
- attacks: ((_R = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _R : []).map((a) => {
688
+ attacks: ((_X = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _X : []).map((a) => {
647
689
  var _a2;
648
690
  const riders = [...(_a2 = a.damageRiders) != null ? _a2 : [], ...featureEffects.damageBonuses];
649
691
  return {
@@ -654,10 +696,10 @@ function recalc(resolved, registry) {
654
696
  ...riders.length ? { damageRiders: riders } : {}
655
697
  };
656
698
  }),
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,
699
+ equippedSlots: (_Y = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _Y : {},
700
+ carriedWeight: (_Z = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _Z : 0,
701
+ attunementUsed: (__ = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? __ : 0,
702
+ attunementLimit: (_aa = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _aa : (_$ = overrides.attunement_limit) != null ? _$ : 3,
661
703
  conditionEffects,
662
704
  rollModifiers: featureEffects.rollModifiers
663
705
  };
@@ -669,6 +711,8 @@ export {
669
711
  computeAbilityScores,
670
712
  computeProficiencies,
671
713
  flattenRaceAsi,
714
+ hitDiceAverageSum,
715
+ hpLevelCount,
672
716
  initiativeBonus,
673
717
  multiclassMaxHP,
674
718
  parseDieSize,
@@ -9,15 +9,15 @@ import {
9
9
  dedupeResolvedSpells,
10
10
  resolveOriginFeat,
11
11
  stripSlug
12
- } from "../chunk-R5SQHP2X.js";
12
+ } from "../chunk-5MZSB6OM.js";
13
13
  import "../chunk-BH6AMZVY.js";
14
- import "../chunk-UC4FE5X3.js";
15
- import "../chunk-IXZXFFFW.js";
14
+ import "../chunk-M2EMFD6S.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,6 +221,8 @@ 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>;
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  characterSchema
3
- } from "../chunk-5WQD3WNZ.js";
3
+ } from "../chunk-A4WENOUQ.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,
@@ -3,9 +3,9 @@ import {
3
3
  deriveSpellSlots,
4
4
  normalizeKnownSpell,
5
5
  resolveSpellcasting
6
- } from "../chunk-IXZXFFFW.js";
6
+ } from "../chunk-M2EMFD6S.js";
7
7
  import "../chunk-5XUXXAQJ.js";
8
- import "../chunk-J2RYSZMQ.js";
8
+ import "../chunk-VTTA2ALZ.js";
9
9
  import "../chunk-NAEPSZAM.js";
10
10
  import "../chunk-WP2CX2JO.js";
11
11
  export {