<%*
// 1) Prompt for Personās Name and rename file const personName = await tp.system.prompt(āEnter Personās Nameā, tp.file.title); if (!personName) return; await tp.file.rename(personName);
// 2) Gather all potential residence notes const allFiles = tp.app.vault.getMarkdownFiles(); const locationFiles = allFiles.filter(f ā f.path.startsWith(ā2-World/Hubs/ā) || f.path.startsWith(ā2-World/Points of Interest/ā) || f.path.startsWith(ā2-World/Regions/ā) || f.path.startsWith(ā2-World/Places/ā) );
// Add placeholder option const placeholderLabel = āš No Residence Selectedā; const placeholderPath = āplaceholderā;
const locationChoices = [placeholderLabel, ā¦locationFiles.map(f ā f.basename)]; const locationValues = [placeholderPath, ā¦locationFiles.map(f ā f.path)];
const chosenPath = await tp.system.suggester(locationChoices, locationValues, true); if (!chosenPath) return;
// 3) Build wiki-link let locationLink = null; if (chosenPath !== placeholderPath) { const alias = chosenPath.split(ā/ā).pop().replace(/.md{chosenPath}|${alias}]]`; }
// 4) Insert into front-matter as MyContainer setTimeout(() ā { const file = tp.file.find_tfile(tp.file.path(true)); if (!file) return; app.fileManager.processFrontMatter(file, fm ā { fm[āMyContainerā] = locationLink ?? āNoneā; }); }, 100);
%>
Parent Location:
INPUT[inlineListSuggester(optionQuery(#Category/Hub),optionQuery(#Category/Region),optionQuery(#Category/Place),optionQuery(#Category/PointofInterest)):MyContainer]
Column
Place Name
INPUT[select( option(1, ā¹ļøGeneral), option(2, šStatblock), option(3, šGM Notes), class(tabbed) )]Tabbed
NOTE
INPUT[select( option(1, āļøInventory), option(2, šConnections), option(3, š§āš¤āš§Relationships), class(tabbed) )]Tabbed
General
Name: = this.file.name
Status: INPUT[template-person-status][:char_status]
Race/Species: INPUT[template-person-race][:char_race]
Gender: INPUT[template-person-gender][:char_gender]
Age: INPUT[template-person-age-range][:char_age]
This is the persons description.
Statblock
monster: CommonerGM Notes
Make notes of what you need to track in the town here.
Inventory
The following items belong to = this.file.name.
// This dataviewjs code grabs a random item(s) from the folder below. You can remove this if that's not useful. It's an example of what's possible.
// 1. grab all pages in the folder
let pages = dv.pages('"3-Mechanics/Items"').values;
// 2. shuffle (FisherāYates)
for (let i = pages.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[pages[i], pages[j]] = [pages[j], pages[i]];
}
// 3. take the first two
let pick = pages.slice(0, 1);
// 4. render table of clickable links + Gender
dv.table(
["Random Item", "cost", "weight"],
pick.map(p => [
dv.fileLink(p.file.path), // clickable note link
p.cost ?? "ā", // frontmatter field (falls back to āāā if missing)
p.weight ?? "ā" // frontmatter field (falls back to āāā if missing)
])
);Connections
Is the person linked to any groups or quests?
Quests: INPUT[inlineListSuggester(optionQuery(#Category/Quest)):Connected_Quests]
Groups: INPUT[inlineListSuggester(optionQuery(#Category/Group)):Connected_Groups]
Relationships
List important relationships here.
var parents = dv.current().parents ?? [];
var children = dv.current().children ?? [];
var enemies = dv.current().enemies ?? [];
var allies = dv.current().allies ?? [];
var siblings = dv.current().siblings ?? [];
var current = dv.current().file.name;
var partner = dv.current().partner ?? [];
dv.paragraph("```mermaid\nflowchart LR\n" +
// Parents with internal-link on individual nodes only
(parents.length > 0 ? parents.map((parent, index) => `P${index + 1}[${parent}]:::internal-link\nP${index + 1} --> Current\n`).join('') : '') +
// Current node
`Current[${current}]\n` +
// Partner group node (no internal-link applied)
(partner.length > 0 ? `PT[Partner]\nCurrent --> PT\n` : '') +
// Individual partners with internal-link
(partner.length > 0 ? partner.map((p, index) => `PT${index + 1}[${p}]:::internal-link\nPT --> PT${index + 1}\n`).join('') : '') +
// Children group node (no internal-link applied)
(children.length > 0 ? `C[Children]\nCurrent --> C\n${children.map((child, index) => `C${index + 1}[${child}]:::internal-link\nC --> C${index + 1}\n`).join('')}` : '') +
// Siblings group node (no internal-link applied)
(siblings.length > 0 ? `S[Siblings]\nCurrent --> S\n${siblings.map((sibling, index) => `S${index + 1}[${sibling}]:::internal-link\nS --> S${index + 1}\n`).join('')}` : '') +
// Enemies group node (no internal-link applied)
(enemies.length > 0 ? `E[Enemies]\nCurrent --> E\n${enemies.map((enemy, index) => `E${index + 1}[${enemy}]:::internal-link\nE --> E${index + 1}\n`).join('')}` : '') +
// Allies group node (no internal-link applied)
(allies.length > 0 ? `A[Allies]\nCurrent --> A\n${allies.map((ally, index) => `A${index + 1}[${ally}]:::internal-link\nA --> A${index + 1}\n`).join('')}` : '') +
// Styling: Apply internal-link only to individual nodes, not group nodes
`class ${parents.length > 0 ? parents.map((_, index) => `P${index + 1},`).join('') : ''}Current${children.length > 0 ? children.map((_, index) => `C${index + 1},`).join('') : ''}${siblings.length > 0 ? siblings.map((_, index) => `S${index + 1},`).join('') : ''}${enemies.length > 0 ? enemies.map((_, index) => `E${index + 1},`).join('') : ''}${allies.length > 0 ? allies.map((_, index) => `A${index + 1},`).join('') : ''} internal-link;`
)Relationship Config - Enter name of People Notes
BUTTON[button_person]Nodes will link to notes of the same name.
Parents Partner Children INPUT[list:parents]INPUT[list:partner]INPUT[list:children]
Siblings Enemies Allies INPUT[list:siblings]INPUT[list:enemies]INPUT[list:allies]
