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
A resident of [[Torkef]] and bearer of the Hernespear. He was murdered by [[Auntie Agnes]].
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.
Whilst in the town the party had heard that the mage who lived nearby, Finethil Birlond, had investigated the accidents and tragedies but struggled to identify any magical causes for them. The party had also found, after hearing a woman’s scream cut off, that an old woman named Oma was found with bludgeoning injuries. The party had heard children’s cries and laughter about the same time before they happened upon her body. The party learned Oma had been the woman who cleaned and helped Birlond.
The party found the Nana Ruth’s cottage dark and disused, with a layer of dust. The party found a letter within from Birlond confirming that he would hire Nana Ruth and give her access to hyis tower following the passing of Oma.
The party then raced to Birlond’s tower. There they found the door open and that the tower interior was an extradimensional space. As the party entered they found a number of apparent constructs destroyed on the ground floor at the same time that they heard Birlond’s voice magically calling out that none would pass without a reckoning.
The party moved upwards and found themselves encountering other defences of the tower such as an infinite loop until they tried descending instead, which broke them out of it. They also found themselves facing enchanted rugs and the forces which were assaulting the tower. They found themselves facing giants and eladrin, all whilst hearing Birlond’s magical voice continue whilst he fought elsewhere,
Both Gideon and Iskar found themselves exhausted and traumatised by the ordeals they underwent during this, both utterly spent. Despite this the party continued on up the tower. Immediately prior to reaching the tower summit the party heard Birlond’s voice for the last time crying out,
The party found some fey on the roof and a portal. The party dispatched the fey and recognised that the portal lead directly and physically into Death. Gideon dared enter the portal and observed some distance closer to the First Gate as a slight figure, resembling Birlond, wrestled with a hulking figure. Gideon saw Birlond be cast down into the waters and the hulking figure wrest his staff from him. The hulking figure fought back up against Death’s currents and back into life, at a diagonal away from where Gideon stood. The figure, a large hideous crone waved and cackled “bye dearie”. Gideon struggled against the waters pulling at this legs and struggled back to the barrier to life himself, although he felt the urge to lie down and rest.
Back in life, Gideon and the party found themselves questioning what that crone had wanted in robbing Birlond’s staff from him. Calyn, along amongst the party, was able to perceive a bundled up robe on the roofs parapet. This was a Robe of Eyes, once worn by Birlond. There was a note tucked into it which read that it was intended for a watcher, someone with the eyes to see.
Finethil Birlond
Medium Humanoid (Wizard), Neutral
Armor Class 18
Hit Points 195 (26d8 + 78)
Speed 30 ft.
Initiative +8 (18)
STR
DEX
CON
INT
WIS
CHA
10 (+0)
16 (+3)
16 (+3)
20 (+5)
15 (+2)
16 (+3)
Saving Throws Int +10, Wis +7
Skills Arcana +15, History +10, Perception +7
Immunities Psychic; Charmed (with Mind Blank)
GearWandSenses Passive Perception 17
Languages Common, Dwarvish, Elvish, Sylvan, Primordial, Draconic
Challenge 14 (XP 11,500; PB +5)
Proficiency Bonus +5
Magic Resistance. Finethil Birlond has Advantage on saving throws against spells and other magical effects.
Actions
Multiattack. Finethil Birlond makes four Arcane Burst attacks.
Arcane Burst.Melee or Ranged Attack Roll: +10, reach 5 ft. or range 150 ft. Hit: 28 (4d10 + 6) Force damage.
Spellcasting. Finethil Birlond casts one of the following spells, using Intelligence as the spellcasting ability (spell save DC 18):
At will: Detect Magic, Detect Thoughts, Disguise Self, Invisibility, Light, Mage Armor (included in AC), Mage Hand, Prestidigitation
2/day each: Fly, Lightning Bolt (level 7 version)
1/day each: Cone of Cold (level 9 version), Mind Blank (cast before combat), Scrying, Teleport
Bonus Actions
Misty Step (3/Day). Finethil Birlond casts Misty Step, using the same spellcasting ability as Spellcasting.
Reactions
Protective Magic (3/Day). Finethil Birlond casts Counterspell or Shield in response to the spell’s trigger, using the same spellcasting ability as Spellcasting.