@iamjameslennon/ddb-mcp 2.8.0 → 2.9.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 (88) hide show
  1. package/dist/browser.d.ts.map +1 -1
  2. package/dist/browser.js +19 -4
  3. package/dist/browser.js.map +1 -1
  4. package/dist/index.js +10 -18
  5. package/dist/index.js.map +1 -1
  6. package/dist/tools/campaign.js +1 -1
  7. package/dist/tools/campaign.js.map +1 -1
  8. package/dist/tools/character/ac.d.ts +20 -0
  9. package/dist/tools/character/ac.d.ts.map +1 -0
  10. package/dist/tools/character/ac.js +83 -0
  11. package/dist/tools/character/ac.js.map +1 -0
  12. package/dist/tools/character/actions.d.ts +22 -0
  13. package/dist/tools/character/actions.d.ts.map +1 -0
  14. package/dist/tools/character/actions.js +110 -0
  15. package/dist/tools/character/actions.js.map +1 -0
  16. package/dist/tools/character/core.d.ts +15 -0
  17. package/dist/tools/character/core.d.ts.map +1 -0
  18. package/dist/tools/character/core.js +129 -0
  19. package/dist/tools/character/core.js.map +1 -0
  20. package/dist/tools/character/defenses.d.ts +16 -0
  21. package/dist/tools/character/defenses.d.ts.map +1 -0
  22. package/dist/tools/character/defenses.js +27 -0
  23. package/dist/tools/character/defenses.js.map +1 -0
  24. package/dist/tools/character/definition.d.ts +14 -0
  25. package/dist/tools/character/definition.d.ts.map +1 -0
  26. package/dist/tools/character/definition.js +205 -0
  27. package/dist/tools/character/definition.js.map +1 -0
  28. package/dist/tools/character/features.d.ts +26 -0
  29. package/dist/tools/character/features.d.ts.map +1 -0
  30. package/dist/tools/character/features.js +107 -0
  31. package/dist/tools/character/features.js.map +1 -0
  32. package/dist/tools/character/helpers.d.ts +57 -0
  33. package/dist/tools/character/helpers.d.ts.map +1 -0
  34. package/dist/tools/character/helpers.js +80 -0
  35. package/dist/tools/character/helpers.js.map +1 -0
  36. package/dist/tools/character/identity.d.ts +19 -0
  37. package/dist/tools/character/identity.d.ts.map +1 -0
  38. package/dist/tools/character/identity.js +84 -0
  39. package/dist/tools/character/identity.js.map +1 -0
  40. package/dist/tools/character/inventory.d.ts +21 -0
  41. package/dist/tools/character/inventory.d.ts.map +1 -0
  42. package/dist/tools/character/inventory.js +61 -0
  43. package/dist/tools/character/inventory.js.map +1 -0
  44. package/dist/tools/character/notes.d.ts +20 -0
  45. package/dist/tools/character/notes.d.ts.map +1 -0
  46. package/dist/tools/character/notes.js +63 -0
  47. package/dist/tools/character/notes.js.map +1 -0
  48. package/dist/tools/character/parse.d.ts +13 -0
  49. package/dist/tools/character/parse.d.ts.map +1 -0
  50. package/dist/tools/character/parse.js +82 -0
  51. package/dist/tools/character/parse.js.map +1 -0
  52. package/dist/tools/character/spells.d.ts +26 -0
  53. package/dist/tools/character/spells.d.ts.map +1 -0
  54. package/dist/tools/character/spells.js +237 -0
  55. package/dist/tools/character/spells.js.map +1 -0
  56. package/dist/tools/character/stats.d.ts +33 -0
  57. package/dist/tools/character/stats.d.ts.map +1 -0
  58. package/dist/tools/character/stats.js +372 -0
  59. package/dist/tools/character/stats.js.map +1 -0
  60. package/dist/tools/character/templates.d.ts +22 -0
  61. package/dist/tools/character/templates.d.ts.map +1 -0
  62. package/dist/tools/character/templates.js +61 -0
  63. package/dist/tools/character/templates.js.map +1 -0
  64. package/dist/tools/character/types.d.ts +133 -0
  65. package/dist/tools/character/types.d.ts.map +1 -0
  66. package/dist/tools/character/types.js +12 -0
  67. package/dist/tools/character/types.js.map +1 -0
  68. package/dist/tools/character/vitals.d.ts +34 -0
  69. package/dist/tools/character/vitals.d.ts.map +1 -0
  70. package/dist/tools/character/vitals.js +198 -0
  71. package/dist/tools/character/vitals.js.map +1 -0
  72. package/dist/tools/character/weapons.d.ts +13 -0
  73. package/dist/tools/character/weapons.d.ts.map +1 -0
  74. package/dist/tools/character/weapons.js +79 -0
  75. package/dist/tools/character/weapons.js.map +1 -0
  76. package/dist/tools/character.d.ts +13 -3
  77. package/dist/tools/character.d.ts.map +1 -1
  78. package/dist/tools/character.js +18 -1181
  79. package/dist/tools/character.js.map +1 -1
  80. package/dist/tools/library.d.ts +32 -4
  81. package/dist/tools/library.d.ts.map +1 -1
  82. package/dist/tools/library.js +181 -86
  83. package/dist/tools/library.js.map +1 -1
  84. package/dist/tools/search.d.ts +1 -2
  85. package/dist/tools/search.d.ts.map +1 -1
  86. package/dist/tools/search.js +36 -59
  87. package/dist/tools/search.js.map +1 -1
  88. package/package.json +2 -1
@@ -0,0 +1,372 @@
1
+ /**
2
+ * Stats domain — saving throws, skills, senses, proficiencies. Owns the
3
+ * ability-score display line and the stats block.
4
+ *
5
+ * Phase 5 of the character.ts refactor — see docs/character-refactor.md.
6
+ *
7
+ * Output strings are pre-formatted (e.g. `savingThrows = ["STR +5*", ...]`)
8
+ * to preserve byte-for-byte parity with the original inline code. A future
9
+ * pass could lift these into structured data, but that's a separate concern.
10
+ */
11
+ import { arr, capitalize, hasRemarkableAthlete, isBonusMod, isExpertiseMod, isHalfProficiencyMod, isLanguageMod, isProficiencyMod, isSenseMod, isSetBaseMod, isSetMod, num, obj, signed, statKeys, statNames, str } from "./helpers.js";
12
+ // 18 standard skills, with the index of the ability stat they key off of.
13
+ const SKILLS = [
14
+ ["Acrobatics", 1], ["Animal Handling", 4], ["Arcana", 3], ["Athletics", 0],
15
+ ["Deception", 5], ["History", 3], ["Insight", 4], ["Intimidation", 5],
16
+ ["Investigation", 3], ["Medicine", 4], ["Nature", 3], ["Perception", 4],
17
+ ["Performance", 5], ["Persuasion", 5], ["Religion", 3], ["Sleight of Hand", 1],
18
+ ["Stealth", 1], ["Survival", 4],
19
+ ];
20
+ const SENSE_ID_NAMES = {
21
+ 1: "Blindsight", 2: "Darkvision", 3: "Tremorsense", 4: "Truesight",
22
+ };
23
+ const SENSE_SLUGS = new Set(["darkvision", "blindsight", "tremorsense", "truesight"]);
24
+ // ── Ability score display ────────────────────────────────────────────────────
25
+ function buildAbilityScoreDisplay(statTotals, statMods) {
26
+ return statNames.map((n, i) => `${n} ${statTotals[i]} (${signed(statMods[i])})`);
27
+ }
28
+ // ── Saving throws ────────────────────────────────────────────────────────────
29
+ function buildSavingThrows(allMods, statMods, profBonus) {
30
+ const saveProfSubTypes = new Set(allMods.filter(isProficiencyMod)
31
+ .filter(m => m.subType.includes("saving-throws"))
32
+ .map(m => m.subType));
33
+ // Global save bonus — `bonus subType:"saving-throws"` applies to every save.
34
+ // Sources: Stone of Good Luck (Luckstone), Cloak of Protection, Paladin's
35
+ // Aura of Protection (via grantedModifiers on the aura feature), etc.
36
+ const globalSaveBonus = allMods
37
+ .filter(m => isBonusMod(m) && m.subType === "saving-throws")
38
+ .reduce((s, m) => s + num(m.value ?? m.fixedValue), 0);
39
+ return statKeys.map((key, i) => {
40
+ const isProficient = saveProfSubTypes.has(`${key}-saving-throws`);
41
+ const total = statMods[i] + (isProficient ? profBonus : 0) + globalSaveBonus;
42
+ return `${statNames[i]} ${signed(total)}${isProficient ? "*" : ""}`;
43
+ });
44
+ }
45
+ // STR/DEX/CON stat indices — the abilities that Remarkable Athlete covers.
46
+ const RA_STAT_INDICES = new Set([0, 1, 2]);
47
+ function computeSkillBonuses(allMods, statMods, profBonus, classes) {
48
+ const skillProfSubTypes = new Set(allMods.filter(isProficiencyMod).map(m => m.subType));
49
+ const skillExpertiseSubTypes = new Set(allMods.filter(isExpertiseMod).map(m => m.subType));
50
+ // half-proficiency (e.g. Bard's Jack of All Trades applies to all ability
51
+ // checks; floor(prof/2)).
52
+ const hasJackOfAllTrades = allMods.some(m => isHalfProficiencyMod(m) && m.subType === "ability-checks");
53
+ const skillHalfProfSubTypes = new Set(allMods.filter(isHalfProficiencyMod)
54
+ .filter(m => m.subType !== "ability-checks")
55
+ .map(m => m.subType));
56
+ // Remarkable Athlete (Champion 7+) adds ceil(prof/2) to non-proficient
57
+ // STR/DEX/CON ability checks. DDB does NOT emit a half-proficiency
58
+ // modifier for RA, so we must detect it by class + level.
59
+ const ra = hasRemarkableAthlete(classes);
60
+ // Global ability-check bonus — `bonus subType:"ability-checks"` applies to
61
+ // every skill (and therefore every passive). Sources: Stone of Good Luck
62
+ // (Luckstone), Headband of Intellect (no — that's a set on INT score), etc.
63
+ const globalAbilityCheckBonus = allMods
64
+ .filter(m => isBonusMod(m) && m.subType === "ability-checks")
65
+ .reduce((s, m) => s + num(m.value ?? m.fixedValue), 0);
66
+ return SKILLS.map(([skillName, statIdx]) => {
67
+ const slug = skillName.toLowerCase().replace(/ /g, "-").replace(/'/g, "");
68
+ const isProficient = skillProfSubTypes.has(slug);
69
+ const isExpertise = skillExpertiseSubTypes.has(slug);
70
+ const isJoatHalf = !isProficient && (skillHalfProfSubTypes.has(slug) || hasJackOfAllTrades);
71
+ const isRaHalf = !isProficient && ra && RA_STAT_INDICES.has(statIdx);
72
+ let bonus = statMods[statIdx];
73
+ if (isExpertise)
74
+ bonus += profBonus * 2;
75
+ else if (isProficient)
76
+ bonus += profBonus;
77
+ // RA takes precedence over JoAT on STR/DEX/CON because it rounds up
78
+ // (a strict superset of JoAT's floor at odd proficiency bonuses).
79
+ else if (isRaHalf)
80
+ bonus += Math.ceil(profBonus / 2);
81
+ else if (isJoatHalf)
82
+ bonus += Math.floor(profBonus / 2);
83
+ // Flat bonus modifiers on the skill subType (e.g. Divine Order: Scholar adds WIS to Arcana/Religion).
84
+ // When value/fixedValue are null, statId identifies which ability modifier to add instead.
85
+ const flatBonus = allMods
86
+ .filter(m => isBonusMod(m) && m.subType === slug)
87
+ .reduce((s, m) => {
88
+ if (m.value != null)
89
+ return s + num(m.value);
90
+ if (m.fixedValue != null)
91
+ return s + num(m.fixedValue);
92
+ const sid = num(m.statId);
93
+ return s + (sid > 0 ? statMods[sid - 1] : 0);
94
+ }, 0);
95
+ bonus += flatBonus + globalAbilityCheckBonus;
96
+ return { bonus, isProficient, isExpertise };
97
+ });
98
+ }
99
+ function buildSkillLines(skillBonuses) {
100
+ return SKILLS.map(([skillName, statIdx], i) => {
101
+ const { bonus, isProficient, isExpertise } = skillBonuses[i];
102
+ const marker = isExpertise ? " **" : isProficient ? " *" : "";
103
+ const statLabel = statNames[statIdx];
104
+ return ` ${(skillName + ` (${statLabel})`).padEnd(22)} ${signed(bonus)}${marker}`;
105
+ });
106
+ }
107
+ // ── Senses ──────────────────────────────────────────────────────────────────
108
+ // Senses use a two-pass model so Gloom Stalker's Umbral Sight extends race
109
+ // darkvision rather than being clamped to the higher of the two:
110
+ //
111
+ // Pass 1 (base-establishing): record `set`/`set-base` modifiers,
112
+ // `customSenses`, and racial-trait sense notes. These define the
113
+ // character's baseline for each sense.
114
+ // Pass 2 (`type:"sense"` modifiers): for each, decide:
115
+ // • no baseline yet → this sense becomes the base (2024-style: race
116
+ // emits `type:"sense"` directly without a paired set-base)
117
+ // • baseline from a DIFFERENT component → additive (Umbral Sight pattern:
118
+ // race has set-base 60 from one component, class emits sense 30 from
119
+ // another → 60 + 30 = 90)
120
+ // • baseline from the SAME component → take the max (Umbral Sight in
121
+ // isolation emits both set-base 30 and sense 30 from the same
122
+ // component as dual encodings — must not double-count to 60)
123
+ function computeSenses(char, allMods, skillBonuses) {
124
+ const perceptionIdx = SKILLS.findIndex(([n]) => n === "Perception");
125
+ const investigationIdx = SKILLS.findIndex(([n]) => n === "Investigation");
126
+ const insightIdx = SKILLS.findIndex(([n]) => n === "Insight");
127
+ const passivePerception = 10 + skillBonuses[perceptionIdx].bonus;
128
+ const passiveInvestigation = 10 + skillBonuses[investigationIdx].bonus;
129
+ const passiveInsight = 10 + skillBonuses[insightIdx].bonus;
130
+ const senseBase = new Map();
131
+ const senseAdditions = new Map();
132
+ const recordBase = (name, val, cid) => {
133
+ if (val <= 0)
134
+ return;
135
+ const existing = senseBase.get(name);
136
+ if (!existing || val > existing.value)
137
+ senseBase.set(name, { value: val, componentId: cid });
138
+ };
139
+ // Pass 1: collect baseline-establishing sources.
140
+ for (const m of allMods) {
141
+ if ((isSetMod(m) || isSetBaseMod(m)) && SENSE_SLUGS.has(m.subType)) {
142
+ recordBase(capitalize(m.subType), num(m.value), num(m.componentId));
143
+ }
144
+ }
145
+ for (const cs of arr(char.customSenses)) {
146
+ const name = SENSE_ID_NAMES[num(cs.senseId)];
147
+ if (name)
148
+ recordBase(name, num(cs.value), 0);
149
+ }
150
+ for (const trait of arr(obj(char.race).racialTraits)) {
151
+ for (const sense of arr(obj(trait.definition).senses)) {
152
+ const name = SENSE_ID_NAMES[num(sense.senseId)];
153
+ const match = str(sense.notes).match(/\d+/);
154
+ if (name && match)
155
+ recordBase(name, parseInt(match[0], 10), 0);
156
+ }
157
+ }
158
+ // Pass 2: process `type:"sense"` modifiers — additive if from a different
159
+ // component than the current baseline (Umbral Sight extending race darkvision).
160
+ for (const m of allMods) {
161
+ if (!isSenseMod(m))
162
+ continue;
163
+ const name = capitalize(m.subType);
164
+ const val = num(m.value);
165
+ if (val <= 0)
166
+ continue;
167
+ const cid = num(m.componentId);
168
+ const baseEntry = senseBase.get(name);
169
+ if (!baseEntry) {
170
+ recordBase(name, val, cid);
171
+ }
172
+ else if (baseEntry.componentId !== cid) {
173
+ senseAdditions.set(name, (senseAdditions.get(name) ?? 0) + val);
174
+ }
175
+ else if (val > baseEntry.value) {
176
+ // Same component — dual encoding of one effective value; keep the higher.
177
+ senseBase.set(name, { value: val, componentId: cid });
178
+ }
179
+ }
180
+ const special = [];
181
+ for (const [name, { value }] of senseBase) {
182
+ special.push(`${name} ${value + (senseAdditions.get(name) ?? 0)} ft.`);
183
+ }
184
+ return { passivePerception, passiveInvestigation, passiveInsight, special };
185
+ }
186
+ // ── Proficiencies ───────────────────────────────────────────────────────────
187
+ // customProficiencies type IDs (DDB's encoding):
188
+ // 1 = Skill, 2 = Tool, 3 = Language
189
+ // Languages added by the player directly (not via a race/background/feat
190
+ // modifier) live here. Confirmed by inspecting Astarion (107164636) whose
191
+ // "Orc" language is stored as {name:"Orc", type:3, proficiencyLevel:3}.
192
+ const CUSTOM_PROF_TYPE_LANGUAGE = 3;
193
+ // characterValues entries with typeId 35 are language grants that point
194
+ // into the rule-data language table via `valueId` (a stringified integer).
195
+ // DDB's React app resolves the ID → name client-side from a /rule-data
196
+ // fetch. Confirmed via Playwright network trace against the three "missing
197
+ // languages" characters in BUG #7. We mirror every officially-sourced
198
+ // language (those with `rpgSourceId != null` in /character/v5/rule-data)
199
+ // here so the parser doesn't need a network call. Creature-language IDs
200
+ // (Worg, Sahuagin, Giant Eagle, etc — `rpgSourceId: null`) are excluded
201
+ // since they aren't typically player-selectable. Unknown IDs fall back
202
+ // to a placeholder so homebrew never silently disappears.
203
+ //
204
+ // Refresh procedure: re-run `scripts/dump-sourced-languages.mts` and
205
+ // paste the output here, keeping the ID-sorted order.
206
+ const CHAR_VALUE_TYPE_LANGUAGE = 35;
207
+ const LANGUAGE_NAMES_BY_ID = {
208
+ // PHB (rpgSourceId 198) — core 2014 + 2024 standard languages
209
+ 1: "Common", 2: "Dwarvish", 3: "Elvish", 4: "Giant", 5: "Gnomish",
210
+ 6: "Goblin", 7: "Halfling", 8: "Orc", 9: "Abyssal", 10: "Celestial",
211
+ 11: "Draconic", 12: "Deep Speech", 13: "Infernal", 14: "Primordial",
212
+ 15: "Sylvan", 16: "Undercommon",
213
+ // Telepathy (unsourced in rule-data but commonly granted by monster races / mind flayers)
214
+ 18: "Telepathy",
215
+ // PHB elementals + Druidic + Thieves' Cant
216
+ 19: "Aquan", 20: "Auran", 21: "Ignan", 22: "Terran", 23: "Druidic",
217
+ 46: "Thieves' Cant",
218
+ // Journeys through the Radiant Citadel (rpgSourceId 87)
219
+ 74: "Citlanés", 75: "Djaynaian", 76: "Godstongue", 77: "Halri",
220
+ 78: "Maynah", 79: "N'warian", 80: "Quirapu", 81: "Sensan",
221
+ 82: "Shankhi", 83: "Tletlahtolli", 84: "Xingyu", 85: "Zabaani",
222
+ // Spelljammer: Adventures in Space (rpgSourceId 90)
223
+ 86: "Dohwar", 87: "Hadozee", 88: "Aartuk",
224
+ // Dragonlance: Shadow of the Dragon Queen (rpgSourceId 95)
225
+ 89: "Abanasinian", 90: "Ergot", 91: "Istarian", 92: "Kenderspeak",
226
+ 93: "Kharolian", 94: "Khur", 95: "Kothian", 96: "Nerakese",
227
+ 97: "Nordmaarian", 98: "Ogre", 99: "Solamnic",
228
+ // Planescape: Adventures in the Multiverse (rpgSourceId 114)
229
+ 101: "Demodand",
230
+ // Humblewood (rpgSourceId 133)
231
+ 102: "Birdfolk", 103: "Cervan", 105: "Hedge", 106: "Jerbeen",
232
+ 107: "Mapach", 108: "Vulpin",
233
+ // Tome of Beasts / Kobold Press (rpgSourceId 139)
234
+ 110: "Derro", 111: "Eonic", 113: "Lemurfolk", 114: "Loxodan",
235
+ 115: "Millitaur", 117: "Tosculi", 118: "Trollkin", 120: "Void Speech",
236
+ // Tales of the Valiant (rpgSourceId 142)
237
+ 121: "Angulotl", 122: "Kuran'zoi",
238
+ // Tome of Beasts 2 / Midgard (rpgSourceId 151)
239
+ 109: "Darakhul", 112: "Erina", 116: "Ravenfolk", 119: "Umbral",
240
+ 124: "Huginn's Speech", 125: "Northern Tongue",
241
+ // Ankeshel (rpgSourceId 152)
242
+ 126: "Ankeshelian",
243
+ // Birdfolk feather speech (rpgSourceId 39)
244
+ 104: "Feather Speech",
245
+ // Old Gods of Appalachia / Drakkenheim (rpgSourceId 137)
246
+ 123: "Gibberling",
247
+ // 2024 additions (rpgSourceId 198)
248
+ 127: "Common Sign Language",
249
+ // Adventures in Middle-earth (rpgSourceId 154)
250
+ 129: "Black Speech", 130: "Dalish", 131: "Khuzdul", 132: "Orkish",
251
+ 133: "Sindarin", 134: "Warg-speech", 135: "Westron", 136: "Dunlendish",
252
+ // Setting expansion (rpgSourceId 156) — secondary Thieves' Cant entry
253
+ 137: "Thieves' Cant",
254
+ // Quests from the Infinite Staircase / Critical Role / etc (rpgSourceId 158, 160, 162)
255
+ 138: "Capran", 139: "Eluran", 140: "Tilia",
256
+ 141: "Swallybog",
257
+ 142: "Dara", 143: "Howler", 144: "Naku Naku", 145: "Torum",
258
+ // Pathfinder for Dummies / Paizo-style (rpgSourceId 202)
259
+ 146: "Aklo", 147: "Caligni", 148: "Daemonic", 149: "Necril",
260
+ 150: "Varisian",
261
+ // Forgotten Realms regional (rpgSourceId 205)
262
+ 151: "Aglarondan", 152: "Alzhedo", 153: "Chessentan", 154: "Chondathan",
263
+ 155: "Damaran", 156: "Iluskan", 157: "Lantanese", 158: "Midani",
264
+ 159: "Mulhorandi", 160: "Rashemi", 161: "Reghedjic", 162: "Sespech",
265
+ 163: "Turmic", 164: "Untheric",
266
+ // Misc later additions (rpgSourceId 224, 225, 230)
267
+ 165: "Skin Cant", 166: "Communication Spores", 167: "Archosauric",
268
+ };
269
+ function computeProficiencies(char, allMods) {
270
+ const armorProfMap = {
271
+ "light-armor": "Light Armor", "medium-armor": "Medium Armor",
272
+ "heavy-armor": "Heavy Armor", "shields": "Shields",
273
+ };
274
+ const weaponProfMap = {
275
+ "simple-weapons": "Simple Weapons", "martial-weapons": "Martial Weapons",
276
+ };
277
+ // Placeholder subType values that are unresolved character-builder selections — discard them.
278
+ const isProfPlaceholder = (sub) => sub.toLowerCase().startsWith("choose") || sub.toLowerCase() === "self";
279
+ // Specific weapon type slugs — route to Weapons, not Tools.
280
+ const isWeaponSlug = (sub) => /sword|axe|bow|crossbow|dagger|dart|sling|blowgun|staff|spear|club|mace|hammer|flail|lance|pike|rapier|scimitar|sickle|whip|maul|halberd|glaive|javelin|trident|handaxe|net|morningstar/.test(sub);
281
+ const armor = [];
282
+ const weapons = [];
283
+ const tools = [];
284
+ const languages = [];
285
+ for (const m of allMods) {
286
+ const sub = str(m.subType);
287
+ if (isProfPlaceholder(sub))
288
+ continue;
289
+ if (isProficiencyMod(m)) {
290
+ if (armorProfMap[sub])
291
+ armor.push(armorProfMap[sub]);
292
+ else if (weaponProfMap[sub])
293
+ weapons.push(weaponProfMap[sub]);
294
+ else if (sub.includes("saving-throws") || sub.includes("-skill") ||
295
+ SKILLS.some(([n]) => n.toLowerCase().replace(/ /g, "-").replace(/'/g, "") === sub)) {
296
+ // skill/save prof — handled elsewhere
297
+ }
298
+ else if (!sub.includes("-score") && sub.length > 0 &&
299
+ !statKeys.some(k => sub.startsWith(k))) {
300
+ if (isWeaponSlug(sub)) {
301
+ weapons.push(capitalize(sub.replace(/-/g, " ")));
302
+ }
303
+ else {
304
+ tools.push(capitalize(sub.replace(/-/g, " ")));
305
+ }
306
+ }
307
+ }
308
+ else if (isLanguageMod(m)) {
309
+ languages.push(capitalize(sub.replace(/-/g, " ")));
310
+ }
311
+ }
312
+ // Player-added languages via DDB's "Custom Proficiency" UI live here.
313
+ for (const cp of arr(char.customProficiencies)) {
314
+ if (num(cp.type) !== CUSTOM_PROF_TYPE_LANGUAGE)
315
+ continue;
316
+ const name = str(cp.name).trim();
317
+ if (name)
318
+ languages.push(name);
319
+ }
320
+ // Language grants stored in char.characterValues (typeId 35). valueId is
321
+ // a stringified integer pointing into the rule-data language table.
322
+ for (const cv of arr(char.characterValues)) {
323
+ if (num(cv.typeId) !== CHAR_VALUE_TYPE_LANGUAGE)
324
+ continue;
325
+ if (num(cv.value) <= 0)
326
+ continue;
327
+ const id = parseInt(str(cv.valueId), 10);
328
+ if (!Number.isFinite(id) || id <= 0)
329
+ continue;
330
+ languages.push(LANGUAGE_NAMES_BY_ID[id] ?? `Language #${id}`);
331
+ }
332
+ return { armor, weapons, tools, languages };
333
+ }
334
+ // ── Public API ──────────────────────────────────────────────────────────────
335
+ export function computeStats(core) {
336
+ const { char, allMods, statMods, statTotals, profBonus, classes } = core;
337
+ const skillBonuses = computeSkillBonuses(allMods, statMods, profBonus, classes);
338
+ return {
339
+ abilityScoreDisplay: buildAbilityScoreDisplay(statTotals, statMods),
340
+ savingThrows: buildSavingThrows(allMods, statMods, profBonus),
341
+ skillLines: buildSkillLines(skillBonuses),
342
+ senses: computeSenses(char, allMods, skillBonuses),
343
+ proficiencies: computeProficiencies(char, allMods),
344
+ };
345
+ }
346
+ export function formatStatsBlock(s) {
347
+ const { proficiencies: p } = s;
348
+ return [
349
+ `ABILITY SCORES`,
350
+ ` ${s.abilityScoreDisplay.join(" ")}`,
351
+ ``,
352
+ `SAVING THROWS`,
353
+ ` ${s.savingThrows.join(" ")}`,
354
+ ` (* proficient)`,
355
+ ``,
356
+ `SKILLS`,
357
+ ...s.skillLines,
358
+ ` (* proficient, ** expertise)`,
359
+ ``,
360
+ `SENSES`,
361
+ ` Passive Perception: ${s.senses.passivePerception} Passive Investigation: ${s.senses.passiveInvestigation} Passive Insight: ${s.senses.passiveInsight}`,
362
+ ...(s.senses.special.length ? [` ${s.senses.special.join(", ")}`] : []),
363
+ ``,
364
+ `PROFICIENCIES & TRAINING`,
365
+ ` Armor: ${p.armor.length ? [...new Set(p.armor)].join(", ") : "None"}`,
366
+ ` Weapons: ${p.weapons.length ? [...new Set(p.weapons)].join(", ") : "None"}`,
367
+ ` Tools: ${p.tools.length ? [...new Set(p.tools)].join(", ") : "None"}`,
368
+ ` Languages: ${p.languages.length ? [...new Set(p.languages)].join(", ") : "None"}`,
369
+ ``,
370
+ ];
371
+ }
372
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../../src/tools/character/stats.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Template resolver for class/feat description strings.
3
+ *
4
+ * Phase 1 of the character.ts refactor — see docs/character-refactor.md.
5
+ *
6
+ * D&D Beyond descriptions embed templates like `{{proficiency}}`,
7
+ * `{{characterlevel*2#signed}}`, `{{level/3}}`. This factory takes the
8
+ * character's profBonus and totalLevel and returns a resolver that
9
+ * substitutes them.
10
+ *
11
+ * Supported variables:
12
+ * proficiency — the character's proficiency bonus
13
+ * level — total character level
14
+ * characterlevel — alias of `level`
15
+ * classlevel — `classLevel` arg, falls back to `totalLevel`
16
+ *
17
+ * Supported operators: `*`, `+`, `-`, `/` (integer divide).
18
+ * Supported modifiers (after `#`): `signed`, `unsigned`.
19
+ */
20
+ export type TemplateResolver = (text: string, classLevel?: number) => string;
21
+ export declare function makeResolveTemplates(profBonus: number, totalLevel: number): TemplateResolver;
22
+ //# sourceMappingURL=templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../../src/tools/character/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;AAE7E,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAgC5F"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Template resolver for class/feat description strings.
3
+ *
4
+ * Phase 1 of the character.ts refactor — see docs/character-refactor.md.
5
+ *
6
+ * D&D Beyond descriptions embed templates like `{{proficiency}}`,
7
+ * `{{characterlevel*2#signed}}`, `{{level/3}}`. This factory takes the
8
+ * character's profBonus and totalLevel and returns a resolver that
9
+ * substitutes them.
10
+ *
11
+ * Supported variables:
12
+ * proficiency — the character's proficiency bonus
13
+ * level — total character level
14
+ * characterlevel — alias of `level`
15
+ * classlevel — `classLevel` arg, falls back to `totalLevel`
16
+ *
17
+ * Supported operators: `*`, `+`, `-`, `/` (integer divide).
18
+ * Supported modifiers (after `#`): `signed`, `unsigned`.
19
+ */
20
+ export function makeResolveTemplates(profBonus, totalLevel) {
21
+ return (text, classLevel) => {
22
+ const vars = {
23
+ proficiency: profBonus,
24
+ level: totalLevel,
25
+ characterlevel: totalLevel,
26
+ classlevel: classLevel ?? totalLevel,
27
+ };
28
+ return text.replace(/\{\{([^}]+)\}\}/g, (_match, expr) => {
29
+ const [rawExpr, modifier] = expr.split("#");
30
+ const opMatch = rawExpr.match(/^(\w+)\s*([*+\-/])\s*(\d+(?:\.\d+)?)$/);
31
+ let value = null;
32
+ if (opMatch) {
33
+ const [, varName, op, numStr] = opMatch;
34
+ const base = vars[varName] ?? null;
35
+ const n = parseFloat(numStr);
36
+ if (base !== null) {
37
+ if (op === "*")
38
+ value = base * n;
39
+ else if (op === "+")
40
+ value = base + n;
41
+ else if (op === "-")
42
+ value = base - n;
43
+ else if (op === "/")
44
+ value = Math.floor(base / n);
45
+ }
46
+ }
47
+ else if (vars[rawExpr] !== undefined) {
48
+ value = vars[rawExpr];
49
+ }
50
+ if (value === null)
51
+ return "?";
52
+ const rounded = Math.floor(value);
53
+ if (modifier === "signed")
54
+ return rounded >= 0 ? `+${rounded}` : `${rounded}`;
55
+ if (modifier === "unsigned")
56
+ return String(Math.max(0, rounded));
57
+ return String(rounded);
58
+ });
59
+ };
60
+ }
61
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/tools/character/templates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,UAAkB;IACxE,OAAO,CAAC,IAAY,EAAE,UAAmB,EAAU,EAAE;QACnD,MAAM,IAAI,GAA2B;YACnC,WAAW,EAAE,SAAS;YACtB,KAAK,EAAE,UAAU;YACjB,cAAc,EAAE,UAAU;YAC1B,UAAU,EAAE,UAAU,IAAI,UAAU;SACrC,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,MAAM,EAAE,IAAY,EAAE,EAAE;YAC/D,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiC,CAAC;YAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YACvE,IAAI,KAAK,GAAkB,IAAI,CAAC;YAChC,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;gBACxC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;gBACnC,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;gBAC7B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;oBAClB,IAAI,EAAE,KAAK,GAAG;wBAAE,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;yBAC5B,IAAI,EAAE,KAAK,GAAG;wBAAE,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;yBACjC,IAAI,EAAE,KAAK,GAAG;wBAAE,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC;yBACjC,IAAI,EAAE,KAAK,GAAG;wBAAE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;gBACvC,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;YACxB,CAAC;YACD,IAAI,KAAK,KAAK,IAAI;gBAAE,OAAO,GAAG,CAAC;YAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,QAAQ,KAAK,QAAQ;gBAAE,OAAO,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC;YAC9E,IAAI,QAAQ,KAAK,UAAU;gBAAE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;YACjE,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Shared types for the character module.
3
+ *
4
+ * Phase 1 of the character.ts refactor — see docs/character-refactor.md.
5
+ *
6
+ * `Mod`, `ClassEntry`, `InventoryItem`, `CharData` are all currently aliased
7
+ * to `Record<string, unknown>`. They will be tightened to proper shapes
8
+ * post-refactor (see follow-up A in the refactor doc) — the aliases exist so
9
+ * future tightening is a one-place change instead of a sweep.
10
+ */
11
+ export type CharData = Record<string, unknown>;
12
+ export type Mod = Record<string, unknown>;
13
+ export type ClassEntry = Record<string, unknown>;
14
+ export type InventoryItem = Record<string, unknown>;
15
+ /** `type:"proficiency"` — skill/save/tool/weapon/armor/language proficiency grant. */
16
+ export interface ProficiencyMod {
17
+ type: "proficiency";
18
+ subType: string;
19
+ }
20
+ /** `type:"expertise"` — doubles proficiency bonus on the given skill/tool. */
21
+ export interface ExpertiseMod {
22
+ type: "expertise";
23
+ subType: string;
24
+ }
25
+ /** `type:"half-proficiency"` — half-prof (Jack of All Trades family). */
26
+ export interface HalfProficiencyMod {
27
+ type: "half-proficiency";
28
+ subType: string;
29
+ }
30
+ /**
31
+ * `type:"bonus"` — additive numeric modifier. Most varied mod type in DDB:
32
+ * AC, skill bonuses, ability-score buffs, HP-per-level, initiative, speed,
33
+ * hit/damage. The value is in `value` OR `fixedValue` (use `??` —
34
+ * "whichever is present"), or computed from `statId` (e.g. Gloom Stalker
35
+ * Dread Ambusher adds WIS mod to initiative). `bonusTypes` indicates a
36
+ * dynamic value source (e.g. `[1]` = use the proficiency bonus).
37
+ * `isGranted: false` on a race mod means the player declined the ASI
38
+ * (2024 floating-ASI rule).
39
+ */
40
+ export interface BonusMod {
41
+ type: "bonus";
42
+ subType: string;
43
+ value?: number | null;
44
+ fixedValue?: number | null;
45
+ statId?: number | null;
46
+ isGranted?: boolean;
47
+ bonusTypes?: number[];
48
+ }
49
+ /**
50
+ * `type:"set"` — replaces the base value (e.g. Belt of Giant Strength sets STR
51
+ * to 23, Boots of Striding and Springing set walking speed to 40, Draconic
52
+ * Resilience sets unarmored AC base via `unarmored-armor-class`).
53
+ * `componentId` discriminates dual-encoded set+sense pairs from same-source
54
+ * extensions in the sense calculation.
55
+ */
56
+ export interface SetMod {
57
+ type: "set";
58
+ subType: string;
59
+ value?: number | null;
60
+ fixedValue?: number | null;
61
+ statId?: number | null;
62
+ componentId?: number;
63
+ }
64
+ /**
65
+ * `type:"set-base"` — baseline-establishing set, used by senses (e.g. race
66
+ * darkvision baseline 60 ft.). Functionally identical to `set` for the
67
+ * baseline pass; the distinct type exists because DDB sometimes emits both.
68
+ */
69
+ export interface SetBaseMod {
70
+ type: "set-base";
71
+ subType: string;
72
+ value?: number | null;
73
+ fixedValue?: number | null;
74
+ componentId?: number;
75
+ }
76
+ /**
77
+ * `type:"sense"` — grants or extends a sense (Darkvision, Blindsight, etc.).
78
+ * Pass 2 of the sense calculation uses `componentId` to decide whether the mod
79
+ * is a dual encoding of the baseline (take max) or an extension from a
80
+ * different source (additive — Gloom Stalker Umbral Sight +30 ft on race
81
+ * darkvision 60 ft).
82
+ */
83
+ export interface SenseMod {
84
+ type: "sense";
85
+ subType: string;
86
+ value?: number | null;
87
+ componentId?: number;
88
+ }
89
+ /** `type:"resistance"` — damage resistance grant (e.g. "fire", "cold"). */
90
+ export interface ResistanceMod {
91
+ type: "resistance";
92
+ subType: string;
93
+ }
94
+ /** `type:"immunity"` — damage immunity grant (e.g. "poison", "psychic"). */
95
+ export interface ImmunityMod {
96
+ type: "immunity";
97
+ subType: string;
98
+ }
99
+ /** `type:"vulnerability"` — damage vulnerability grant. */
100
+ export interface VulnerabilityMod {
101
+ type: "vulnerability";
102
+ subType: string;
103
+ }
104
+ /**
105
+ * `type:"language"` — language proficiency grant. The standard race/class/feat
106
+ * source for languages. The other two storage mechanisms (custom proficiencies
107
+ * with `type: 3`, and `characterValues` entries with `typeId: 35`) live
108
+ * outside `modifiers` and don't use this interface.
109
+ */
110
+ export interface LanguageMod {
111
+ type: "language";
112
+ subType: string;
113
+ }
114
+ export type ParseSection = "summary" | "combat" | "spells" | "inventory" | "features" | "concentration" | "notes" | "full";
115
+ /**
116
+ * The shared context object passed to every per-domain computer module.
117
+ *
118
+ * Computed once by `computeCoreStats(char)` (Phase 2) and threaded through
119
+ * vitals/stats/spells/etc. Avoids each module re-deriving statMods,
120
+ * profBonus, allMods, etc.
121
+ */
122
+ export interface CoreStats {
123
+ readonly char: CharData;
124
+ readonly allMods: readonly Mod[];
125
+ readonly statTotals: readonly number[];
126
+ readonly statMods: readonly number[];
127
+ readonly profBonus: number;
128
+ readonly totalLevel: number;
129
+ readonly classes: readonly ClassEntry[];
130
+ readonly inventory: readonly InventoryItem[];
131
+ readonly resolveTemplates: (text: string, classLevel?: number) => string;
132
+ }
133
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/tools/character/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared types for the character module.
3
+ *
4
+ * Phase 1 of the character.ts refactor — see docs/character-refactor.md.
5
+ *
6
+ * `Mod`, `ClassEntry`, `InventoryItem`, `CharData` are all currently aliased
7
+ * to `Record<string, unknown>`. They will be tightened to proper shapes
8
+ * post-refactor (see follow-up A in the refactor doc) — the aliases exist so
9
+ * future tightening is a one-place change instead of a sweep.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=types.js.map