@archivist-gg/dnd5e 0.3.7 → 0.3.9

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 (65) 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-RWZTGMSN.js → chunk-22MOUU2G.js} +1 -1
  5. package/dist/{chunk-IWRVOCT5.js → chunk-2M34FLAY.js} +1 -1
  6. package/dist/{chunk-JKLRBILX.js → chunk-3UNP3G4D.js} +1 -1
  7. package/dist/{chunk-3PZHBLFG.js → chunk-4DOMDEBZ.js} +1 -1
  8. package/dist/{chunk-CQAL67R3.js → chunk-7YU4NPKR.js} +1 -1
  9. package/dist/{chunk-BS355LND.js → chunk-BIA32MQ5.js} +1 -1
  10. package/dist/{chunk-7MRW4RTH.js → chunk-BL3VELKP.js} +1 -1
  11. package/dist/{chunk-MT4RWROQ.js → chunk-BLRW2UU6.js} +2 -2
  12. package/dist/{chunk-KPEJMNRD.js → chunk-CBEKVAX4.js} +30 -7
  13. package/dist/{chunk-A6YL53NC.js → chunk-G247QXWW.js} +1 -1
  14. package/dist/{chunk-EYZCCWG2.js → chunk-HLQAFZKQ.js} +1 -1
  15. package/dist/{chunk-ABQ6ZWAF.js → chunk-J77CKYV3.js} +1 -1
  16. package/dist/{chunk-MYW7AOUE.js → chunk-JANNRGJC.js} +1 -1
  17. package/dist/{chunk-63XQXPZL.js → chunk-JCEV7KYN.js} +1 -1
  18. package/dist/{chunk-ULCQ73LA.js → chunk-MAH6DCRI.js} +1 -1
  19. package/dist/{chunk-7WNQJAZW.js → chunk-MQ747UCR.js} +2 -2
  20. package/dist/{chunk-H4VEMVOO.js → chunk-NWDF5HG3.js} +1 -1
  21. package/dist/{chunk-BJFL4KYG.js → chunk-OYUEUKKF.js} +3 -3
  22. package/dist/{chunk-JOVMV2X5.js → chunk-PI4LLJG4.js} +3 -3
  23. package/dist/{chunk-NNAQ4KQF.js → chunk-PJMG5XV3.js} +1 -1
  24. package/dist/{chunk-3BMVVNCS.js → chunk-QHMWA3SZ.js} +1 -1
  25. package/dist/{chunk-B4TQTJVC.js → chunk-R747YKS7.js} +1 -1
  26. package/dist/{chunk-DTCR4DBF.js → chunk-S56D6B6C.js} +3 -3
  27. package/dist/{chunk-2BI5NAXK.js → chunk-V6LJFP4R.js} +2 -2
  28. package/dist/{chunk-X3D6LXUU.js → chunk-XTRDCSJB.js} +7 -0
  29. package/dist/{chunk-UA3I2YSO.js → chunk-ZJXSXVFP.js} +1 -1
  30. package/dist/class/class.codec.js +7 -7
  31. package/dist/class/class.parser.js +6 -6
  32. package/dist/class/class.schema.js +5 -5
  33. package/dist/feat/feat.codec.js +6 -6
  34. package/dist/feat/feat.parser.js +5 -5
  35. package/dist/feat/feat.schema.d.ts +23 -0
  36. package/dist/feat/feat.schema.js +4 -4
  37. package/dist/index.js +24 -24
  38. package/dist/monster/monster.parser.js +6 -6
  39. package/dist/monster/monster.schema.js +5 -5
  40. package/dist/optional-feature/optional-feature.codec.js +5 -5
  41. package/dist/optional-feature/optional-feature.parser.js +4 -4
  42. package/dist/optional-feature/optional-feature.schema.d.ts +24 -0
  43. package/dist/optional-feature/optional-feature.schema.js +3 -3
  44. package/dist/pc/pc.decision-engine.js +2 -2
  45. package/dist/pc/pc.feature-effects.d.ts +27 -0
  46. package/dist/pc/pc.feature-effects.js +1 -1
  47. package/dist/pc/pc.proficiencies.js +2 -2
  48. package/dist/pc/pc.recalc.js +58 -30
  49. package/dist/pc/pc.resolver.js +2 -2
  50. package/dist/pc/pc.types.d.ts +19 -0
  51. package/dist/race/race.codec.js +7 -7
  52. package/dist/race/race.parser.js +6 -6
  53. package/dist/race/race.schema.js +5 -5
  54. package/dist/schemas/choice-schema.js +2 -2
  55. package/dist/schemas/feature-effect-schema.d.ts +23 -0
  56. package/dist/schemas/feature-effect-schema.js +1 -1
  57. package/dist/schemas/feature-schema.js +4 -4
  58. package/dist/schemas/resource-schema.d.ts +1 -0
  59. package/dist/schemas/resource-schema.js +1 -1
  60. package/dist/subclass/subclass.codec.js +7 -7
  61. package/dist/subclass/subclass.parser.js +6 -6
  62. package/dist/subclass/subclass.schema.js +5 -5
  63. package/dist/types/feature-effect.d.ts +9 -0
  64. package/dist/types/resource.d.ts +1 -1
  65. 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-R747YKS7.js";
9
+ import "./chunk-J77CKYV3.js";
10
+ import "./chunk-BLRW2UU6.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-7YU4NPKR.js";
23
+ import "./chunk-BL3VELKP.js";
24
+ import "./chunk-V6LJFP4R.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-QHMWA3SZ.js";
38
+ import "./chunk-G247QXWW.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-JANNRGJC.js";
43
+ import "./chunk-PJMG5XV3.js";
44
+ import "./chunk-MQ747UCR.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-3UNP3G4D.js";
68
+ import "./chunk-22MOUU2G.js";
69
+ import "./chunk-OYUEUKKF.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-BIA32MQ5.js";
76
+ import "./chunk-NWDF5HG3.js";
77
77
  import "./chunk-4U55VNC7.js";
78
- import "./chunk-DTCR4DBF.js";
78
+ import "./chunk-S56D6B6C.js";
79
79
  import "./chunk-23LZLBJK.js";
80
80
  import "./chunk-CJYCVNW2.js";
81
- import "./chunk-JOVMV2X5.js";
81
+ import "./chunk-PI4LLJG4.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-MAH6DCRI.js";
95
+ import "./chunk-4DOMDEBZ.js";
96
+ import "./chunk-JCEV7KYN.js";
97
97
  import "./chunk-IN4M4X7P.js";
98
- import "./chunk-IWRVOCT5.js";
99
- import "./chunk-X3D6LXUU.js";
98
+ import "./chunk-2M34FLAY.js";
99
+ import "./chunk-XTRDCSJB.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-QHMWA3SZ.js";
5
+ import "../chunk-G247QXWW.js";
6
+ import "../chunk-PI4LLJG4.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-2M34FLAY.js";
10
+ import "../chunk-XTRDCSJB.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-G247QXWW.js";
15
+ import "../chunk-PI4LLJG4.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-2M34FLAY.js";
19
+ import "../chunk-XTRDCSJB.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-JANNRGJC.js";
4
+ import "../chunk-PJMG5XV3.js";
5
+ import "../chunk-MQ747UCR.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-XTRDCSJB.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-PJMG5XV3.js";
4
+ import "../chunk-MQ747UCR.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-XTRDCSJB.js";
8
8
  import "../chunk-UA5KS2PL.js";
9
9
  export {
10
10
  parseOptionalFeature
@@ -65,6 +65,29 @@ 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>;
82
+ }, z.core.$strip>, z.ZodObject<{
83
+ kind: z.ZodLiteral<"half-proficiency">;
84
+ skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
85
+ round: z.ZodOptional<z.ZodEnum<{
86
+ down: "down";
87
+ up: "up";
88
+ }>>;
89
+ condition: z.ZodOptional<z.ZodString>;
90
+ subject: z.ZodOptional<z.ZodString>;
68
91
  }, z.core.$strip>, z.ZodObject<{
69
92
  kind: z.ZodLiteral<"immune-condition">;
70
93
  condition: z.ZodString;
@@ -364,6 +387,7 @@ export declare const optionalFeatureEntitySchema: z.ZodObject<{
364
387
  }, z.core.$strip>>>;
365
388
  consumes: z.ZodOptional<z.ZodNullable<z.ZodObject<{
366
389
  source: z.ZodOptional<z.ZodEnum<{
390
+ "spell-slots": "spell-slots";
367
391
  resource: "resource";
368
392
  "class-column": "class-column";
369
393
  "attack-dice": "attack-dice";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  optionalFeatureEntitySchema
3
- } from "../chunk-7WNQJAZW.js";
3
+ } from "../chunk-MQ747UCR.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-XTRDCSJB.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-HLQAFZKQ.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-CBEKVAX4.js";
18
18
  import "../chunk-TOM66P2P.js";
19
19
  import "../chunk-KU3YLF6D.js";
20
20
  import "../chunk-RLGQ5PZZ.js";
@@ -23,6 +23,29 @@ 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
+ }[];
37
+ /**
38
+ * Half-proficiency terms (Jack of All Trades, Remarkable Athlete). Resolved in recalc against the
39
+ * proficiency bonus, and ONLY for a skill whose effective tri is "none" — that gate is the mechanic
40
+ * ("a skill proficiency you lack"), so it lives at the consumer, not here. Empty `skills` = every skill.
41
+ * recalc takes the MAX across terms, never the sum: "add half your Proficiency Bonus" is one grant, so two
42
+ * features (or a duplicated homebrew note) must not double it.
43
+ */
44
+ half_proficiency_terms: {
45
+ skills: string[];
46
+ round: "down" | "up";
47
+ label: string;
48
+ }[];
26
49
  hp_per_level_bonus: number;
27
50
  /** One term per hp-per-level-bonus effect, labeled with the owning feature's name. */
28
51
  hp_per_level_terms: {
@@ -30,6 +53,10 @@ export interface FeatureEffectTotals {
30
53
  value: number;
31
54
  }[];
32
55
  speed_walk_bonus: number;
56
+ speed_walk_terms: {
57
+ label: string;
58
+ value: number;
59
+ }[];
33
60
  /**
34
61
  * Absolute walk-speed FLOOR from `speed-bonus` effects with `set:true` (e.g.
35
62
  * 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-CBEKVAX4.js";
11
11
  import "../chunk-TOM66P2P.js";
12
12
  import "../chunk-KU3YLF6D.js";
13
13
  import "../chunk-RLGQ5PZZ.js";
@@ -2,7 +2,7 @@ import {
2
2
  collectChosenProficiencies,
3
3
  collectProficiencyGrants,
4
4
  computeEffectiveProficiencies
5
- } from "../chunk-EYZCCWG2.js";
5
+ } from "../chunk-HLQAFZKQ.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-CBEKVAX4.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-HLQAFZKQ.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-CBEKVAX4.js";
43
43
  import "../chunk-TOM66P2P.js";
44
44
  import "../chunk-KU3YLF6D.js";
45
45
  import "../chunk-RLGQ5PZZ.js";
@@ -61,8 +61,6 @@ import {
61
61
  attackBonus,
62
62
  isCanonicalDamageType,
63
63
  isChosenDamageType,
64
- passive,
65
- passivePerception,
66
64
  proficiencyFromLevel,
67
65
  saveDC,
68
66
  savingThrow,
@@ -516,7 +514,7 @@ function computeProficiencies(resolved) {
516
514
  };
517
515
  }
518
516
  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;
517
+ 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;
520
518
  const warnings = [];
521
519
  const overrides = (_a = resolved.definition.overrides) != null ? _a : {};
522
520
  const chosenProfs = collectChosenProficiencies(resolved);
@@ -594,12 +592,19 @@ function recalc(resolved, registry) {
594
592
  for (const ab of featureEffects.proficiencies.saves) saveProfs.add(ab);
595
593
  for (const ab of chosenProfs.saves) saveProfs.add(ab);
596
594
  const saves = {};
595
+ const saveBreakdowns = {};
597
596
  for (const ab of ABILITY_KEYS) {
598
597
  const override = (_f = overrides.saves) == null ? void 0 : _f[ab];
599
598
  const prof = (_g = override == null ? void 0 : override.proficient) != null ? _g : saveProfs.has(ab);
600
599
  const derivedBonus = savingThrow(scores[ab], prof, proficiencyBonus) + applied.save_bonus + conditionEffects.d20_test_penalty;
601
600
  const bonus = (_h = override == null ? void 0 : override.bonus) != null ? _h : derivedBonus;
602
601
  saves[ab] = { bonus, proficient: prof };
602
+ saveBreakdowns[ab] = [
603
+ { source: ab.toUpperCase(), amount: mods[ab] },
604
+ ...prof ? [{ source: "Proficiency", amount: proficiencyBonus }] : [],
605
+ ...applied.save_bonus ? [{ source: "Equipment", amount: applied.save_bonus }] : [],
606
+ ...conditionEffects.d20_test_penalty ? [{ source: "Conditions", amount: conditionEffects.d20_test_penalty }] : []
607
+ ];
603
608
  }
604
609
  const profSet = /* @__PURE__ */ new Set([
605
610
  ...resolved.definition.skills.proficient,
@@ -609,28 +614,36 @@ function recalc(resolved, registry) {
609
614
  ]);
610
615
  const expSet = /* @__PURE__ */ new Set([...resolved.definition.skills.expertise, ...chosenProfs.expertise, ...featureEffects.proficiencies.skillExpertise]);
611
616
  const skills = {};
617
+ const skillBreakdowns = {};
612
618
  for (const skill of ALL_SKILLS) {
613
619
  const skillKey = skillSlugFromDisplay(skill);
614
620
  const ab = SKILL_ABILITY[skillSlugToAbilityLookup(skillKey)];
615
621
  const override = (_k = overrides.skills) == null ? void 0 : _k[skillKey];
616
622
  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;
623
+ 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]) }));
624
+ const halfProfTerms = tri !== "none" ? [] : featureEffects.half_proficiency_terms.filter((t) => t.skills.length === 0 || t.skills.includes(skillKey)).map((t) => ({ source: t.label, amount: t.round === "up" ? Math.ceil(proficiencyBonus / 2) : Math.floor(proficiencyBonus / 2) }));
625
+ const halfProfBest = halfProfTerms.length ? halfProfTerms.reduce((best, t) => t.amount > best.amount ? t : best) : null;
626
+ const bonus = (_n = override == null ? void 0 : override.bonus) != null ? _n : skillBonus(scores[ab], tri, proficiencyBonus) + skillTerms.reduce((sum, t) => sum + t.amount, 0) + ((_m = halfProfBest == null ? void 0 : halfProfBest.amount) != null ? _m : 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
+ ...halfProfBest ? [halfProfBest] : [],
632
+ ...conditionEffects.d20_test_penalty ? [{ source: "Conditions", amount: conditionEffects.d20_test_penalty }] : []
633
+ ];
618
634
  skills[skillKey] = {
619
635
  bonus,
620
636
  proficiency: tri,
621
637
  ability: ab
622
638
  };
623
639
  }
624
- const perceptionTri = skills.perception.proficiency;
625
- const investigationTri = skills.investigation.proficiency;
626
- const insightTri = skills.insight.proficiency;
627
640
  const passives = {
628
- perception: (_o = (_n = overrides.passives) == null ? void 0 : _n.perception) != null ? _o : passivePerception(scores.wis, perceptionTri, proficiencyBonus),
629
- investigation: (_q = (_p = overrides.passives) == null ? void 0 : _p.investigation) != null ? _q : passive(scores.int, investigationTri, proficiencyBonus),
630
- insight: (_s = (_r = overrides.passives) == null ? void 0 : _r.insight) != null ? _s : passive(scores.wis, insightTri, proficiencyBonus)
641
+ perception: (_p = (_o = overrides.passives) == null ? void 0 : _o.perception) != null ? _p : 10 + skills.perception.bonus,
642
+ investigation: (_r = (_q = overrides.passives) == null ? void 0 : _q.investigation) != null ? _r : 10 + skills.investigation.bonus,
643
+ insight: (_t = (_s = overrides.passives) == null ? void 0 : _s.insight) != null ? _t : 10 + skills.insight.bonus
631
644
  };
632
- const hpRolled = (_u = (_t = overrides.hp) == null ? void 0 : _t.rolled) != null ? _u : null;
633
- const hpModifier = (_w = (_v = overrides.hp) == null ? void 0 : _v.modifier) != null ? _w : null;
645
+ const hpRolled = (_v = (_u = overrides.hp) == null ? void 0 : _u.rolled) != null ? _v : null;
646
+ const hpModifier = (_x = (_w = overrides.hp) == null ? void 0 : _w.modifier) != null ? _x : null;
634
647
  const averageDiceSum = hitDiceAverageSum(resolved.classes);
635
648
  const conLevels = hpLevelCount(resolved.classes);
636
649
  const diceSum = hpRolled != null ? hpRolled : averageDiceSum;
@@ -638,7 +651,7 @@ function recalc(resolved, registry) {
638
651
  const diceConClamped = Math.max(1, diceConRaw);
639
652
  const hpMaxDerived = diceConClamped + featureEffects.hp_per_level_bonus * totalLevel + (hpModifier != null ? hpModifier : 0);
640
653
  const hpMaxAfterConditions = Math.max(0, Math.floor(hpMaxDerived * conditionEffects.hp_max_multiplier));
641
- const hpMax = (_y = (_x = overrides.hp) == null ? void 0 : _x.max) != null ? _y : hpMaxAfterConditions;
654
+ const hpMax = (_z = (_y = overrides.hp) == null ? void 0 : _y.max) != null ? _z : hpMaxAfterConditions;
642
655
  const hpBreakdown = {
643
656
  diceSum,
644
657
  diceSource: hpRolled != null ? "rolled" : "average",
@@ -656,7 +669,7 @@ function recalc(resolved, registry) {
656
669
  exhaustionMultiplier: conditionEffects.hp_max_multiplier,
657
670
  exhaustionLevel: conditionEffects.exhaustion_level,
658
671
  derivedMax: hpMaxAfterConditions,
659
- override: (_A = (_z = overrides.hp) == null ? void 0 : _z.max) != null ? _A : null,
672
+ override: (_B = (_A = overrides.hp) == null ? void 0 : _A.max) != null ? _B : null,
660
673
  final: hpMax
661
674
  };
662
675
  const featureAcTermsFor = (hasArmor) => featureEffects.ac_terms.filter((t) => !t.requires_armor || hasArmor).map((t) => ({ source: t.label, amount: t.value, kind: "feature", condition: t.condition }));
@@ -680,7 +693,7 @@ function recalc(resolved, registry) {
680
693
  let acBreakdownDerived = [];
681
694
  let acInformationalDerived = [];
682
695
  if (registry) {
683
- derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_B = resolved.weaponMasteries) != null ? _B : [], featureEffects.attunement_set);
696
+ derivedEquipment = computeSlotsAndAttacks(resolved, mods, profsForApply, registry, warnings, proficiencyBonus, weaponAbilities, (_C = resolved.weaponMasteries) != null ? _C : [], featureEffects.attunement_set);
684
697
  if (derivedEquipment.equippedSlots.armor) {
685
698
  const featTerms = featureAcTermsFor(true);
686
699
  acDerived = derivedEquipment.ac + sumTerms(featTerms);
@@ -704,16 +717,30 @@ function recalc(resolved, registry) {
704
717
  acDerived = total + sumTerms(featTerms);
705
718
  acBreakdownDerived = [...terms, ...featTerms];
706
719
  }
707
- const ac = (_C = overrides.ac) != null ? _C : acDerived;
720
+ const ac = (_D = overrides.ac) != null ? _D : acDerived;
708
721
  const additiveSpeed = speedFromRace(resolved) + applied.speed_bonuses.walk + featureEffects.speed_walk_bonus;
709
722
  const baseSpeed = Math.max(featureEffects.speed_walk_set, additiveSpeed);
710
723
  const adjustedSpeed = baseSpeed * conditionEffects.speed_multiplier - conditionEffects.speed_reduction_ft;
711
724
  const conditionSpeed = conditionEffects.speed_floor_zero ? 0 : Math.max(0, Math.floor(adjustedSpeed));
712
- const speed = (_D = overrides.speed) != null ? _D : conditionSpeed;
725
+ const speed = (_E = overrides.speed) != null ? _E : conditionSpeed;
726
+ const raceSpeed = (_H = (_G = (_F = resolved.race) == null ? void 0 : _F.speed) == null ? void 0 : _G.walk) != null ? _H : 30;
727
+ const speedBreakdown = [
728
+ { source: "Base speed", amount: raceSpeed },
729
+ ...speedFromRace(resolved) !== raceSpeed ? [{ source: "Feats", amount: speedFromRace(resolved) - raceSpeed }] : [],
730
+ ...applied.speed_bonuses.walk ? [{ source: "Equipment", amount: applied.speed_bonuses.walk }] : [],
731
+ ...featureEffects.speed_walk_terms.map((term) => ({ source: term.label, amount: term.value })),
732
+ ...baseSpeed > additiveSpeed ? [{ source: "Minimum speed", amount: baseSpeed - additiveSpeed }] : [],
733
+ ...conditionSpeed !== baseSpeed ? [{ source: "Conditions", amount: conditionSpeed - baseSpeed }] : []
734
+ ];
713
735
  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;
736
+ const init = (_I = overrides.initiative) != null ? _I : initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) + featureEffects.initiative_bonus;
737
+ const initiativeBreakdown = [
738
+ { source: "DEX", amount: mods.dex },
739
+ ...initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) !== mods.dex ? [{ source: "Feats", amount: initiativeBonus(mods.dex, resolved.feats, resolved.definition.edition) - mods.dex }] : [],
740
+ ...featureEffects.initiative_terms.map((term) => ({ source: term.label, amount: term.value }))
741
+ ];
715
742
  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),
743
+ darkvision: Math.max((_L = (_K = (_J = resolved.race) == null ? void 0 : _J.vision) == null ? void 0 : _K.darkvision) != null ? _L : 0, featureEffects.senses.darkvision, applied.senses.darkvision),
717
744
  blindsight: Math.max(featureEffects.senses.blindsight, applied.senses.blindsight),
718
745
  tremorsense: Math.max(featureEffects.senses.tremorsense, applied.senses.tremorsense),
719
746
  truesight: Math.max(featureEffects.senses.truesight, applied.senses.truesight)
@@ -760,27 +787,27 @@ function recalc(resolved, registry) {
760
787
  const spellLimits = computeSpellLimits(limitInputs);
761
788
  const defenses = {
762
789
  resistances: suppress(resolved, "resistances", composeDefenseEntries(
763
- (_J = (_I = resolved.definition.defenses) == null ? void 0 : _I.resistances) != null ? _J : [],
790
+ (_N = (_M = resolved.definition.defenses) == null ? void 0 : _M.resistances) != null ? _N : [],
764
791
  applied.defenses.resistances,
765
792
  featureEffects.resistances
766
793
  )),
767
794
  immunities: suppress(resolved, "immunities", composeDefenseEntries(
768
- (_L = (_K = resolved.definition.defenses) == null ? void 0 : _K.immunities) != null ? _L : [],
795
+ (_P = (_O = resolved.definition.defenses) == null ? void 0 : _O.immunities) != null ? _P : [],
769
796
  applied.defenses.immunities,
770
797
  featureEffects.immunities
771
798
  )),
772
799
  vulnerabilities: suppress(resolved, "vulnerabilities", composeDefenseEntries(
773
- (_N = (_M = resolved.definition.defenses) == null ? void 0 : _M.vulnerabilities) != null ? _N : [],
800
+ (_R = (_Q = resolved.definition.defenses) == null ? void 0 : _Q.vulnerabilities) != null ? _R : [],
774
801
  applied.defenses.vulnerabilities,
775
802
  featureEffects.vulnerabilities
776
803
  )),
777
804
  condition_immunities: suppress(resolved, "condition_immunities", composeDefenseEntries(
778
- (_P = (_O = resolved.definition.defenses) == null ? void 0 : _O.condition_immunities) != null ? _P : [],
805
+ (_T = (_S = resolved.definition.defenses) == null ? void 0 : _S.condition_immunities) != null ? _T : [],
779
806
  applied.defenses.condition_immunities,
780
807
  featureEffects.condition_immunities
781
808
  ))
782
809
  };
783
- const attackRows = [...(_Q = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _Q : [], buildUnarmedRow(mods, proficiencyBonus, resolveUnarmedStrike(resolved))];
810
+ const attackRows = [...(_U = derivedEquipment == null ? void 0 : derivedEquipment.attacks) != null ? _U : [], buildUnarmedRow(mods, proficiencyBonus, resolveUnarmedStrike(resolved))];
784
811
  const riderBindings = {
785
812
  level: totalLevel,
786
813
  class_level: totalLevel,
@@ -801,6 +828,7 @@ function recalc(resolved, registry) {
801
828
  saves,
802
829
  proficiencies: profsForApply,
803
830
  skills,
831
+ statBreakdowns: { skills: skillBreakdowns, saves: saveBreakdowns, speed: speedBreakdown, initiative: initiativeBreakdown },
804
832
  passives,
805
833
  senses,
806
834
  hp: {
@@ -843,10 +871,10 @@ function recalc(resolved, registry) {
843
871
  ...riders.length ? { damageRiders: riders } : {}
844
872
  };
845
873
  }),
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),
874
+ equippedSlots: (_V = derivedEquipment == null ? void 0 : derivedEquipment.equippedSlots) != null ? _V : {},
875
+ carriedWeight: (_W = derivedEquipment == null ? void 0 : derivedEquipment.carriedWeight) != null ? _W : 0,
876
+ attunementUsed: (_X = derivedEquipment == null ? void 0 : derivedEquipment.attunementUsed) != null ? _X : 0,
877
+ attunementLimit: (_Z = derivedEquipment == null ? void 0 : derivedEquipment.attunementLimit) != null ? _Z : (_Y = overrides.attunement_limit) != null ? _Y : Math.max(3, featureEffects.attunement_set),
850
878
  conditionEffects,
851
879
  rollModifiers: featureEffects.rollModifiers,
852
880
  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-HLQAFZKQ.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-CBEKVAX4.js";
24
24
  import "../chunk-TOM66P2P.js";
25
25
  import "../chunk-KU3YLF6D.js";
26
26
  import "../chunk-RLGQ5PZZ.js";
@@ -744,6 +744,25 @@ export interface DerivedStats {
744
744
  proficiency: "none" | "proficient" | "expertise";
745
745
  ability: Ability;
746
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
+ };
747
766
  passives: {
748
767
  perception: number;
749
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-7YU4NPKR.js";
4
+ import "../chunk-BL3VELKP.js";
5
+ import "../chunk-V6LJFP4R.js";
6
6
  import "../chunk-4U55VNC7.js";
7
- import "../chunk-JOVMV2X5.js";
7
+ import "../chunk-PI4LLJG4.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-2M34FLAY.js";
11
+ import "../chunk-XTRDCSJB.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-BL3VELKP.js";
4
+ import "../chunk-V6LJFP4R.js";
5
5
  import "../chunk-4U55VNC7.js";
6
- import "../chunk-JOVMV2X5.js";
6
+ import "../chunk-PI4LLJG4.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-2M34FLAY.js";
10
+ import "../chunk-XTRDCSJB.js";
11
11
  import "../chunk-UA5KS2PL.js";
12
12
  export {
13
13
  parseRace
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  fixedAsiSchema,
3
3
  raceEntitySchema
4
- } from "../chunk-2BI5NAXK.js";
5
- import "../chunk-JOVMV2X5.js";
4
+ } from "../chunk-V6LJFP4R.js";
5
+ import "../chunk-PI4LLJG4.js";
6
6
  import "../chunk-WYGD2UGN.js";
7
- import "../chunk-UA3I2YSO.js";
8
- import "../chunk-IWRVOCT5.js";
9
- import "../chunk-X3D6LXUU.js";
7
+ import "../chunk-ZJXSXVFP.js";
8
+ import "../chunk-2M34FLAY.js";
9
+ import "../chunk-XTRDCSJB.js";
10
10
  import "../chunk-UA5KS2PL.js";
11
11
  export {
12
12
  fixedAsiSchema,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  choiceSchema
3
- } from "../chunk-IWRVOCT5.js";
4
- import "../chunk-X3D6LXUU.js";
3
+ } from "../chunk-2M34FLAY.js";
4
+ import "../chunk-XTRDCSJB.js";
5
5
  export {
6
6
  choiceSchema
7
7
  };