@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.
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +19 -4
- package/dist/browser.js.map +1 -1
- package/dist/index.js +10 -18
- package/dist/index.js.map +1 -1
- package/dist/tools/campaign.js +1 -1
- package/dist/tools/campaign.js.map +1 -1
- package/dist/tools/character/ac.d.ts +20 -0
- package/dist/tools/character/ac.d.ts.map +1 -0
- package/dist/tools/character/ac.js +83 -0
- package/dist/tools/character/ac.js.map +1 -0
- package/dist/tools/character/actions.d.ts +22 -0
- package/dist/tools/character/actions.d.ts.map +1 -0
- package/dist/tools/character/actions.js +110 -0
- package/dist/tools/character/actions.js.map +1 -0
- package/dist/tools/character/core.d.ts +15 -0
- package/dist/tools/character/core.d.ts.map +1 -0
- package/dist/tools/character/core.js +129 -0
- package/dist/tools/character/core.js.map +1 -0
- package/dist/tools/character/defenses.d.ts +16 -0
- package/dist/tools/character/defenses.d.ts.map +1 -0
- package/dist/tools/character/defenses.js +27 -0
- package/dist/tools/character/defenses.js.map +1 -0
- package/dist/tools/character/definition.d.ts +14 -0
- package/dist/tools/character/definition.d.ts.map +1 -0
- package/dist/tools/character/definition.js +205 -0
- package/dist/tools/character/definition.js.map +1 -0
- package/dist/tools/character/features.d.ts +26 -0
- package/dist/tools/character/features.d.ts.map +1 -0
- package/dist/tools/character/features.js +107 -0
- package/dist/tools/character/features.js.map +1 -0
- package/dist/tools/character/helpers.d.ts +57 -0
- package/dist/tools/character/helpers.d.ts.map +1 -0
- package/dist/tools/character/helpers.js +80 -0
- package/dist/tools/character/helpers.js.map +1 -0
- package/dist/tools/character/identity.d.ts +19 -0
- package/dist/tools/character/identity.d.ts.map +1 -0
- package/dist/tools/character/identity.js +84 -0
- package/dist/tools/character/identity.js.map +1 -0
- package/dist/tools/character/inventory.d.ts +21 -0
- package/dist/tools/character/inventory.d.ts.map +1 -0
- package/dist/tools/character/inventory.js +61 -0
- package/dist/tools/character/inventory.js.map +1 -0
- package/dist/tools/character/notes.d.ts +20 -0
- package/dist/tools/character/notes.d.ts.map +1 -0
- package/dist/tools/character/notes.js +63 -0
- package/dist/tools/character/notes.js.map +1 -0
- package/dist/tools/character/parse.d.ts +13 -0
- package/dist/tools/character/parse.d.ts.map +1 -0
- package/dist/tools/character/parse.js +82 -0
- package/dist/tools/character/parse.js.map +1 -0
- package/dist/tools/character/spells.d.ts +26 -0
- package/dist/tools/character/spells.d.ts.map +1 -0
- package/dist/tools/character/spells.js +237 -0
- package/dist/tools/character/spells.js.map +1 -0
- package/dist/tools/character/stats.d.ts +33 -0
- package/dist/tools/character/stats.d.ts.map +1 -0
- package/dist/tools/character/stats.js +372 -0
- package/dist/tools/character/stats.js.map +1 -0
- package/dist/tools/character/templates.d.ts +22 -0
- package/dist/tools/character/templates.d.ts.map +1 -0
- package/dist/tools/character/templates.js +61 -0
- package/dist/tools/character/templates.js.map +1 -0
- package/dist/tools/character/types.d.ts +133 -0
- package/dist/tools/character/types.d.ts.map +1 -0
- package/dist/tools/character/types.js +12 -0
- package/dist/tools/character/types.js.map +1 -0
- package/dist/tools/character/vitals.d.ts +34 -0
- package/dist/tools/character/vitals.d.ts.map +1 -0
- package/dist/tools/character/vitals.js +198 -0
- package/dist/tools/character/vitals.js.map +1 -0
- package/dist/tools/character/weapons.d.ts +13 -0
- package/dist/tools/character/weapons.d.ts.map +1 -0
- package/dist/tools/character/weapons.js +79 -0
- package/dist/tools/character/weapons.js.map +1 -0
- package/dist/tools/character.d.ts +13 -3
- package/dist/tools/character.d.ts.map +1 -1
- package/dist/tools/character.js +18 -1181
- package/dist/tools/character.js.map +1 -1
- package/dist/tools/library.d.ts +32 -4
- package/dist/tools/library.d.ts.map +1 -1
- package/dist/tools/library.js +181 -86
- package/dist/tools/library.js.map +1 -1
- package/dist/tools/search.d.ts +1 -2
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +36 -59
- package/dist/tools/search.js.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `parseCharacterData(raw, sections)` — the orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Phase 9 of the character.ts refactor — see docs/character-refactor.md.
|
|
5
|
+
*
|
|
6
|
+
* Every domain (identity, vitals, ac, stats, defenses, features, actions,
|
|
7
|
+
* spells, inventory, notes) computed once via `computeCoreStats`, then
|
|
8
|
+
* routed through `sections` to pick which blocks to render. No business
|
|
9
|
+
* logic lives here — only the section → block routing.
|
|
10
|
+
*/
|
|
11
|
+
import { addCharacterSpellsToCompendium } from "../reference.js";
|
|
12
|
+
import { computeCoreStats } from "./core.js";
|
|
13
|
+
import { computeIdentity, formatHeaderBlock } from "./identity.js";
|
|
14
|
+
import { computeVitals, formatVitalsBlock } from "./vitals.js";
|
|
15
|
+
import { computeAc } from "./ac.js";
|
|
16
|
+
import { computeStats, formatStatsBlock } from "./stats.js";
|
|
17
|
+
import { computeDefenses, formatDefensesBlock } from "./defenses.js";
|
|
18
|
+
import { computeFeatures, formatFeaturesBlock } from "./features.js";
|
|
19
|
+
import { computeActions, formatCombatBlock } from "./actions.js";
|
|
20
|
+
import { computeSpells, formatSpellsBlock, formatConcentrationBlock } from "./spells.js";
|
|
21
|
+
import { computeInventory, formatInventoryBlock } from "./inventory.js";
|
|
22
|
+
import { computeNotes, formatNotesBlock } from "./notes.js";
|
|
23
|
+
export function parseCharacterData(raw, sections = "full") {
|
|
24
|
+
const char = (raw?.data ?? raw);
|
|
25
|
+
// Supplement spell compendium with this character's chosen spells (cantrips etc.)
|
|
26
|
+
addCharacterSpellsToCompendium(char);
|
|
27
|
+
// computeCoreStats produces every value used across multiple sections.
|
|
28
|
+
// After phases 3–8 every domain consumes `core` directly; only profBonus
|
|
29
|
+
// is still needed inline (threaded into vitals for the formatter's prof line).
|
|
30
|
+
const core = computeCoreStats(char);
|
|
31
|
+
const { profBonus } = core;
|
|
32
|
+
const identity = computeIdentity(core);
|
|
33
|
+
const vitals = computeVitals(core);
|
|
34
|
+
const ac = computeAc(core);
|
|
35
|
+
const stats = computeStats(core);
|
|
36
|
+
const defenses = computeDefenses(core);
|
|
37
|
+
const features = computeFeatures(core);
|
|
38
|
+
const actions = computeActions(core);
|
|
39
|
+
const spells = computeSpells(core);
|
|
40
|
+
const inv = computeInventory(core);
|
|
41
|
+
const notes = computeNotes(core);
|
|
42
|
+
const headerBlock = formatHeaderBlock(identity);
|
|
43
|
+
const vitalsBlock = formatVitalsBlock(vitals, ac, profBonus);
|
|
44
|
+
const statsBlock = formatStatsBlock(stats);
|
|
45
|
+
const defensesBlock = formatDefensesBlock(defenses);
|
|
46
|
+
const featuresBlock = formatFeaturesBlock(features);
|
|
47
|
+
const combatBlock = formatCombatBlock(actions);
|
|
48
|
+
const spellsBlock = formatSpellsBlock(spells);
|
|
49
|
+
const concentrationBlock = formatConcentrationBlock(spells);
|
|
50
|
+
const inventoryBlock = formatInventoryBlock(inv);
|
|
51
|
+
const notesBlock = formatNotesBlock(notes);
|
|
52
|
+
const out = [...headerBlock];
|
|
53
|
+
switch (sections) {
|
|
54
|
+
case "summary":
|
|
55
|
+
out.push(...vitalsBlock, ...statsBlock);
|
|
56
|
+
break;
|
|
57
|
+
case "combat":
|
|
58
|
+
out.push(...vitalsBlock, ...statsBlock, ...defensesBlock, ...combatBlock);
|
|
59
|
+
break;
|
|
60
|
+
case "spells":
|
|
61
|
+
out.push(...(spellsBlock.length ? spellsBlock : ["No spellcasting on this character."]));
|
|
62
|
+
break;
|
|
63
|
+
case "inventory":
|
|
64
|
+
out.push(...inventoryBlock);
|
|
65
|
+
break;
|
|
66
|
+
case "features":
|
|
67
|
+
out.push(...featuresBlock);
|
|
68
|
+
break;
|
|
69
|
+
case "concentration":
|
|
70
|
+
out.push(...concentrationBlock);
|
|
71
|
+
break;
|
|
72
|
+
case "notes":
|
|
73
|
+
out.push(...notesBlock);
|
|
74
|
+
break;
|
|
75
|
+
case "full":
|
|
76
|
+
default:
|
|
77
|
+
out.push(...vitalsBlock, ...statsBlock, ...defensesBlock, ...featuresBlock, ...combatBlock, ...spellsBlock, ...inventoryBlock, ...notesBlock);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
return out.join("\n");
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../../src/tools/character/parse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spells domain — spellcasting stats, spell slots, the prepared/known spell
|
|
3
|
+
* listing (with cross-source duplicate detection), and the concentration
|
|
4
|
+
* block. Owns the SPELLS block and the CONCENTRATION SPELLS block.
|
|
5
|
+
*
|
|
6
|
+
* Phase 7 of the character.ts refactor — see docs/character-refactor.md.
|
|
7
|
+
*
|
|
8
|
+
* Concentration detection delegates to `isConcentrationSpell` in
|
|
9
|
+
* `./reference.ts` (compendium-backed) and falls back to the per-spell
|
|
10
|
+
* `concentration` flag. Spellbook (Wizard) prepared/ritual gate is applied
|
|
11
|
+
* to leveled spells but not cantrips.
|
|
12
|
+
*
|
|
13
|
+
* Output is pre-formatted strings to preserve byte-for-byte parity with
|
|
14
|
+
* the original inline code.
|
|
15
|
+
*/
|
|
16
|
+
import type { CoreStats } from "./types.js";
|
|
17
|
+
export interface Spells {
|
|
18
|
+
spellcastingLines: string[];
|
|
19
|
+
slotLines: string[];
|
|
20
|
+
spellSections: string[];
|
|
21
|
+
concentrationByLevel: Map<number, string[]>;
|
|
22
|
+
}
|
|
23
|
+
export declare function computeSpells(core: CoreStats): Spells;
|
|
24
|
+
export declare function formatSpellsBlock(s: Spells): string[];
|
|
25
|
+
export declare function formatConcentrationBlock(s: Spells): string[];
|
|
26
|
+
//# sourceMappingURL=spells.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spells.d.ts","sourceRoot":"","sources":["../../../src/tools/character/spells.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,MAAM;IACrB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,oBAAoB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAC7C;AA2MD,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAQrD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAMrD;AAED,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAc5D"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spells domain — spellcasting stats, spell slots, the prepared/known spell
|
|
3
|
+
* listing (with cross-source duplicate detection), and the concentration
|
|
4
|
+
* block. Owns the SPELLS block and the CONCENTRATION SPELLS block.
|
|
5
|
+
*
|
|
6
|
+
* Phase 7 of the character.ts refactor — see docs/character-refactor.md.
|
|
7
|
+
*
|
|
8
|
+
* Concentration detection delegates to `isConcentrationSpell` in
|
|
9
|
+
* `./reference.ts` (compendium-backed) and falls back to the per-spell
|
|
10
|
+
* `concentration` flag. Spellbook (Wizard) prepared/ritual gate is applied
|
|
11
|
+
* to leveled spells but not cantrips.
|
|
12
|
+
*
|
|
13
|
+
* Output is pre-formatted strings to preserve byte-for-byte parity with
|
|
14
|
+
* the original inline code.
|
|
15
|
+
*/
|
|
16
|
+
import { isConcentrationSpell } from "../reference.js";
|
|
17
|
+
import { arr, num, obj, signed, statNames, str } from "./helpers.js";
|
|
18
|
+
const SOURCE_LABELS = {
|
|
19
|
+
race: "Racial Trait", class: "Class Feature", background: "Background", feat: "Feat", item: "Item",
|
|
20
|
+
};
|
|
21
|
+
const SLOT_ORDINAL = ["", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th"];
|
|
22
|
+
const slotOrdinal = (lvl) => SLOT_ORDINAL[lvl] ?? `${lvl}th`;
|
|
23
|
+
// ── Spellcasting summary (per spellcasting class) ────────────────────────────
|
|
24
|
+
function buildSpellcastingLines(classes, statMods, profBonus) {
|
|
25
|
+
// spellCastingAbilityId: 1=STR 2=DEX 3=CON 4=INT 5=WIS 6=CHA
|
|
26
|
+
const lines = [];
|
|
27
|
+
for (const c of classes) {
|
|
28
|
+
const def = obj(c.definition);
|
|
29
|
+
const subDef = obj(c.subclassDefinition);
|
|
30
|
+
const classCasts = def.canCastSpells === true;
|
|
31
|
+
const subclassCasts = subDef.canCastSpells === true;
|
|
32
|
+
if (!classCasts && !subclassCasts)
|
|
33
|
+
continue;
|
|
34
|
+
const abilityId = num(classCasts ? def.spellCastingAbilityId : subDef.spellCastingAbilityId);
|
|
35
|
+
if (!abilityId)
|
|
36
|
+
continue;
|
|
37
|
+
const className = classCasts ? str(def.name) : `${str(def.name)} (${str(subDef.name)})`;
|
|
38
|
+
const abilityMod = statMods[abilityId - 1];
|
|
39
|
+
const spellAttack = abilityMod + profBonus;
|
|
40
|
+
const saveDc = 8 + abilityMod + profBonus;
|
|
41
|
+
lines.push(` ${className}: ${statNames[abilityId - 1]} Spell Attack: ${signed(spellAttack)} Save DC: ${saveDc}`);
|
|
42
|
+
}
|
|
43
|
+
return lines;
|
|
44
|
+
}
|
|
45
|
+
// ── Spell slots (max from levelSpellSlots, used from char.spellSlots) ────────
|
|
46
|
+
function buildSlotLines(char, classes) {
|
|
47
|
+
// char.spellSlots only tracks used counts; max slots come from the class's
|
|
48
|
+
// levelSpellSlots progression table: levelSpellSlots[classLevel][slotLevel-1]
|
|
49
|
+
const spellSlotUsed = {};
|
|
50
|
+
for (const s of arr(char.spellSlots)) {
|
|
51
|
+
spellSlotUsed[num(s.level)] = num(s.used);
|
|
52
|
+
}
|
|
53
|
+
const slotMax = {};
|
|
54
|
+
for (const c of classes) {
|
|
55
|
+
// Only compute slots for classes/subclasses that actually grant spellcasting.
|
|
56
|
+
// Non-spellcasting base classes (Barbarian, Rogue, Monk, etc.) have canCastSpells: false
|
|
57
|
+
// but still carry non-empty levelSpellSlots tables — skip those.
|
|
58
|
+
// Spellcasting subclasses (Arcane Trickster, Eldritch Knight) set canCastSpells on
|
|
59
|
+
// the subclassDefinition instead, so check both.
|
|
60
|
+
const classCasts = obj(c.definition).canCastSpells === true;
|
|
61
|
+
const subclassCasts = obj(c.subclassDefinition).canCastSpells === true;
|
|
62
|
+
if (!classCasts && !subclassCasts)
|
|
63
|
+
continue;
|
|
64
|
+
const spellRules = obj(obj(c.definition).spellRules);
|
|
65
|
+
const rawTable = spellRules.levelSpellSlots;
|
|
66
|
+
const table = Array.isArray(rawTable) ? rawTable : [];
|
|
67
|
+
const lvl = num(c.level);
|
|
68
|
+
const row = table[lvl] ?? [];
|
|
69
|
+
for (let i = 0; i < row.length; i++) {
|
|
70
|
+
if (row[i] > 0)
|
|
71
|
+
slotMax[i + 1] = (slotMax[i + 1] ?? 0) + row[i];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return Object.entries(slotMax)
|
|
75
|
+
.sort(([a], [b]) => Number(a) - Number(b))
|
|
76
|
+
.map(([lvl, max]) => {
|
|
77
|
+
const used = spellSlotUsed[Number(lvl)] ?? 0;
|
|
78
|
+
return ` Level ${lvl}: ${max - used}/${max}`;
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// ── Spell listing (per class + per non-class source + duplicate warnings) ────
|
|
82
|
+
// Pre-seeds seenSpellIds during the per-class walk so duplicate detection
|
|
83
|
+
// across sources is consistent regardless of section order.
|
|
84
|
+
function buildSpellSections(char, classes) {
|
|
85
|
+
const sections = [];
|
|
86
|
+
const classSpells = arr(char.classSpells);
|
|
87
|
+
const seenSpellIds = new Map(); // spellId → first source label
|
|
88
|
+
for (const cs of classSpells) {
|
|
89
|
+
// Try characterClassId first; fall back to id/classId for 2024-rules format
|
|
90
|
+
const classEntry = classes.find(c => c.id === cs.characterClassId ||
|
|
91
|
+
c.id === cs.id ||
|
|
92
|
+
c.id === cs.classId);
|
|
93
|
+
const className = str(obj(classEntry?.definition ?? {}).name);
|
|
94
|
+
const isSpellbook = className === "Wizard";
|
|
95
|
+
// spells may be under cs.spells or cs.classSpells (2024 format variation)
|
|
96
|
+
const allSpells = arr(cs.spells).length > 0
|
|
97
|
+
? arr(cs.spells)
|
|
98
|
+
: arr(cs.classSpells);
|
|
99
|
+
const cantrips = allSpells
|
|
100
|
+
.filter(s => num(obj(s.definition).level) === 0)
|
|
101
|
+
.map(s => str(obj(s.definition).name));
|
|
102
|
+
const leveled = allSpells
|
|
103
|
+
.filter(s => {
|
|
104
|
+
if (num(obj(s.definition).level) === 0)
|
|
105
|
+
return false;
|
|
106
|
+
if (isSpellbook)
|
|
107
|
+
return s.prepared === true || obj(s.definition).ritual === true;
|
|
108
|
+
return true;
|
|
109
|
+
})
|
|
110
|
+
.map(s => {
|
|
111
|
+
const def = obj(s.definition);
|
|
112
|
+
const ritual = isSpellbook && def.ritual ? " [ritual]" : "";
|
|
113
|
+
return `${str(def.name)} (L${num(def.level)}${ritual})`;
|
|
114
|
+
});
|
|
115
|
+
if (cantrips.length)
|
|
116
|
+
sections.push(` Cantrips: ${cantrips.join(", ")}`);
|
|
117
|
+
if (leveled.length)
|
|
118
|
+
sections.push(` Spells: ${leveled.join(", ")}`);
|
|
119
|
+
// Pre-seed duplicate detection in the same pass
|
|
120
|
+
for (const s of allSpells) {
|
|
121
|
+
const spellId = num(obj(s.definition).id);
|
|
122
|
+
if (spellId && !seenSpellIds.has(spellId))
|
|
123
|
+
seenSpellIds.set(spellId, "Spells");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const spellsObj = obj(char.spells);
|
|
127
|
+
const duplicateWarnings = [];
|
|
128
|
+
for (const [key, label] of Object.entries(SOURCE_LABELS)) {
|
|
129
|
+
const spellList = arr(spellsObj[key]);
|
|
130
|
+
if (!spellList.length)
|
|
131
|
+
continue;
|
|
132
|
+
const names = [...new Set(spellList
|
|
133
|
+
.filter(s => {
|
|
134
|
+
const def = obj(s.definition);
|
|
135
|
+
const spellId = num(def.id);
|
|
136
|
+
if (!spellId)
|
|
137
|
+
return true;
|
|
138
|
+
if (seenSpellIds.has(spellId)) {
|
|
139
|
+
const firstLabel = seenSpellIds.get(spellId);
|
|
140
|
+
const spellName = str(def.name);
|
|
141
|
+
const lvl = num(def.level);
|
|
142
|
+
const spellStr = lvl === 0 ? spellName : `${spellName} (L${lvl})`;
|
|
143
|
+
duplicateWarnings.push(` • ${spellStr} — already granted by ${firstLabel}, also in ${label}`);
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
seenSpellIds.set(spellId, label);
|
|
147
|
+
return true;
|
|
148
|
+
})
|
|
149
|
+
.map(s => {
|
|
150
|
+
const def = obj(s.definition);
|
|
151
|
+
const n = str(def.name);
|
|
152
|
+
return n ? (num(def.level) === 0 ? n : `${n} (L${num(def.level)})`) : "";
|
|
153
|
+
})
|
|
154
|
+
.filter(n => n.length > 0))];
|
|
155
|
+
if (names.length)
|
|
156
|
+
sections.push(` From ${label}: ${names.join(", ")}`);
|
|
157
|
+
}
|
|
158
|
+
if (duplicateWarnings.length) {
|
|
159
|
+
sections.push(` ⚠ Duplicate spell grants detected — the following spells are already`, ` provided by an earlier source; the extra grant may be a wasted choice:`, ...duplicateWarnings);
|
|
160
|
+
}
|
|
161
|
+
return sections;
|
|
162
|
+
}
|
|
163
|
+
// ── Concentration spell collection ───────────────────────────────────────────
|
|
164
|
+
// Collects all available/prepared spells, filters to concentration:true,
|
|
165
|
+
// groups by spell level. Spellbook gate is applied to leveled spells but
|
|
166
|
+
// not cantrips (cantrips don't go through prepared/known lists).
|
|
167
|
+
function buildConcentrationByLevel(char, classes) {
|
|
168
|
+
const concByLevel = new Map();
|
|
169
|
+
const addConcSpell = (s) => {
|
|
170
|
+
const def = obj(s.definition);
|
|
171
|
+
const name = str(def.name);
|
|
172
|
+
if (!name)
|
|
173
|
+
return;
|
|
174
|
+
const level = num(def.level);
|
|
175
|
+
const fromCompendium = isConcentrationSpell(name);
|
|
176
|
+
const isConc = fromCompendium !== null ? fromCompendium : def.concentration === true;
|
|
177
|
+
if (!isConc)
|
|
178
|
+
return;
|
|
179
|
+
const bucket = concByLevel.get(level) ?? [];
|
|
180
|
+
if (!bucket.includes(name)) {
|
|
181
|
+
bucket.push(name);
|
|
182
|
+
concByLevel.set(level, bucket);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
for (const cs of arr(char.classSpells)) {
|
|
186
|
+
const classEntry = classes.find(c => c.id === cs.characterClassId || c.id === cs.id || c.id === cs.classId);
|
|
187
|
+
const isSpellbook = str(obj(classEntry?.definition ?? {}).name) === "Wizard";
|
|
188
|
+
const allSp = arr(cs.spells).length > 0
|
|
189
|
+
? arr(cs.spells)
|
|
190
|
+
: arr(cs.classSpells);
|
|
191
|
+
for (const s of allSp) {
|
|
192
|
+
const def = obj(s.definition);
|
|
193
|
+
if (num(def.level) > 0 && isSpellbook && !(s.prepared === true || def.ritual === true))
|
|
194
|
+
continue;
|
|
195
|
+
addConcSpell(s);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
for (const spellList of Object.values(obj(char.spells))) {
|
|
199
|
+
for (const s of arr(spellList))
|
|
200
|
+
addConcSpell(s);
|
|
201
|
+
}
|
|
202
|
+
return concByLevel;
|
|
203
|
+
}
|
|
204
|
+
// ── Public API ───────────────────────────────────────────────────────────────
|
|
205
|
+
export function computeSpells(core) {
|
|
206
|
+
const { char, classes, statMods, profBonus } = core;
|
|
207
|
+
return {
|
|
208
|
+
spellcastingLines: buildSpellcastingLines(classes, statMods, profBonus),
|
|
209
|
+
slotLines: buildSlotLines(char, classes),
|
|
210
|
+
spellSections: buildSpellSections(char, classes),
|
|
211
|
+
concentrationByLevel: buildConcentrationByLevel(char, classes),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
export function formatSpellsBlock(s) {
|
|
215
|
+
return [
|
|
216
|
+
...(s.spellcastingLines.length ? [`SPELLCASTING`, ...s.spellcastingLines, ``] : []),
|
|
217
|
+
...(s.slotLines.length ? [`SPELL SLOTS`, ...s.slotLines, ``] : []),
|
|
218
|
+
...(s.spellSections.length ? [`SPELLS`, ...s.spellSections, ``] : []),
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
export function formatConcentrationBlock(s) {
|
|
222
|
+
if (s.concentrationByLevel.size === 0) {
|
|
223
|
+
return ["This character has no concentration spells prepared."];
|
|
224
|
+
}
|
|
225
|
+
const out = ["CONCENTRATION SPELLS"];
|
|
226
|
+
for (const lvl of [...s.concentrationByLevel.keys()].sort((a, b) => a - b)) {
|
|
227
|
+
out.push(lvl === 0 ? " Cantrips (no slot required):" : ` Level ${lvl}:`);
|
|
228
|
+
for (const name of s.concentrationByLevel.get(lvl)) {
|
|
229
|
+
out.push(` • ${name}${lvl > 0 ? ` [${slotOrdinal(lvl)}-level slot]` : ""}`);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
out.push("");
|
|
233
|
+
if (s.slotLines.length)
|
|
234
|
+
out.push("SPELL SLOTS", ...s.slotLines);
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=spells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spells.js","sourceRoot":"","sources":["../../../src/tools/character/spells.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
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 type { CoreStats } from "./types.js";
|
|
12
|
+
export interface Senses {
|
|
13
|
+
passivePerception: number;
|
|
14
|
+
passiveInvestigation: number;
|
|
15
|
+
passiveInsight: number;
|
|
16
|
+
special: string[];
|
|
17
|
+
}
|
|
18
|
+
export interface Proficiencies {
|
|
19
|
+
armor: string[];
|
|
20
|
+
weapons: string[];
|
|
21
|
+
tools: string[];
|
|
22
|
+
languages: string[];
|
|
23
|
+
}
|
|
24
|
+
export interface Stats {
|
|
25
|
+
abilityScoreDisplay: string[];
|
|
26
|
+
savingThrows: string[];
|
|
27
|
+
skillLines: string[];
|
|
28
|
+
senses: Senses;
|
|
29
|
+
proficiencies: Proficiencies;
|
|
30
|
+
}
|
|
31
|
+
export declare function computeStats(core: CoreStats): Stats;
|
|
32
|
+
export declare function formatStatsBlock(s: Stats): string[];
|
|
33
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../src/tools/character/stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAwB,SAAS,EAAO,MAAM,YAAY,CAAC;AAEvE,MAAM,WAAW,MAAM;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,KAAK;IACpB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,aAAa,CAAC;CAC9B;AA+UD,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,GAAG,KAAK,CAUnD;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,EAAE,CAyBnD"}
|