<%*

// 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: Commoner

GM 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;`
)