@iamjameslennon/ddb-mcp 2.7.1 → 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/README.md +2 -0
- 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 +58 -38
- package/dist/index.js.map +1 -1
- package/dist/open5e.d.ts +2 -0
- package/dist/open5e.d.ts.map +1 -1
- package/dist/open5e.js +4 -0
- package/dist/open5e.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 +15 -3
- package/dist/tools/character.d.ts.map +1 -1
- package/dist/tools/character.js +28 -1182
- 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/monster.d.ts +2 -0
- package/dist/tools/monster.d.ts.map +1 -1
- package/dist/tools/monster.js +4 -0
- package/dist/tools/monster.js.map +1 -1
- package/dist/tools/reference.d.ts +5 -0
- package/dist/tools/reference.d.ts.map +1 -1
- package/dist/tools/reference.js +76 -69
- package/dist/tools/reference.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,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Definition lookup — searches a character's known spells, feats, class &
|
|
3
|
+
* subclass features, racial traits, background feature, and equipped items
|
|
4
|
+
* for a name match, and returns formatted definitions for the hits.
|
|
5
|
+
*
|
|
6
|
+
* Phase 9 of the character.ts refactor — see docs/character-refactor.md.
|
|
7
|
+
*
|
|
8
|
+
* `getDefinition` is the public entry point (re-exported from character.ts).
|
|
9
|
+
* It depends on `getCharacter` from the network/IO layer in character.ts
|
|
10
|
+
* — that import is intentionally one-way (definition consumes IO, not
|
|
11
|
+
* the other way around).
|
|
12
|
+
*/
|
|
13
|
+
export declare function getDefinition(characterId: string, query: string): Promise<string>;
|
|
14
|
+
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../src/tools/character/definition.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA+MH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAiBjB"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Definition lookup — searches a character's known spells, feats, class &
|
|
3
|
+
* subclass features, racial traits, background feature, and equipped items
|
|
4
|
+
* for a name match, and returns formatted definitions for the hits.
|
|
5
|
+
*
|
|
6
|
+
* Phase 9 of the character.ts refactor — see docs/character-refactor.md.
|
|
7
|
+
*
|
|
8
|
+
* `getDefinition` is the public entry point (re-exported from character.ts).
|
|
9
|
+
* It depends on `getCharacter` from the network/IO layer in character.ts
|
|
10
|
+
* — that import is intentionally one-way (definition consumes IO, not
|
|
11
|
+
* the other way around).
|
|
12
|
+
*/
|
|
13
|
+
import { stripHtml as stripHtmlFull } from "../../utils.js";
|
|
14
|
+
import { getCharacter } from "../character.js";
|
|
15
|
+
import { levenshteinDistance } from "./helpers.js";
|
|
16
|
+
function matchesDefinitionQuery(name, query) {
|
|
17
|
+
const n = name.toLowerCase();
|
|
18
|
+
const q = query.toLowerCase();
|
|
19
|
+
if (n.includes(q))
|
|
20
|
+
return true;
|
|
21
|
+
return name.split(/\s+/).some(w => levenshteinDistance(q, w.toLowerCase()) <= 2);
|
|
22
|
+
}
|
|
23
|
+
function formatSpellResult(spell) {
|
|
24
|
+
const d = (spell.definition ?? spell);
|
|
25
|
+
const name = String(d.name ?? "Unknown");
|
|
26
|
+
const level = Number(d.level ?? 0);
|
|
27
|
+
const school = String(d.school ?? "");
|
|
28
|
+
const levelLabel = level === 0 ? "Cantrip" : `Level ${level}`;
|
|
29
|
+
const ACTIVATION_TYPES = { 1: "Action", 3: "Bonus Action", 6: "Reaction" };
|
|
30
|
+
const act = d.activation;
|
|
31
|
+
const castingTime = act
|
|
32
|
+
? `${act.activationTime} ${ACTIVATION_TYPES[Number(act.activationType)] ?? "Action"}`
|
|
33
|
+
: "1 Action";
|
|
34
|
+
const rng = d.range;
|
|
35
|
+
let range = "Self";
|
|
36
|
+
if (rng) {
|
|
37
|
+
if (rng.rangeValue && rng.origin !== "Self")
|
|
38
|
+
range = `${rng.rangeValue} ft`;
|
|
39
|
+
else
|
|
40
|
+
range = String(rng.origin ?? "Self");
|
|
41
|
+
if (rng.aoeType && rng.aoeValue)
|
|
42
|
+
range += ` (${rng.aoeValue}-ft ${rng.aoeType})`;
|
|
43
|
+
}
|
|
44
|
+
const dur = d.duration;
|
|
45
|
+
let duration = "Instantaneous";
|
|
46
|
+
if (dur) {
|
|
47
|
+
const isConc = dur.durationType === "Concentration";
|
|
48
|
+
if (dur.durationInterval && dur.durationUnit) {
|
|
49
|
+
duration = `${isConc ? "Concentration, up to " : ""}${dur.durationInterval} ${dur.durationUnit}${Number(dur.durationInterval) > 1 ? "s" : ""}`;
|
|
50
|
+
}
|
|
51
|
+
else if (isConc) {
|
|
52
|
+
duration = "Concentration";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const components = (Array.isArray(d.components) ? d.components : [])
|
|
56
|
+
.map((c) => ({ 1: "V", 2: "S", 3: "M" })[c])
|
|
57
|
+
.filter(Boolean)
|
|
58
|
+
.join(", ");
|
|
59
|
+
const matNote = d.componentsDescription ? ` (${d.componentsDescription})` : "";
|
|
60
|
+
const lines = [
|
|
61
|
+
`${name} (${levelLabel} ${school})`,
|
|
62
|
+
`Casting Time: ${castingTime}`,
|
|
63
|
+
`Range: ${range}`,
|
|
64
|
+
`Components: ${components || "None"}${matNote}`,
|
|
65
|
+
`Duration: ${duration}`,
|
|
66
|
+
];
|
|
67
|
+
if (d.ritual)
|
|
68
|
+
lines.push("Ritual: Yes");
|
|
69
|
+
lines.push("", stripHtmlFull(String(d.description ?? "")));
|
|
70
|
+
return lines.join("\n");
|
|
71
|
+
}
|
|
72
|
+
function formatFeatResult(feat) {
|
|
73
|
+
const d = (feat.definition ?? feat);
|
|
74
|
+
const lines = [String(d.name ?? "Unknown")];
|
|
75
|
+
if (d.prerequisite)
|
|
76
|
+
lines.push(`Prerequisite: ${d.prerequisite}`);
|
|
77
|
+
lines.push("", stripHtmlFull(String(d.description ?? d.snippet ?? "")));
|
|
78
|
+
return lines.join("\n");
|
|
79
|
+
}
|
|
80
|
+
function formatClassFeatureResult(feature, className, level) {
|
|
81
|
+
const d = (feature.definition ?? feature);
|
|
82
|
+
const name = String(d.name ?? feature.name ?? "Unknown");
|
|
83
|
+
const desc = stripHtmlFull(String(d.description ?? d.snippet ?? ""));
|
|
84
|
+
return `${name} (${className}, Level ${level})\n\n${desc}`;
|
|
85
|
+
}
|
|
86
|
+
function formatRacialTraitResult(trait, raceName) {
|
|
87
|
+
const d = (trait.definition ?? trait);
|
|
88
|
+
const name = String(d.name ?? "Unknown");
|
|
89
|
+
const desc = stripHtmlFull(String(d.description ?? d.snippet ?? ""));
|
|
90
|
+
return `${name} (${raceName})\n\n${desc}`;
|
|
91
|
+
}
|
|
92
|
+
function formatItemResult(item) {
|
|
93
|
+
const d = (item.definition ?? item);
|
|
94
|
+
const name = String(d.name ?? "Unknown");
|
|
95
|
+
const type = String(d.type ?? "Item");
|
|
96
|
+
const rarity = String(d.rarity ?? "Common");
|
|
97
|
+
const weight = d.weight != null ? `Weight: ${d.weight} lb\n` : "";
|
|
98
|
+
const desc = stripHtmlFull(String(d.description ?? ""));
|
|
99
|
+
return `${name} (${type}, ${rarity})\n${weight}\n${desc}`;
|
|
100
|
+
}
|
|
101
|
+
function searchDefinitions(char, query) {
|
|
102
|
+
const results = [];
|
|
103
|
+
// searchDefinitions intentionally keeps these as locals (not the shared
|
|
104
|
+
// helpers) — its tolerance for unexpected shapes differs slightly (e.g.
|
|
105
|
+
// it accepts `spell.name` as a fallback for `spell.definition.name`).
|
|
106
|
+
const arr = (v) => (Array.isArray(v) ? v : []);
|
|
107
|
+
const obj = (v) => v != null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
108
|
+
const str = (v) => (typeof v === "string" ? v : "");
|
|
109
|
+
const num = (v) => (typeof v === "number" ? v : 0);
|
|
110
|
+
// ── Spells ────────────────────────────────────────────────────────────────
|
|
111
|
+
const allSpells = [
|
|
112
|
+
...arr(char.classSpells).flatMap(cs => arr(cs.spells)),
|
|
113
|
+
...Object.values(obj(char.spells)).flatMap(v => arr(v)),
|
|
114
|
+
];
|
|
115
|
+
for (const spell of allSpells) {
|
|
116
|
+
const name = str(obj(spell.definition).name || spell.name);
|
|
117
|
+
if (name && matchesDefinitionQuery(name, query)) {
|
|
118
|
+
results.push({ type: "Spell", text: formatSpellResult(spell) });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── Feats ─────────────────────────────────────────────────────────────────
|
|
122
|
+
for (const feat of arr(char.feats)) {
|
|
123
|
+
const name = str(obj(feat.definition).name);
|
|
124
|
+
if (name && matchesDefinitionQuery(name, query)) {
|
|
125
|
+
results.push({ type: "Feat", text: formatFeatResult(feat) });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// ── Class & Subclass Features ─────────────────────────────────────────────
|
|
129
|
+
const seen = new Set();
|
|
130
|
+
for (const cls of arr(char.classes)) {
|
|
131
|
+
const charLevel = num(cls.level);
|
|
132
|
+
const className = str(obj(cls.definition).name);
|
|
133
|
+
for (const cf of arr(cls.classFeatures)) {
|
|
134
|
+
const d = obj(cf.definition);
|
|
135
|
+
const name = str(d.name);
|
|
136
|
+
const requiredLevel = num(d.requiredLevel || 1);
|
|
137
|
+
if (requiredLevel <= charLevel && name && matchesDefinitionQuery(name, query) && !seen.has(name)) {
|
|
138
|
+
seen.add(name);
|
|
139
|
+
results.push({
|
|
140
|
+
type: "Class Feature",
|
|
141
|
+
text: formatClassFeatureResult(cf, className, requiredLevel),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
const subDef = obj(cls.subclassDefinition);
|
|
146
|
+
const subName = str(subDef.name);
|
|
147
|
+
for (const cf of arr(subDef.classFeatures)) {
|
|
148
|
+
const d = obj(cf.definition);
|
|
149
|
+
const name = str(d.name);
|
|
150
|
+
const requiredLevel = num(d.requiredLevel || 1);
|
|
151
|
+
const label = subName ? `${className} / ${subName}` : className;
|
|
152
|
+
if (requiredLevel <= charLevel && name && matchesDefinitionQuery(name, query) && !seen.has(name)) {
|
|
153
|
+
seen.add(name);
|
|
154
|
+
results.push({
|
|
155
|
+
type: "Subclass Feature",
|
|
156
|
+
text: formatClassFeatureResult(cf, label, requiredLevel),
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// ── Racial Traits ─────────────────────────────────────────────────────────
|
|
162
|
+
const raceName = str(obj(char.race).fullName || obj(char.race).baseName);
|
|
163
|
+
for (const trait of arr(obj(char.race).racialTraits)) {
|
|
164
|
+
const name = str(obj(trait.definition).name);
|
|
165
|
+
if (name && matchesDefinitionQuery(name, query)) {
|
|
166
|
+
results.push({ type: "Racial Trait", text: formatRacialTraitResult(trait, raceName) });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// ── Background Feature ────────────────────────────────────────────────────
|
|
170
|
+
const bgDef = obj(obj(char.background).definition);
|
|
171
|
+
const bgFeatureName = str(bgDef.featureName);
|
|
172
|
+
if (bgFeatureName && matchesDefinitionQuery(bgFeatureName, query)) {
|
|
173
|
+
const bgName = str(bgDef.name);
|
|
174
|
+
const bgDesc = stripHtmlFull(str(bgDef.featureDescription));
|
|
175
|
+
results.push({
|
|
176
|
+
type: "Background Feature",
|
|
177
|
+
text: `${bgFeatureName} (${bgName})\n\n${bgDesc}`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
// ── Equipped Items ────────────────────────────────────────────────────────
|
|
181
|
+
for (const item of arr(char.inventory)) {
|
|
182
|
+
if (!item.equipped)
|
|
183
|
+
continue;
|
|
184
|
+
const name = str(obj(item.definition).name);
|
|
185
|
+
if (name && matchesDefinitionQuery(name, query)) {
|
|
186
|
+
results.push({ type: "Item", text: formatItemResult(item) });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return results;
|
|
190
|
+
}
|
|
191
|
+
export async function getDefinition(characterId, query) {
|
|
192
|
+
const jsonData = await getCharacter(characterId);
|
|
193
|
+
const raw = JSON.parse(jsonData);
|
|
194
|
+
const char = (raw?.data ?? raw);
|
|
195
|
+
const hits = searchDefinitions(char, query);
|
|
196
|
+
if (hits.length === 0) {
|
|
197
|
+
return `No definition found matching "${query}" on this character. Try a partial name like "hunter" for Hunter's Mark.`;
|
|
198
|
+
}
|
|
199
|
+
if (hits.length > 3) {
|
|
200
|
+
const list = hits.map((h, i) => `${i + 1}. [${h.type}] ${h.text.split("\n")[0]}`).join("\n");
|
|
201
|
+
return `Found ${hits.length} matches for "${query}". Be more specific, or here are the matches:\n\n${list}`;
|
|
202
|
+
}
|
|
203
|
+
return hits.map(h => `[${h.type}]\n${h.text}`).join("\n\n===\n\n");
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=definition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../../src/tools/character/definition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Features domain — feats (real + disguised), class features, racial traits,
|
|
3
|
+
* background feature. Owns the features block.
|
|
4
|
+
*
|
|
5
|
+
* Phase 5c of the character.ts refactor — see docs/character-refactor.md.
|
|
6
|
+
*
|
|
7
|
+
* Output strings are pre-formatted (e.g. featLines = ["• Great Weapon Master: …"])
|
|
8
|
+
* to preserve byte-for-byte parity with the original inline code.
|
|
9
|
+
*/
|
|
10
|
+
import type { CoreStats } from "./types.js";
|
|
11
|
+
export interface BackgroundFeature {
|
|
12
|
+
name: string;
|
|
13
|
+
isFeat: boolean;
|
|
14
|
+
descSnippet: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Features {
|
|
17
|
+
featLines: string[];
|
|
18
|
+
disguisedFeatLines: string[];
|
|
19
|
+
realFeatCount: number;
|
|
20
|
+
classFeatureLines: string[];
|
|
21
|
+
racialTraitLines: string[];
|
|
22
|
+
background: BackgroundFeature;
|
|
23
|
+
}
|
|
24
|
+
export declare function computeFeatures(core: CoreStats): Features;
|
|
25
|
+
export declare function formatFeaturesBlock(f: Features): string[];
|
|
26
|
+
//# sourceMappingURL=features.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.d.ts","sourceRoot":"","sources":["../../../src/tools/character/features.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAwB,SAAS,EAAO,MAAM,YAAY,CAAC;AAGvE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,UAAU,EAAE,iBAAiB,CAAC;CAC/B;AAqED,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAWzD;AAED,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CA0BzD"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Features domain — feats (real + disguised), class features, racial traits,
|
|
3
|
+
* background feature. Owns the features block.
|
|
4
|
+
*
|
|
5
|
+
* Phase 5c of the character.ts refactor — see docs/character-refactor.md.
|
|
6
|
+
*
|
|
7
|
+
* Output strings are pre-formatted (e.g. featLines = ["• Great Weapon Master: …"])
|
|
8
|
+
* to preserve byte-for-byte parity with the original inline code.
|
|
9
|
+
*/
|
|
10
|
+
import { arr, hasTag, num, obj, str, stripHtml } from "./helpers.js";
|
|
11
|
+
// ── Feats ────────────────────────────────────────────────────────────────────
|
|
12
|
+
function buildFeatLines(char, resolveTemplates) {
|
|
13
|
+
// DDB stores some non-feat entries in the feats array.
|
|
14
|
+
// __DISGUISE_FEAT = class features surfaced as feats (shown in OTHER FEATURES).
|
|
15
|
+
// __INITIAL_ASI = 2024 background Ability Score Improvements (already in ABILITY SCORES; drop entirely).
|
|
16
|
+
const allFeats = arr(char.feats);
|
|
17
|
+
const realFeats = allFeats.filter(f => !hasTag(f, "__DISGUISE_FEAT") && !hasTag(f, "__INITIAL_ASI"));
|
|
18
|
+
const disguisedFeats = allFeats.filter(f => hasTag(f, "__DISGUISE_FEAT"));
|
|
19
|
+
const featLines = realFeats.map(f => {
|
|
20
|
+
const def = obj(f.definition);
|
|
21
|
+
const snippet = resolveTemplates(stripHtml(str(def.snippet || def.description))).slice(0, 120);
|
|
22
|
+
return `• ${str(def.name)}${snippet ? `: ${snippet}${snippet.length >= 120 ? "…" : ""}` : ""}`;
|
|
23
|
+
});
|
|
24
|
+
const disguisedFeatLines = disguisedFeats.map(f => `• ${str(obj(f.definition).name)}`);
|
|
25
|
+
return { featLines, disguisedFeatLines, realFeatCount: realFeats.length };
|
|
26
|
+
}
|
|
27
|
+
// ── Class features ───────────────────────────────────────────────────────────
|
|
28
|
+
function buildClassFeatureLines(classes) {
|
|
29
|
+
const lines = [];
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const c of classes) {
|
|
32
|
+
const charLevel = num(c.level);
|
|
33
|
+
for (const cf of arr(c.classFeatures)) {
|
|
34
|
+
const def = obj(cf.definition);
|
|
35
|
+
const line = `• ${str(def.name)} (${str(obj(c.definition).name)} ${num(def.requiredLevel || 1)})`;
|
|
36
|
+
if (num(def.requiredLevel || 0) <= charLevel && !seen.has(line)) {
|
|
37
|
+
seen.add(line);
|
|
38
|
+
lines.push(line);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return lines;
|
|
43
|
+
}
|
|
44
|
+
// ── Racial traits ────────────────────────────────────────────────────────────
|
|
45
|
+
function buildRacialTraitLines(char) {
|
|
46
|
+
return arr(obj(char.race).racialTraits).map(t => `• ${str(obj(t.definition).name)}`);
|
|
47
|
+
}
|
|
48
|
+
// ── Background feature ───────────────────────────────────────────────────────
|
|
49
|
+
function buildBackgroundFeature(char, resolveTemplates) {
|
|
50
|
+
// For custom backgrounds, featureName may reflect a feat name rather than
|
|
51
|
+
// the actual background feature. Check customBackground first if present.
|
|
52
|
+
const bgObj = obj(char.background);
|
|
53
|
+
const customBg = obj(bgObj.customBackground);
|
|
54
|
+
const featuresBackgroundDef = obj(obj(customBg.featuresBackground).definition);
|
|
55
|
+
const customBgDef = Object.keys(featuresBackgroundDef).length > 0
|
|
56
|
+
? featuresBackgroundDef
|
|
57
|
+
: obj(customBg.definition);
|
|
58
|
+
const bgDef = Object.keys(customBgDef).length > 0 ? customBgDef : obj(bgObj.definition);
|
|
59
|
+
return {
|
|
60
|
+
name: str(bgDef.featureName),
|
|
61
|
+
isFeat: bgDef.featureIsFeat === true,
|
|
62
|
+
descSnippet: bgDef.featureDescription
|
|
63
|
+
? resolveTemplates(stripHtml(str(bgDef.featureDescription))).slice(0, 300)
|
|
64
|
+
: "",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
// ── Public API ───────────────────────────────────────────────────────────────
|
|
68
|
+
export function computeFeatures(core) {
|
|
69
|
+
const { char, classes, resolveTemplates } = core;
|
|
70
|
+
const { featLines, disguisedFeatLines, realFeatCount } = buildFeatLines(char, resolveTemplates);
|
|
71
|
+
return {
|
|
72
|
+
featLines,
|
|
73
|
+
disguisedFeatLines,
|
|
74
|
+
realFeatCount,
|
|
75
|
+
classFeatureLines: buildClassFeatureLines(classes),
|
|
76
|
+
racialTraitLines: buildRacialTraitLines(char),
|
|
77
|
+
background: buildBackgroundFeature(char, resolveTemplates),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export function formatFeaturesBlock(f) {
|
|
81
|
+
return [
|
|
82
|
+
`FEATS (${f.realFeatCount})`,
|
|
83
|
+
...(f.featLines.length ? f.featLines : [" (none)"]),
|
|
84
|
+
``,
|
|
85
|
+
...(f.disguisedFeatLines.length ? [
|
|
86
|
+
`OTHER FEATURES (stored as feats in API but NOT player-chosen feats)`,
|
|
87
|
+
...f.disguisedFeatLines,
|
|
88
|
+
``,
|
|
89
|
+
] : []),
|
|
90
|
+
`CLASS FEATURES`,
|
|
91
|
+
...f.classFeatureLines,
|
|
92
|
+
``,
|
|
93
|
+
`RACIAL TRAITS`,
|
|
94
|
+
...f.racialTraitLines,
|
|
95
|
+
``,
|
|
96
|
+
...(!f.background.name || f.background.isFeat ? [] : (() => {
|
|
97
|
+
const desc = f.background.descSnippet;
|
|
98
|
+
const descSnippet = desc ? `${desc}${desc.length >= 300 ? "…" : ""}` : "";
|
|
99
|
+
return [
|
|
100
|
+
`BACKGROUND FEATURE`,
|
|
101
|
+
` ${f.background.name}${descSnippet ? `: ${descSnippet}` : ""}`,
|
|
102
|
+
``,
|
|
103
|
+
];
|
|
104
|
+
})()),
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=features.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features.js","sourceRoot":"","sources":["../../../src/tools/character/features.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Primitive helpers shared across the character module.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 of the character.ts refactor — see docs/character-refactor.md.
|
|
5
|
+
* No business logic — pure type/string/number utilities.
|
|
6
|
+
*/
|
|
7
|
+
import type { Mod, ProficiencyMod, ExpertiseMod, HalfProficiencyMod, BonusMod, SetMod, SetBaseMod, SenseMod, ResistanceMod, ImmunityMod, VulnerabilityMod, LanguageMod } from "./types.js";
|
|
8
|
+
export declare const str: (v: unknown) => string;
|
|
9
|
+
export declare const num: (v: unknown) => number;
|
|
10
|
+
export declare const arr: <T>(v: unknown) => T[];
|
|
11
|
+
export declare const obj: (v: unknown) => Record<string, unknown>;
|
|
12
|
+
export declare const signed: (n: number) => string;
|
|
13
|
+
export declare const modOf: (score: number) => number;
|
|
14
|
+
export declare const capitalize: (s: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* Lightweight HTML strip + whitespace collapse. Used for character snippets
|
|
17
|
+
* (one-line summaries). For full HTML stripping with entity decoding, see
|
|
18
|
+
* `stripHtml` in `src/utils.ts`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const stripHtml: (s: string) => string;
|
|
21
|
+
/** Returns true if the feat has the given category tagName. */
|
|
22
|
+
export declare const hasTag: (feat: Mod, tag: string) => boolean;
|
|
23
|
+
export declare const isProficiencyMod: (m: Mod) => m is Mod & ProficiencyMod;
|
|
24
|
+
export declare const isExpertiseMod: (m: Mod) => m is Mod & ExpertiseMod;
|
|
25
|
+
export declare const isHalfProficiencyMod: (m: Mod) => m is Mod & HalfProficiencyMod;
|
|
26
|
+
export declare const isBonusMod: (m: Mod) => m is Mod & BonusMod;
|
|
27
|
+
export declare const isSetMod: (m: Mod) => m is Mod & SetMod;
|
|
28
|
+
export declare const isSetBaseMod: (m: Mod) => m is Mod & SetBaseMod;
|
|
29
|
+
export declare const isSenseMod: (m: Mod) => m is Mod & SenseMod;
|
|
30
|
+
export declare const isResistanceMod: (m: Mod) => m is Mod & ResistanceMod;
|
|
31
|
+
export declare const isImmunityMod: (m: Mod) => m is Mod & ImmunityMod;
|
|
32
|
+
export declare const isVulnerabilityMod: (m: Mod) => m is Mod & VulnerabilityMod;
|
|
33
|
+
export declare const isLanguageMod: (m: Mod) => m is Mod & LanguageMod;
|
|
34
|
+
/**
|
|
35
|
+
* True if any class entry is a Champion Fighter at level 7+ — the
|
|
36
|
+
* threshold at which the Remarkable Athlete feature kicks in. DDB does
|
|
37
|
+
* NOT emit a `half-proficiency` modifier for Remarkable Athlete (the way
|
|
38
|
+
* it does for Bard's Jack of All Trades), so this predicate is the only
|
|
39
|
+
* way to detect the feature reliably. Used by:
|
|
40
|
+
* - vitals.ts: adds half prof to initiative
|
|
41
|
+
* - stats.ts: adds half prof to non-proficient STR/DEX/CON skills
|
|
42
|
+
*
|
|
43
|
+
* Detection accepts both shapes DDB has used for subclassDefinition
|
|
44
|
+
* (`{ name: "..." }` and `{ definition: { name: "..." } }`).
|
|
45
|
+
*/
|
|
46
|
+
export declare function hasRemarkableAthlete(classes: ReadonlyArray<Record<string, unknown>>): boolean;
|
|
47
|
+
/** Display labels for the six ability scores, in canonical order. */
|
|
48
|
+
export declare const statNames: string[];
|
|
49
|
+
/** Internal slugs for the six ability scores, in canonical order (matches statNames). */
|
|
50
|
+
export declare const statKeys: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Levenshtein edit distance between two strings. Used by character-name
|
|
53
|
+
* fuzzy resolution (character.ts) and definition-query matching
|
|
54
|
+
* (definition.ts).
|
|
55
|
+
*/
|
|
56
|
+
export declare function levenshteinDistance(a: string, b: string): number;
|
|
57
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/tools/character/helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,YAAY,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3L,eAAO,MAAM,GAAG,GAAI,GAAG,OAAO,KAAG,MAAsC,CAAC;AACxE,eAAO,MAAM,GAAG,GAAI,GAAG,OAAO,KAAG,MAAyC,CAAC;AAC3E,eAAO,MAAM,GAAG,GAAI,CAAC,EAAE,GAAG,OAAO,KAAG,CAAC,EAA0C,CAAC;AAChF,eAAO,MAAM,GAAG,GAAI,GAAG,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAEd,CAAC;AAE1C,eAAO,MAAM,MAAM,GAAI,GAAG,MAAM,KAAG,MAAqC,CAAC;AACzE,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,MAAsC,CAAC;AAC7E,eAAO,MAAM,UAAU,GAAI,GAAG,MAAM,KAAG,MAAgD,CAAC;AAExF;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MACiB,CAAC;AAExD,+DAA+D;AAC/D,eAAO,MAAM,MAAM,GAAI,MAAM,GAAG,EAAE,KAAK,MAAM,KAAG,OAC4C,CAAC;AAO7F,eAAO,MAAM,gBAAgB,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,cACM,CAAC;AAE5D,eAAO,MAAM,cAAc,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,YACM,CAAC;AAE1D,eAAO,MAAM,oBAAoB,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,kBACO,CAAC;AAEjE,eAAO,MAAM,UAAU,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,QACM,CAAC;AAEtD,eAAO,MAAM,QAAQ,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,MACM,CAAC;AAEpD,eAAO,MAAM,YAAY,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,UACO,CAAC;AAEzD,eAAO,MAAM,UAAU,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,QACM,CAAC;AAEtD,eAAO,MAAM,eAAe,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,aACM,CAAC;AAE3D,eAAO,MAAM,aAAa,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,WACM,CAAC;AAEzD,eAAO,MAAM,kBAAkB,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,gBACM,CAAC;AAE9D,eAAO,MAAM,aAAa,GAAI,GAAG,GAAG,KAAG,CAAC,IAAI,GAAG,GAAG,WACM,CAAC;AAEzD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,OAAO,CAM7F;AAED,qEAAqE;AACrE,eAAO,MAAM,SAAS,UAA6C,CAAC;AAEpE,yFAAyF;AACzF,eAAO,MAAM,QAAQ,UAAkF,CAAC;AAExG;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAahE"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Primitive helpers shared across the character module.
|
|
3
|
+
*
|
|
4
|
+
* Phase 1 of the character.ts refactor — see docs/character-refactor.md.
|
|
5
|
+
* No business logic — pure type/string/number utilities.
|
|
6
|
+
*/
|
|
7
|
+
export const str = (v) => (v != null ? String(v) : "");
|
|
8
|
+
export const num = (v) => (typeof v === "number" ? v : 0);
|
|
9
|
+
export const arr = (v) => (Array.isArray(v) ? v : []);
|
|
10
|
+
export const obj = (v) => v != null && typeof v === "object" && !Array.isArray(v)
|
|
11
|
+
? v : {};
|
|
12
|
+
export const signed = (n) => (n >= 0 ? `+${n}` : `${n}`);
|
|
13
|
+
export const modOf = (score) => Math.floor((score - 10) / 2);
|
|
14
|
+
export const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
15
|
+
/**
|
|
16
|
+
* Lightweight HTML strip + whitespace collapse. Used for character snippets
|
|
17
|
+
* (one-line summaries). For full HTML stripping with entity decoding, see
|
|
18
|
+
* `stripHtml` in `src/utils.ts`.
|
|
19
|
+
*/
|
|
20
|
+
export const stripHtml = (s) => s.replace(/<[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
21
|
+
/** Returns true if the feat has the given category tagName. */
|
|
22
|
+
export const hasTag = (feat, tag) => arr(obj(feat.definition).categories).some(c => c.tagName === tag);
|
|
23
|
+
// ── Mod type guards (follow-up A) ─────────────────────────────────────────────
|
|
24
|
+
// Narrow `Mod` (Record<string, unknown>) to the discriminated shapes in
|
|
25
|
+
// `types.ts`. Each guard checks `type` and the fields the consumer reads, so
|
|
26
|
+
// downstream code sees `subType: string` directly without a `str()` wrapper.
|
|
27
|
+
export const isProficiencyMod = (m) => m.type === "proficiency" && typeof m.subType === "string";
|
|
28
|
+
export const isExpertiseMod = (m) => m.type === "expertise" && typeof m.subType === "string";
|
|
29
|
+
export const isHalfProficiencyMod = (m) => m.type === "half-proficiency" && typeof m.subType === "string";
|
|
30
|
+
export const isBonusMod = (m) => m.type === "bonus" && typeof m.subType === "string";
|
|
31
|
+
export const isSetMod = (m) => m.type === "set" && typeof m.subType === "string";
|
|
32
|
+
export const isSetBaseMod = (m) => m.type === "set-base" && typeof m.subType === "string";
|
|
33
|
+
export const isSenseMod = (m) => m.type === "sense" && typeof m.subType === "string";
|
|
34
|
+
export const isResistanceMod = (m) => m.type === "resistance" && typeof m.subType === "string";
|
|
35
|
+
export const isImmunityMod = (m) => m.type === "immunity" && typeof m.subType === "string";
|
|
36
|
+
export const isVulnerabilityMod = (m) => m.type === "vulnerability" && typeof m.subType === "string";
|
|
37
|
+
export const isLanguageMod = (m) => m.type === "language" && typeof m.subType === "string";
|
|
38
|
+
/**
|
|
39
|
+
* True if any class entry is a Champion Fighter at level 7+ — the
|
|
40
|
+
* threshold at which the Remarkable Athlete feature kicks in. DDB does
|
|
41
|
+
* NOT emit a `half-proficiency` modifier for Remarkable Athlete (the way
|
|
42
|
+
* it does for Bard's Jack of All Trades), so this predicate is the only
|
|
43
|
+
* way to detect the feature reliably. Used by:
|
|
44
|
+
* - vitals.ts: adds half prof to initiative
|
|
45
|
+
* - stats.ts: adds half prof to non-proficient STR/DEX/CON skills
|
|
46
|
+
*
|
|
47
|
+
* Detection accepts both shapes DDB has used for subclassDefinition
|
|
48
|
+
* (`{ name: "..." }` and `{ definition: { name: "..." } }`).
|
|
49
|
+
*/
|
|
50
|
+
export function hasRemarkableAthlete(classes) {
|
|
51
|
+
return classes.some(cls => {
|
|
52
|
+
const sub = obj(cls.subclassDefinition);
|
|
53
|
+
const subName = str(obj(sub.definition ?? cls.subclassDefinition).name || sub.name);
|
|
54
|
+
return /champion/i.test(subName) && num(cls.level) >= 7;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/** Display labels for the six ability scores, in canonical order. */
|
|
58
|
+
export const statNames = ["STR", "DEX", "CON", "INT", "WIS", "CHA"];
|
|
59
|
+
/** Internal slugs for the six ability scores, in canonical order (matches statNames). */
|
|
60
|
+
export const statKeys = ["strength", "dexterity", "constitution", "intelligence", "wisdom", "charisma"];
|
|
61
|
+
/**
|
|
62
|
+
* Levenshtein edit distance between two strings. Used by character-name
|
|
63
|
+
* fuzzy resolution (character.ts) and definition-query matching
|
|
64
|
+
* (definition.ts).
|
|
65
|
+
*/
|
|
66
|
+
export function levenshteinDistance(a, b) {
|
|
67
|
+
if (a.length === 0)
|
|
68
|
+
return b.length;
|
|
69
|
+
if (b.length === 0)
|
|
70
|
+
return a.length;
|
|
71
|
+
const matrix = Array.from({ length: a.length + 1 }, (_, i) => Array.from({ length: b.length + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)));
|
|
72
|
+
for (let i = 1; i <= a.length; i++) {
|
|
73
|
+
for (let j = 1; j <= b.length; j++) {
|
|
74
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
75
|
+
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return matrix[a.length][b.length];
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/tools/character/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity domain — name, race (with 2024 variant detection), class line,
|
|
3
|
+
* background, XP, inspiration. Owns the header block.
|
|
4
|
+
*
|
|
5
|
+
* Phase 3 of the character.ts refactor — see docs/character-refactor.md.
|
|
6
|
+
*/
|
|
7
|
+
import type { CoreStats } from "./types.js";
|
|
8
|
+
export interface Identity {
|
|
9
|
+
charName: string;
|
|
10
|
+
race: string;
|
|
11
|
+
classLine: string;
|
|
12
|
+
totalLevel: number;
|
|
13
|
+
background: string;
|
|
14
|
+
xp: number;
|
|
15
|
+
inspiration: boolean;
|
|
16
|
+
}
|
|
17
|
+
export declare function computeIdentity(core: CoreStats): Identity;
|
|
18
|
+
export declare function formatHeaderBlock(i: Identity): string[];
|
|
19
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../../src/tools/character/identity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,OAAO,CAAC;CACtB;AAoDD,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAWzD;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,CAUvD"}
|