let current = dv.current();let title = current.name || current.file.name;// --- CONFIGURATION ---// Set to your silhouette image path or filename (e.g., "npc-images/silhouette.webp" or "silhouette.webp").// If the file doesn't exist or is set to "", it will gracefully display the text message below.let fallbackImage = "npc-images/silhouette.webp"; // ---------------------// 1. Gather all potential names (Title, quoted nicknames, and Obsidian Aliases)let rawNames = [title];// Extract quoted nickname if present in title (e.g., Wulfric "The Bear" -> The Bear)let matchNick = title.match(/"([^"]+)"/);if (matchNick && matchNick) { rawNames.push(matchNick);}// Safely pull aliases from Obsidian Frontmatter/Propertieslet rawAliases = current.file?.aliases || current.aliases || [];if (typeof rawAliases === "string") { rawNames.push(rawAliases);} else if (rawAliases && typeof rawAliases[Symbol.iterator] === "function") { for (let a of rawAliases) { if (a && typeof a === "string") rawNames.push(a); }}// 2. Build sanitized search terms (ensures terms are >= 2 chars to avoid matching "_" or empty strings)let searchTerms = new Set();for (let name of rawNames) { if (!name || typeof name !== "string") continue; let lower = name.toLowerCase().trim().replace(/["']/g, ""); let slug = lower.replace(/[\s-]+/g, "_").replace(/^_+|_+\$/g, ""); if (lower.length >= 2) searchTerms.add(lower); if (slug.length >= 2) searchTerms.add(slug);}// 3. Search npc-images for matching character fileslet matches = app.vault.getFiles().filter(f => { let pathLower = f.path.toLowerCase(); if (!pathLower.includes("npc-images")) return false; // Exclude the fallback image from character search if (fallbackImage && pathLower.includes(fallbackImage.toLowerCase())) return false; let imgName = f.name.toLowerCase(); return Array.from(searchTerms).some(term => term && imgName.includes(term));});// 4. Prioritize files with "avatar" in the name, otherwise take first matchlet match = matches.find(f => f.name.toLowerCase().includes("avatar")) || (matches.length > 0 ? matches : null);// 5. Render artwork, fallback image, or clean text messageif (match) { dv.paragraph(`![[${match.path}|cover]]`);} else { // Flexible fallback image lookup (works with filename, full path, or partial match) let fallbackFile = null; if (fallbackImage && fallbackImage.trim() !== "") { let cleanFB = fallbackImage.toLowerCase().trim(); fallbackFile = app.vault.getFiles().find(f => f.path.toLowerCase() === cleanFB || f.path.toLowerCase().includes(cleanFB) || f.name.toLowerCase().includes(cleanFB) ); } if (fallbackFile) { dv.paragraph(`![[${fallbackFile.path}|cover]]`); } else { dv.paragraph(`*No artwork generated yet for ${title}*`); }}
// 5. Render artwork or fallback
if (match) {
dv.paragraph(![[${match.path}|cover]]);
} else {
let fallbackFile = fallbackImage ? app.vault.getAbstractFileByPath(fallbackImage) : null;
if (fallbackFile) {
dv.paragraph(![[${fallbackFile.path}|cover]]);
} else {
dv.paragraph(*No artwork generated yet for ${title}*);
}
}
### Character Bio
Bodyguard of [[Rurisk Korunda]] and brother of [[Thargran]]. Died fighting the Illithid threat alongside the [[The Party|party]].
Appearance & Personality
Visuals & Mannerisms
let current = dv.current();let title = current.name || current.file.name;// --- CONFIGURATION ---// Set to your silhouette image path or filename (e.g., "npc-images/silhouette.webp" or "silhouette.webp").// If the file doesn't exist or is set to "", it will gracefully display the text message below.let fallbackImage = "npc-images/silhouette.webp"; // ---------------------// 1. Gather all potential names (Title, quoted nicknames, and Obsidian Aliases)let rawNames = [title];// Extract quoted nickname if present in title (e.g., Wulfric "The Bear" -> The Bear)let matchNick = title.match(/"([^"]+)"/);if (matchNick && matchNick) { rawNames.push(matchNick);}// Safely pull aliases from Obsidian Frontmatter/Propertieslet rawAliases = current.file?.aliases || current.aliases || [];if (typeof rawAliases === "string") { rawNames.push(rawAliases);} else if (rawAliases && typeof rawAliases[Symbol.iterator] === "function") { for (let a of rawAliases) { if (a && typeof a === "string") rawNames.push(a); }}// 2. Build sanitized search terms (ensures terms are >= 2 chars to avoid matching "_" or empty strings)let searchTerms = new Set();for (let name of rawNames) { if (!name || typeof name !== "string") continue; let lower = name.toLowerCase().trim().replace(/["']/g, ""); let slug = lower.replace(/[\s-]+/g, "_").replace(/^_+|_+\$/g, ""); if (lower.length >= 2) searchTerms.add(lower); if (slug.length >= 2) searchTerms.add(slug);}// 3. Search npc-images for matching character fileslet matches = app.vault.getFiles().filter(f => { let pathLower = f.path.toLowerCase(); if (!pathLower.includes("npc-images")) return false; // Exclude the fallback image from character search if (fallbackImage && pathLower.includes(fallbackImage.toLowerCase())) return false; let imgName = f.name.toLowerCase(); return Array.from(searchTerms).some(term => term && imgName.includes(term));});// 4. Prioritize files with "avatar" in the name, otherwise take first matchlet match = matches.find(f => f.name.toLowerCase().includes("avatar")) || (matches.length > 0 ? matches : null);// 5. Render artwork, fallback image, or clean text messageif (match) { dv.paragraph(`![[${match.path}|cover]]`);} else { // Flexible fallback image lookup (works with filename, full path, or partial match) let fallbackFile = null; if (fallbackImage && fallbackImage.trim() !== "") { let cleanFB = fallbackImage.toLowerCase().trim(); fallbackFile = app.vault.getFiles().find(f => f.path.toLowerCase() === cleanFB || f.path.toLowerCase().includes(cleanFB) || f.name.toLowerCase().includes(cleanFB) ); } if (fallbackFile) { dv.paragraph(`![[${fallbackFile.path}|cover]]`); } else { dv.paragraph(`*No artwork generated yet for ${title}*`); }}
// 5. Render artwork or fallback
if (match) {
dv.paragraph(![[${match.path}|cover]]);
} else {
let fallbackFile = fallbackImage ? app.vault.getAbstractFileByPath(fallbackImage) : null;
if (fallbackFile) {
dv.paragraph(![[${fallbackFile.path}|cover]]);
} else {
dv.paragraph(*No artwork generated yet for ${title}*);
}
}
- **Mannerisms:**
Recent Activity
This section displays every time this entity is mentioned in session summaries.
The party were then accompanied by the bodyguards Bhaldir, Branmund, Galnir, Tharmond, and Thargran. The dwarven bodyguards all swore the creed of the Legion of the Dead before doing so, making a lifelong oath to confront the Illithid. Upon entering the mountain tunnels they encountered Mind Flayers who dominated some of their minds. The bodyguards didn’t hesitate and slew some of their own subjugated fellows. Eventually only Galnir and Thargran left those tunnels alive with the party.
Tharmond
Medium Humanoid (Dwarf), Any Alignment
Armor Class 20 (plate armor, shield)
Hit Points 75 (10d8 + 30)
Speed 25 ft.
Initiative +0 (10)
Dwarven Resilience. Tharmond has advantage on saving throws against spells and the charmed, paralyzed, and poisoned conditions.
Dwarven Sensitivity. While in sunlight, Tharmond has disadvantage on attack rolls, as well as on Wisdom (Perception) checks that rely on sight.
Actions
Multiattack. Tharmond makes three Psychic-Attuned Hammer or Javelin attacks and uses Call to Attack.
Psychic-Attuned Hammer.Melee Weapon Attack: +7 to hit, reach 5 ft., one target. Hit: 9 (1d10 + 4) bludgeoning damage, or 15 (2d10 + 4) bludgeoning damage while under the effect of Enlarge, plus 5 (1d10) psychic damage.
Javelin.Melee or Ranged Weapon Attack: +7 to hit, reach 5 ft. or range 30/120 ft., one target. Hit: 7 (1d6 + 4) piercing damage, or 11 (2d6 + 4) piercing damage while under the effect of Enlarge.
Call to Attack. Up to three allies within 120 feet of Tharmond that can hear it can each use their reaction to make one weapon attack.
Invisibility (Recharge 4–6). Tharmond magically turns invisible for up to 1 hour or until it attacks, he forces a creature to make a saving throw, or his concentration is broken (as if concentrating on a spell). Any equipment Tharmond wears or carries is invisible with it.
Bonus Actions
Enlarge (Recharges after a Short or Long Rest). For 1 minute, Tharmond magically increases in size, along with anything he is wearing or carrying. While enlarged, Tharmond is Large, doubles its damage dice on Strength-based weapon attacks (included in the attacks), and makes Strength checks and Strength saving throws with advantage. If Tharmond lacks the room to become Large, he attains the maximum size possible in the space available.
Reactions
Scouring Instruction. When an ally that Tharmond can see makes a d20 roll, Tharmond can roll a d6, and the ally can add the number rolled to the d20 by taking 3 (1d6) psychic damage.