@archivist-gg/dnd5e 0.3.6 → 0.3.8

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 (70) hide show
  1. package/dist/background/background.codec.js +5 -5
  2. package/dist/background/background.parser.js +4 -4
  3. package/dist/background/background.schema.js +3 -3
  4. package/dist/{chunk-3PZHBLFG.js → chunk-2Q374PZ3.js} +1 -1
  5. package/dist/{chunk-BJFL4KYG.js → chunk-47SCRXGM.js} +3 -3
  6. package/dist/{chunk-MYW7AOUE.js → chunk-5QM7YNGV.js} +1 -1
  7. package/dist/{chunk-ABQ6ZWAF.js → chunk-5SMMRAO2.js} +1 -1
  8. package/dist/{chunk-7MRW4RTH.js → chunk-5VTDYZIW.js} +1 -1
  9. package/dist/{chunk-BS355LND.js → chunk-DIAYWWHG.js} +1 -1
  10. package/dist/{chunk-H4VEMVOO.js → chunk-EISRDJUV.js} +1 -1
  11. package/dist/{chunk-7WNQJAZW.js → chunk-FYM3ROGA.js} +2 -2
  12. package/dist/{chunk-MT4RWROQ.js → chunk-GD2CFJ3T.js} +2 -2
  13. package/dist/{chunk-CQAL67R3.js → chunk-HRG4URUK.js} +1 -1
  14. package/dist/{chunk-A6YL53NC.js → chunk-IVLA24R3.js} +1 -1
  15. package/dist/{chunk-KPEJMNRD.js → chunk-IXMS2HHP.js} +22 -7
  16. package/dist/{chunk-IWRVOCT5.js → chunk-LEHDXPY6.js} +1 -1
  17. package/dist/{chunk-JOVMV2X5.js → chunk-N4JJNGLZ.js} +3 -3
  18. package/dist/{chunk-63XQXPZL.js → chunk-O5WXS3G5.js} +1 -1
  19. package/dist/{chunk-E4KG7HXO.js → chunk-PZCE7DJM.js} +9 -0
  20. package/dist/{chunk-DTCR4DBF.js → chunk-Q6L2RASW.js} +3 -3
  21. package/dist/{chunk-2BI5NAXK.js → chunk-QCKOVD3K.js} +2 -2
  22. package/dist/{chunk-NNAQ4KQF.js → chunk-RW42SHFM.js} +1 -1
  23. package/dist/{chunk-EYZCCWG2.js → chunk-TEKRIRNZ.js} +1 -1
  24. package/dist/{chunk-B4TQTJVC.js → chunk-U3DNWCEI.js} +1 -1
  25. package/dist/{chunk-RWZTGMSN.js → chunk-UYBCC473.js} +1 -1
  26. package/dist/{chunk-ULCQ73LA.js → chunk-VMIFD2RB.js} +1 -1
  27. package/dist/{chunk-X3D6LXUU.js → chunk-VTKJOAJD.js} +1 -0
  28. package/dist/{chunk-3BMVVNCS.js → chunk-WNQ2O2IS.js} +1 -1
  29. package/dist/{chunk-JKLRBILX.js → chunk-YRTI2FLD.js} +1 -1
  30. package/dist/{chunk-UA3I2YSO.js → chunk-ZJXSXVFP.js} +1 -1
  31. package/dist/class/class.codec.js +7 -7
  32. package/dist/class/class.parser.js +6 -6
  33. package/dist/class/class.schema.js +5 -5
  34. package/dist/feat/feat.codec.js +6 -6
  35. package/dist/feat/feat.parser.js +5 -5
  36. package/dist/feat/feat.schema.d.ts +14 -0
  37. package/dist/feat/feat.schema.js +4 -4
  38. package/dist/index.js +24 -24
  39. package/dist/monster/monster.parser.js +6 -6
  40. package/dist/monster/monster.schema.js +5 -5
  41. package/dist/optional-feature/optional-feature.codec.js +5 -5
  42. package/dist/optional-feature/optional-feature.parser.js +4 -4
  43. package/dist/optional-feature/optional-feature.schema.d.ts +15 -0
  44. package/dist/optional-feature/optional-feature.schema.js +3 -3
  45. package/dist/pc/pc.decision-engine.js +2 -2
  46. package/dist/pc/pc.feature-effects.d.ts +15 -0
  47. package/dist/pc/pc.feature-effects.js +1 -1
  48. package/dist/pc/pc.parser.js +1 -1
  49. package/dist/pc/pc.proficiencies.js +2 -2
  50. package/dist/pc/pc.recalc.js +45 -15
  51. package/dist/pc/pc.resolver.js +2 -2
  52. package/dist/pc/pc.rest.js +17 -11
  53. package/dist/pc/pc.schema.d.ts +1 -0
  54. package/dist/pc/pc.schema.js +1 -1
  55. package/dist/pc/pc.types.d.ts +22 -0
  56. package/dist/race/race.codec.js +7 -7
  57. package/dist/race/race.parser.js +6 -6
  58. package/dist/race/race.schema.js +5 -5
  59. package/dist/schemas/choice-schema.js +2 -2
  60. package/dist/schemas/feature-effect-schema.d.ts +14 -0
  61. package/dist/schemas/feature-effect-schema.js +1 -1
  62. package/dist/schemas/feature-schema.js +4 -4
  63. package/dist/schemas/resource-schema.d.ts +1 -0
  64. package/dist/schemas/resource-schema.js +1 -1
  65. package/dist/subclass/subclass.codec.js +7 -7
  66. package/dist/subclass/subclass.parser.js +6 -6
  67. package/dist/subclass/subclass.schema.js +5 -5
  68. package/dist/types/feature-effect.d.ts +5 -0
  69. package/dist/types/resource.d.ts +1 -1
  70. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5,9 +5,9 @@ import "./chunk-HZA7OE7N.js";
5
5
  import "./chunk-2DFENQIJ.js";
6
6
  import {
7
7
  subclassCodec
8
- } from "./chunk-B4TQTJVC.js";
9
- import "./chunk-ABQ6ZWAF.js";
10
- import "./chunk-MT4RWROQ.js";
8
+ } from "./chunk-U3DNWCEI.js";
9
+ import "./chunk-5SMMRAO2.js";
10
+ import "./chunk-GD2CFJ3T.js";
11
11
  import {
12
12
  spellInputSchema
13
13
  } from "./chunk-656QCX4U.js";
@@ -19,9 +19,9 @@ import {
19
19
  } from "./chunk-WSVMLNTO.js";
20
20
  import {
21
21
  raceCodec
22
- } from "./chunk-CQAL67R3.js";
23
- import "./chunk-7MRW4RTH.js";
24
- import "./chunk-2BI5NAXK.js";
22
+ } from "./chunk-HRG4URUK.js";
23
+ import "./chunk-5VTDYZIW.js";
24
+ import "./chunk-QCKOVD3K.js";
25
25
  import "./chunk-OZP6JFGT.js";
26
26
  import "./chunk-VQAXTIBW.js";
27
27
  import {
@@ -34,14 +34,14 @@ import {
34
34
  } from "./chunk-6PXTNCBP.js";
35
35
  import {
36
36
  parseMonster
37
- } from "./chunk-3BMVVNCS.js";
38
- import "./chunk-A6YL53NC.js";
37
+ } from "./chunk-WNQ2O2IS.js";
38
+ import "./chunk-IVLA24R3.js";
39
39
  import "./chunk-IKSMX4TN.js";
40
40
  import {
41
41
  optionalFeatureCodec
42
- } from "./chunk-MYW7AOUE.js";
43
- import "./chunk-NNAQ4KQF.js";
44
- import "./chunk-7WNQJAZW.js";
42
+ } from "./chunk-5QM7YNGV.js";
43
+ import "./chunk-RW42SHFM.js";
44
+ import "./chunk-FYM3ROGA.js";
45
45
  import {
46
46
  itemCodec
47
47
  } from "./chunk-4XTNPNQB.js";
@@ -64,23 +64,23 @@ import {
64
64
  } from "./chunk-LSLSG67V.js";
65
65
  import {
66
66
  featCodec
67
- } from "./chunk-JKLRBILX.js";
68
- import "./chunk-RWZTGMSN.js";
69
- import "./chunk-BJFL4KYG.js";
67
+ } from "./chunk-YRTI2FLD.js";
68
+ import "./chunk-UYBCC473.js";
69
+ import "./chunk-47SCRXGM.js";
70
70
  import "./chunk-DEEHHLAP.js";
71
71
  import "./chunk-PDJSUH24.js";
72
72
  import "./chunk-WELIKLZF.js";
73
73
  import {
74
74
  classCodec
75
- } from "./chunk-BS355LND.js";
76
- import "./chunk-H4VEMVOO.js";
75
+ } from "./chunk-DIAYWWHG.js";
76
+ import "./chunk-EISRDJUV.js";
77
77
  import "./chunk-4U55VNC7.js";
78
- import "./chunk-DTCR4DBF.js";
78
+ import "./chunk-Q6L2RASW.js";
79
79
  import "./chunk-23LZLBJK.js";
80
80
  import "./chunk-CJYCVNW2.js";
81
- import "./chunk-JOVMV2X5.js";
81
+ import "./chunk-N4JJNGLZ.js";
82
82
  import "./chunk-WYGD2UGN.js";
83
- import "./chunk-UA3I2YSO.js";
83
+ import "./chunk-ZJXSXVFP.js";
84
84
  import {
85
85
  parseCondition
86
86
  } from "./chunk-6X2NV665.js";
@@ -91,12 +91,12 @@ import "./chunk-5N2GW72F.js";
91
91
  import "./chunk-JC5UNIVM.js";
92
92
  import {
93
93
  backgroundCodec
94
- } from "./chunk-ULCQ73LA.js";
95
- import "./chunk-3PZHBLFG.js";
96
- import "./chunk-63XQXPZL.js";
94
+ } from "./chunk-VMIFD2RB.js";
95
+ import "./chunk-2Q374PZ3.js";
96
+ import "./chunk-O5WXS3G5.js";
97
97
  import "./chunk-IN4M4X7P.js";
98
- import "./chunk-IWRVOCT5.js";
99
- import "./chunk-X3D6LXUU.js";
98
+ import "./chunk-LEHDXPY6.js";
99
+ import "./chunk-VTKJOAJD.js";
100
100
  import "./chunk-UA5KS2PL.js";
101
101
 
102
102
  // src/monster/monster.codec.ts
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  migrateLegacy,
3
3
  parseMonster
4
- } from "../chunk-3BMVVNCS.js";
5
- import "../chunk-A6YL53NC.js";
6
- import "../chunk-JOVMV2X5.js";
4
+ } from "../chunk-WNQ2O2IS.js";
5
+ import "../chunk-IVLA24R3.js";
6
+ import "../chunk-N4JJNGLZ.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
- import "../chunk-UA3I2YSO.js";
9
- import "../chunk-IWRVOCT5.js";
10
- import "../chunk-X3D6LXUU.js";
8
+ import "../chunk-ZJXSXVFP.js";
9
+ import "../chunk-LEHDXPY6.js";
10
+ import "../chunk-VTKJOAJD.js";
11
11
  import "../chunk-UA5KS2PL.js";
12
12
  export {
13
13
  migrateLegacy,
@@ -11,12 +11,12 @@ import {
11
11
  monsterSpeedSchema,
12
12
  monsterSpellcastingSchema,
13
13
  monsterTypeSchema
14
- } from "../chunk-A6YL53NC.js";
15
- import "../chunk-JOVMV2X5.js";
14
+ } from "../chunk-IVLA24R3.js";
15
+ import "../chunk-N4JJNGLZ.js";
16
16
  import "../chunk-WYGD2UGN.js";
17
- import "../chunk-UA3I2YSO.js";
18
- import "../chunk-IWRVOCT5.js";
19
- import "../chunk-X3D6LXUU.js";
17
+ import "../chunk-ZJXSXVFP.js";
18
+ import "../chunk-LEHDXPY6.js";
19
+ import "../chunk-VTKJOAJD.js";
20
20
  import "../chunk-UA5KS2PL.js";
21
21
  export {
22
22
  MONSTER_KNOWN_KEYS,
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  optionalFeatureCodec
3
- } from "../chunk-MYW7AOUE.js";
4
- import "../chunk-NNAQ4KQF.js";
5
- import "../chunk-7WNQJAZW.js";
3
+ } from "../chunk-5QM7YNGV.js";
4
+ import "../chunk-RW42SHFM.js";
5
+ import "../chunk-FYM3ROGA.js";
6
6
  import "../chunk-WYGD2UGN.js";
7
- import "../chunk-UA3I2YSO.js";
8
- import "../chunk-X3D6LXUU.js";
7
+ import "../chunk-ZJXSXVFP.js";
8
+ import "../chunk-VTKJOAJD.js";
9
9
  import "../chunk-UA5KS2PL.js";
10
10
  export {
11
11
  optionalFeatureCodec
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  parseOptionalFeature
3
- } from "../chunk-NNAQ4KQF.js";
4
- import "../chunk-7WNQJAZW.js";
3
+ } from "../chunk-RW42SHFM.js";
4
+ import "../chunk-FYM3ROGA.js";
5
5
  import "../chunk-WYGD2UGN.js";
6
- import "../chunk-UA3I2YSO.js";
7
- import "../chunk-X3D6LXUU.js";
6
+ import "../chunk-ZJXSXVFP.js";
7
+ import "../chunk-VTKJOAJD.js";
8
8
  import "../chunk-UA5KS2PL.js";
9
9
  export {
10
10
  parseOptionalFeature
@@ -65,6 +65,20 @@ export declare const optionalFeatureEntitySchema: z.ZodObject<{
65
65
  value: z.ZodNumber;
66
66
  condition: z.ZodOptional<z.ZodString>;
67
67
  subject: z.ZodOptional<z.ZodString>;
68
+ }, z.core.$strip>, z.ZodObject<{
69
+ kind: z.ZodLiteral<"skill-bonus">;
70
+ skills: z.ZodArray<z.ZodString>;
71
+ ability: z.ZodEnum<{
72
+ str: "str";
73
+ dex: "dex";
74
+ con: "con";
75
+ int: "int";
76
+ wis: "wis";
77
+ cha: "cha";
78
+ }>;
79
+ minimum: z.ZodOptional<z.ZodNumber>;
80
+ condition: z.ZodOptional<z.ZodString>;
81
+ subject: z.ZodOptional<z.ZodString>;
68
82
  }, z.core.$strip>, z.ZodObject<{
69
83
  kind: z.ZodLiteral<"immune-condition">;
70
84
  condition: z.ZodString;
@@ -364,6 +378,7 @@ export declare const optionalFeatureEntitySchema: z.ZodObject<{
364
378
  }, z.core.$strip>>>;
365
379
  consumes: z.ZodOptional<z.ZodNullable<z.ZodObject<{
366
380
  source: z.ZodOptional<z.ZodEnum<{
381
+ "spell-slots": "spell-slots";
367
382
  resource: "resource";
368
383
  "class-column": "class-column";
369
384
  "attack-dice": "attack-dice";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  optionalFeatureEntitySchema
3
- } from "../chunk-7WNQJAZW.js";
3
+ } from "../chunk-FYM3ROGA.js";
4
4
  import "../chunk-WYGD2UGN.js";
5
- import "../chunk-UA3I2YSO.js";
6
- import "../chunk-X3D6LXUU.js";
5
+ import "../chunk-ZJXSXVFP.js";
6
+ import "../chunk-VTKJOAJD.js";
7
7
  import "../chunk-UA5KS2PL.js";
8
8
  export {
9
9
  optionalFeatureEntitySchema
@@ -4,7 +4,7 @@ import {
4
4
  collectChosenAbilityPoints,
5
5
  collectChosenProficiencies,
6
6
  computeEffectiveProficiencies
7
- } from "../chunk-EYZCCWG2.js";
7
+ } from "../chunk-TEKRIRNZ.js";
8
8
  import "../chunk-4ISR76DH.js";
9
9
  import "../chunk-DPUJDOKV.js";
10
10
  import "../chunk-O4SRD3J5.js";
@@ -14,7 +14,7 @@ import "../chunk-YHYTW5QA.js";
14
14
  import "../chunk-MI7P3NX3.js";
15
15
  import "../chunk-PVCEA4HZ.js";
16
16
  import "../chunk-UBBKSYBY.js";
17
- import "../chunk-KPEJMNRD.js";
17
+ import "../chunk-IXMS2HHP.js";
18
18
  import "../chunk-TOM66P2P.js";
19
19
  import "../chunk-KU3YLF6D.js";
20
20
  import "../chunk-RLGQ5PZZ.js";
@@ -23,6 +23,17 @@ export interface WeaponAbilityOverride {
23
23
  */
24
24
  export interface FeatureEffectTotals {
25
25
  initiative_bonus: number;
26
+ initiative_terms: {
27
+ label: string;
28
+ value: number;
29
+ }[];
30
+ /** Ability-based numeric skill bonuses, resolved against final scores in recalc. */
31
+ skill_bonus_terms: {
32
+ skills: string[];
33
+ ability: Ability;
34
+ minimum: number;
35
+ label: string;
36
+ }[];
26
37
  hp_per_level_bonus: number;
27
38
  /** One term per hp-per-level-bonus effect, labeled with the owning feature's name. */
28
39
  hp_per_level_terms: {
@@ -30,6 +41,10 @@ export interface FeatureEffectTotals {
30
41
  value: number;
31
42
  }[];
32
43
  speed_walk_bonus: number;
44
+ speed_walk_terms: {
45
+ label: string;
46
+ value: number;
47
+ }[];
33
48
  /**
34
49
  * Absolute walk-speed FLOOR from `speed-bonus` effects with `set:true` (e.g.
35
50
  * a "base speed becomes 60" feature). Max across all set effects; 0 = none.
@@ -7,7 +7,7 @@ import {
7
7
  foldsNow,
8
8
  foldsOnSelf,
9
9
  selfEffectsOf
10
- } from "../chunk-KPEJMNRD.js";
10
+ } from "../chunk-IXMS2HHP.js";
11
11
  import "../chunk-TOM66P2P.js";
12
12
  import "../chunk-KU3YLF6D.js";
13
13
  import "../chunk-RLGQ5PZZ.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  characterSchema
3
- } from "../chunk-E4KG7HXO.js";
3
+ } from "../chunk-PZCE7DJM.js";
4
4
  import "../chunk-S7REMWW4.js";
5
5
 
6
6
  // src/pc/pc.parser.ts
@@ -2,7 +2,7 @@ import {
2
2
  collectChosenProficiencies,
3
3
  collectProficiencyGrants,
4
4
  computeEffectiveProficiencies
5
- } from "../chunk-EYZCCWG2.js";
5
+ } from "../chunk-TEKRIRNZ.js";
6
6
  import "../chunk-4ISR76DH.js";
7
7
  import "../chunk-DPUJDOKV.js";
8
8
  import "../chunk-O4SRD3J5.js";
@@ -12,7 +12,7 @@ import "../chunk-YHYTW5QA.js";
12
12
  import "../chunk-MI7P3NX3.js";
13
13
  import "../chunk-PVCEA4HZ.js";
14
14
  import "../chunk-UBBKSYBY.js";
15
- import "../chunk-KPEJMNRD.js";
15
+ import "../chunk-IXMS2HHP.js";
16
16
  import "../chunk-TOM66P2P.js";
17
17
  import "../chunk-KU3YLF6D.js";
18
18
  import {
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  collectChosenAbilityPoints,
6
6
  collectChosenProficiencies
7
- } from "../chunk-EYZCCWG2.js";
7
+ } from "../chunk-TEKRIRNZ.js";
8
8
  import {
9
9
  resourceLevelFor
10
10
  } from "../chunk-4ISR76DH.js";
@@ -39,7 +39,7 @@ import {
39
39
  computeFeatureEffects,
40
40
  foldsNow,
41
41
  selfEffectsOf
42
- } from "../chunk-KPEJMNRD.js";
42
+ } from "../chunk-IXMS2HHP.js";
43
43
  import "../chunk-TOM66P2P.js";
44
44
  import "../chunk-KU3YLF6D.js";
45
45
  import "../chunk-RLGQ5PZZ.js";
@@ -516,7 +516,7 @@ function computeProficiencies(resolved) {
516
516
  };
517
517
  }
518
518
  function recalc(resolved, registry) {
519
- 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;
519
+ 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;
520
520
  const warnings = [];
521
521
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
522
522
  const chosenProfs = collectChosenProficiencies(resolved);
@@ -594,12 +594,19 @@ function recalc(resolved, registry) {
594
594
  for (const ab of featureEffects.proficiencies.saves) saveProfs.add(ab);
595
595
  for (const ab of chosenProfs.saves) saveProfs.add(ab);
596
596
  const saves = {};
597
+ const saveBreakdowns = {};
597
598
  for (const ab of ABILITY_KEYS) {
598
599
  const override = (_f = overrides.saves) == null ? void 0 : _f[ab];
599
600
  const prof = (_g = override == null ? void 0 : override.proficient) != null ? _g : saveProfs.has(ab);
600
601
  const derivedBonus = savingThrow(scores[ab], prof, proficiencyBonus) + applied.save_bonus + conditionEffects.d20_test_penalty;
601
602
  const bonus = (_h = override == null ? void 0 : override.bonus) != null ? _h : derivedBonus;
602
603
  saves[ab] = { bonus, proficient: prof };
604
+ saveBreakdowns[ab] = [
605
+ { source: ab.toUpperCase(), amount: mods[ab] },
606
+ ...prof ? [{ source: "Proficiency", amount: proficiencyBonus }] : [],
607
+ ...applied.save_bonus ? [{ source: "Equipment", amount: applied.save_bonus }] : [],
608
+ ...conditionEffects.d20_test_penalty ? [{ source: "Conditions", amount: conditionEffects.d20_test_penalty }] : []
609
+ ];
603
610
  }
604
611
  const profSet = /* @__PURE__ */ new Set([
605
612
  ...resolved.definition.skills.proficient,
@@ -609,12 +616,20 @@ function recalc(resolved, registry) {
609
616
  ]);
610
617
  const expSet = /* @__PURE__ */ new Set([...resolved.definition.skills.expertise, ...chosenProfs.expertise, ...featureEffects.proficiencies.skillExpertise]);
611
618
  const skills = {};
619
+ const skillBreakdowns = {};
612
620
  for (const skill of ALL_SKILLS) {
613
621
  const skillKey = skillSlugFromDisplay(skill);
614
622
  const ab = SKILL_ABILITY[skillSlugToAbilityLookup(skillKey)];
615
623
  const override = (_k = overrides.skills) == null ? void 0 : _k[skillKey];
616
624
  const tri = (_l = override == null ? void 0 : override.proficiency) != null ? _l : expSet.has(skillKey) ? "expertise" : profSet.has(skillKey) ? "proficient" : "none";
617
- const bonus = (_m = override == null ? void 0 : override.bonus) != null ? _m : skillBonus(scores[ab], tri, proficiencyBonus) + conditionEffects.d20_test_penalty;
625
+ const skillTerms = featureEffects.skill_bonus_terms.filter((t) => t.skills.includes(skillKey)).map((t) => ({ source: t.label, amount: Math.max(t.minimum, mods[t.ability]) }));
626
+ const bonus = (_m = override == null ? void 0 : override.bonus) != null ? _m : skillBonus(scores[ab], tri, proficiencyBonus) + skillTerms.reduce((sum, t) => sum + t.amount, 0) + conditionEffects.d20_test_penalty;
627
+ skillBreakdowns[skillKey] = [
628
+ { source: ab.toUpperCase(), amount: mods[ab] },
629
+ ...tri !== "none" ? [{ source: tri === "expertise" ? "Expertise" : "Proficiency", amount: proficiencyBonus * (tri === "expertise" ? 2 : 1) }] : [],
630
+ ...skillTerms,
631
+ ...conditionEffects.d20_test_penalty ? [{ source: "Conditions", amount: conditionEffects.d20_test_penalty }] : []
632
+ ];
618
633
  skills[skillKey] = {
619
634
  bonus,
620
635
  proficiency: tri,
@@ -710,10 +725,24 @@ function recalc(resolved, registry) {
710
725
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
711
726
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
712
727
  const speed = (_D = overrides.speed) != null ? _D : conditionSpeed;
728
+ const raceSpeed = (_G = (_F = (_E = resolved.race) == null ? void 0 : _E.speed) == null ? void 0 : _F.walk) != null ? _G : 30;
729
+ const speedBreakdown = [
730
+ { source: "Base speed", amount: raceSpeed },
731
+ ...speedFromRace(resolved) !== raceSpeed ? [{ source: "Feats", amount: speedFromRace(resolved) - raceSpeed }] : [],
732
+ ...applied.speed_bonuses.walk ? [{ source: "Equipment", amount: applied.speed_bonuses.walk }] : [],
733
+ ...featureEffects.speed_walk_terms.map((term) => ({ source: term.label, amount: term.value })),
734
+ ...baseSpeed > additiveSpeed ? [{ source: "Minimum speed", amount: baseSpeed - additiveSpeed }] : [],
735
+ ...conditionSpeed !== baseSpeed ? [{ source: "Conditions", amount: conditionSpeed - baseSpeed }] : []
736
+ ];
713
737
  if (!resolved.race) warnings.push("No race resolved; speed defaulted to 30.");
714
- const init = (_E = overrides.initiative) != null ? _E : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
738
+ const init = (_H = overrides.initiative) != null ? _H : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
739
+ const initiativeBreakdown = [
740
+ { source: "DEX", amount: mods.dex },
741
+ ...initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) !== mods.dex ? [{ source: "Feats", amount: initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) - mods.dex }] : [],
742
+ ...featureEffects.initiative_terms.map((term) => ({ source: term.label, amount: term.value }))
743
+ ];
715
744
  const senses = {
716
- darkvision: Math.max((_H = (_G = (_F = resolved.race) == null ? void 0 : _F.vision) == null ? void 0 : _G.darkvision) != null ? _H : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
745
+ 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),
717
746
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
718
747
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
719
748
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -760,27 +789,27 @@ function recalc(resolved, registry) {
760
789
  const spellLimits = computeSpellLimits(limitInputs);
761
790
  const defenses = {
762
791
  resistances: suppress(resolved, "resistances", composeDefenseEntries(
763
- (_J = (_I = resolved.definition.defenses) == null ? void 0 : _I.resistances) != null ? _J : [],
792
+ (_M = (_L = resolved.definition.defenses) == null ? void 0 : _L.resistances) != null ? _M : [],
764
793
  applied.defenses.resistances,
765
794
  featureEffects.resistances
766
795
  )),
767
796
  immunities: suppress(resolved, "immunities", composeDefenseEntries(
768
- (_L = (_K = resolved.definition.defenses) == null ? void 0 : _K.immunities) != null ? _L : [],
797
+ (_O = (_N = resolved.definition.defenses) == null ? void 0 : _N.immunities) != null ? _O : [],
769
798
  applied.defenses.immunities,
770
799
  featureEffects.immunities
771
800
  )),
772
801
  vulnerabilities: suppress(resolved, "vulnerabilities", composeDefenseEntries(
773
- (_N = (_M = resolved.definition.defenses) == null ? void 0 : _M.vulnerabilities) != null ? _N : [],
802
+ (_Q = (_P = resolved.definition.defenses) == null ? void 0 : _P.vulnerabilities) != null ? _Q : [],
774
803
  applied.defenses.vulnerabilities,
775
804
  featureEffects.vulnerabilities
776
805
  )),
777
806
  condition_immunities: suppress(resolved, "condition_immunities", composeDefenseEntries(
778
- (_P = (_O = resolved.definition.defenses) == null ? void 0 : _O.condition_immunities) != null ? _P : [],
807
+ (_S = (_R = resolved.definition.defenses) == null ? void 0 : _R.condition_immunities) != null ? _S : [],
779
808
  applied.defenses.condition_immunities,
780
809
  featureEffects.condition_immunities
781
810
  ))
782
811
  };
783
- const attackRows = [...(_Q = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _Q : [], buildUnarmedRow(mods, proficiencyBonus, resolveUnarmedStrike(resolved))];
812
+ const attackRows = [...(_T = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _T : [], buildUnarmedRow(mods, proficiencyBonus, resolveUnarmedStrike(resolved))];
784
813
  const riderBindings = {
785
814
  level: totalLevel,
786
815
  class_level: totalLevel,
@@ -801,6 +830,7 @@ function recalc(resolved, registry) {
801
830
  saves,
802
831
  proficiencies: profsForApply,
803
832
  skills,
833
+ statBreakdowns: { skills: skillBreakdowns, saves: saveBreakdowns, speed: speedBreakdown, initiative: initiativeBreakdown },
804
834
  passives,
805
835
  senses,
806
836
  hp: {
@@ -843,10 +873,10 @@ function recalc(resolved, registry) {
843
873
  ...riders.length ? { damageRiders: riders } : {}
844
874
  };
845
875
  }),
846
- equippedSlots: (_R = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _R : {},
847
- carriedWeight: (_S = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _S : 0,
848
- attunementUsed: (_T = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _T : 0,
849
- attunementLimit: (_V = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _V : (_U = overrides.attunement_limit) != null ? _U : Math.max(3, featureEffects.attunement_set),
876
+ equippedSlots: (_U = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _U : {},
877
+ carriedWeight: (_V = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _V : 0,
878
+ attunementUsed: (_W = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _W : 0,
879
+ attunementLimit: (_Y = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _Y : (_X = overrides.attunement_limit) != null ? _X : Math.max(3, featureEffects.attunement_set),
850
880
  conditionEffects,
851
881
  rollModifiers: featureEffects.rollModifiers,
852
882
  saveOutcomes: featureEffects.saveOutcomes
@@ -10,7 +10,7 @@ import {
10
10
  dedupeResolvedSpells,
11
11
  resolveOriginFeat,
12
12
  stripSlug
13
- } from "../chunk-EYZCCWG2.js";
13
+ } from "../chunk-TEKRIRNZ.js";
14
14
  import "../chunk-4ISR76DH.js";
15
15
  import "../chunk-DPUJDOKV.js";
16
16
  import "../chunk-O4SRD3J5.js";
@@ -20,7 +20,7 @@ import "../chunk-YHYTW5QA.js";
20
20
  import "../chunk-MI7P3NX3.js";
21
21
  import "../chunk-PVCEA4HZ.js";
22
22
  import "../chunk-UBBKSYBY.js";
23
- import "../chunk-KPEJMNRD.js";
23
+ import "../chunk-IXMS2HHP.js";
24
24
  import "../chunk-TOM66P2P.js";
25
25
  import "../chunk-KU3YLF6D.js";
26
26
  import "../chunk-RLGQ5PZZ.js";
@@ -65,7 +65,7 @@ function pushBuffEnds(cats, character, resolved) {
65
65
  }
66
66
  }
67
67
  function computeRestPlan(character, resolved, derived, registry, type) {
68
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
68
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
69
69
  const cats = [];
70
70
  let hdRegainDist;
71
71
  const index = resolveResourceIndex(resolved);
@@ -128,14 +128,17 @@ function computeRestPlan(character, resolved, derived, registry, type) {
128
128
  }
129
129
  }
130
130
  for (const [key, fu] of Object.entries((_f = character.state.feature_uses) != null ? _f : {})) {
131
- if (fu.used <= 0) continue;
131
+ const banked = (_g = character.state.feature_rolls) == null ? void 0 : _g[key];
132
+ const bankedRolls = banked ? banked.filter((v) => v > 0).length : 0;
133
+ if (fu.used <= 0 && bankedRolls <= 0) continue;
132
134
  const res = index.get(key);
133
- const reset = (_g = res == null ? void 0 : res.reset) != null ? _g : "long-rest";
135
+ const reset = (_h = res == null ? void 0 : res.reset) != null ? _h : "long-rest";
134
136
  if (reset !== "short-rest" && reset !== "long-rest" && reset !== "either" && reset !== "dawn" && reset !== "dusk") continue;
137
+ const rollsNote = bankedRolls > 0 ? ` \xB7 ${bankedRolls} roll${bankedRolls === 1 ? "" : "s"} cleared` : "";
135
138
  cats.push({
136
139
  id: `feature:${key}`,
137
- label: (_h = res == null ? void 0 : res.name) != null ? _h : key,
138
- preview: `${fu.used}/${fu.max} restored`
140
+ label: (_i = res == null ? void 0 : res.name) != null ? _i : key,
141
+ preview: `${fu.used}/${fu.max} restored${rollsNote}`
139
142
  });
140
143
  }
141
144
  pushPartialRecoveries(cats, character, index, "long");
@@ -155,15 +158,18 @@ function computeRestPlan(character, resolved, derived, registry, type) {
155
158
  });
156
159
  }
157
160
  if (type === "short") {
158
- for (const [key, fu] of Object.entries((_i = character.state.feature_uses) != null ? _i : {})) {
159
- if (fu.used <= 0) continue;
161
+ for (const [key, fu] of Object.entries((_j = character.state.feature_uses) != null ? _j : {})) {
162
+ const banked = (_k = character.state.feature_rolls) == null ? void 0 : _k[key];
163
+ const bankedRolls = banked ? banked.filter((v) => v > 0).length : 0;
164
+ if (fu.used <= 0 && bankedRolls <= 0) continue;
160
165
  const res = index.get(key);
161
- const r = (_j = res == null ? void 0 : res.reset) != null ? _j : "long-rest";
166
+ const r = (_l = res == null ? void 0 : res.reset) != null ? _l : "long-rest";
162
167
  if (r !== "short-rest" && r !== "either") continue;
168
+ const rollsNote = bankedRolls > 0 ? ` \xB7 ${bankedRolls} roll${bankedRolls === 1 ? "" : "s"} cleared` : "";
163
169
  cats.push({
164
170
  id: `feature:${key}`,
165
- label: (_k = res == null ? void 0 : res.name) != null ? _k : key,
166
- preview: `${fu.used}/${fu.max} restored`
171
+ label: (_m = res == null ? void 0 : res.name) != null ? _m : key,
172
+ preview: `${fu.used}/${fu.max} restored${rollsNote}`
167
173
  });
168
174
  }
169
175
  pushPartialRecoveries(cats, character, index, "short");
@@ -183,7 +189,7 @@ function computeRestPlan(character, resolved, derived, registry, type) {
183
189
  });
184
190
  }
185
191
  pushBuffEnds(cats, character, resolved);
186
- 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 })) : [];
192
+ const hdAvailable = type === "short" ? Object.entries((_n = character.state.hit_dice) != null ? _n : {}).filter(([, hd]) => hd.used < hd.total).map(([die, hd]) => ({ die, remaining: hd.total - hd.used })) : [];
187
193
  return { type, categories: cats, hdAvailable, hdRegainDist };
188
194
  }
189
195
  export {
@@ -450,6 +450,7 @@ export declare const characterSchema: z.ZodObject<{
450
450
  used: z.ZodNumber;
451
451
  max: z.ZodNumber;
452
452
  }, z.core.$strip>>>;
453
+ feature_rolls: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodNumber>>>;
453
454
  active_buffs: z.ZodOptional<z.ZodArray<z.ZodString>>;
454
455
  attuned_items: z.ZodOptional<z.ZodArray<z.ZodString>>;
455
456
  }, z.core.$strip>;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  characterOverridesShape,
3
3
  characterSchema
4
- } from "../chunk-E4KG7HXO.js";
4
+ } from "../chunk-PZCE7DJM.js";
5
5
  import "../chunk-S7REMWW4.js";
6
6
  export {
7
7
  characterOverridesShape,
@@ -217,6 +217,9 @@ export interface CharacterState {
217
217
  used: number;
218
218
  max: number;
219
219
  }>;
220
+ /** R4-G5 G8: banked prerolled dice, keyed by the SAME resource id as feature_uses.
221
+ * SIGN IS STATE: negative = spent, positive = live; positions never move. */
222
+ feature_rolls: Record<string, number[]>;
220
223
  /** Phase 3 activatable buffs: ids/slugs of activatable features/boons currently
221
224
  * toggled on. Their effects fold into recalc only while listed here. */
222
225
  active_buffs?: string[];
@@ -741,6 +744,25 @@ export interface DerivedStats {
741
744
  proficiency: "none" | "proficient" | "expertise";
742
745
  ability: Ability;
743
746
  }>;
747
+ /** Numeric terms behind the sheet's skill, save, speed and initiative hovers. */
748
+ statBreakdowns?: {
749
+ skills: Partial<Record<SkillSlug, {
750
+ source: string;
751
+ amount: number;
752
+ }[]>>;
753
+ saves: Record<Ability, {
754
+ source: string;
755
+ amount: number;
756
+ }[]>;
757
+ speed: {
758
+ source: string;
759
+ amount: number;
760
+ }[];
761
+ initiative: {
762
+ source: string;
763
+ amount: number;
764
+ }[];
765
+ };
744
766
  passives: {
745
767
  perception: number;
746
768
  investigation: number;
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  raceCodec
3
- } from "../chunk-CQAL67R3.js";
4
- import "../chunk-7MRW4RTH.js";
5
- import "../chunk-2BI5NAXK.js";
3
+ } from "../chunk-HRG4URUK.js";
4
+ import "../chunk-5VTDYZIW.js";
5
+ import "../chunk-QCKOVD3K.js";
6
6
  import "../chunk-4U55VNC7.js";
7
- import "../chunk-JOVMV2X5.js";
7
+ import "../chunk-N4JJNGLZ.js";
8
8
  import "../chunk-WYGD2UGN.js";
9
- import "../chunk-UA3I2YSO.js";
10
- import "../chunk-IWRVOCT5.js";
11
- import "../chunk-X3D6LXUU.js";
9
+ import "../chunk-ZJXSXVFP.js";
10
+ import "../chunk-LEHDXPY6.js";
11
+ import "../chunk-VTKJOAJD.js";
12
12
  import "../chunk-UA5KS2PL.js";
13
13
  export {
14
14
  raceCodec
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  parseRace
3
- } from "../chunk-7MRW4RTH.js";
4
- import "../chunk-2BI5NAXK.js";
3
+ } from "../chunk-5VTDYZIW.js";
4
+ import "../chunk-QCKOVD3K.js";
5
5
  import "../chunk-4U55VNC7.js";
6
- import "../chunk-JOVMV2X5.js";
6
+ import "../chunk-N4JJNGLZ.js";
7
7
  import "../chunk-WYGD2UGN.js";
8
- import "../chunk-UA3I2YSO.js";
9
- import "../chunk-IWRVOCT5.js";
10
- import "../chunk-X3D6LXUU.js";
8
+ import "../chunk-ZJXSXVFP.js";
9
+ import "../chunk-LEHDXPY6.js";
10
+ import "../chunk-VTKJOAJD.js";
11
11
  import "../chunk-UA5KS2PL.js";
12
12
  export {
13
13
  parseRace