1
0

initial commit

This commit is contained in:
Mike Bloy 2026-01-10 14:30:32 -06:00
commit 0c123ddeac
24 changed files with 1104 additions and 0 deletions

View File

@ -0,0 +1,14 @@
filters:
and:
- this.pdfs.contains(file)
formulas:
File Size: if(file.size > 1024*1024, ((file.size / 1024 / 1024).toFixed(2) + "m"), if(file.size > 1024, ((file.size / 1024).toFixed(2) + "k"), file.size))
views:
- type: table
name: PDF List
order:
- file.name
- formula.File Size
sort:
- property: file.name
direction: ASC

View File

@ -0,0 +1,126 @@
filters:
or:
- and:
- list(campaigns).contains(this)
- this.hasTag("ttrpg/campaign")
- list(this.campaigns).filter(list(campaigns).contains(value)).length > 0
formulas:
Note: file.asLink(if(note.title, note.title, file.basename))
Game Date: '[note["fc-date"], note["fc-end"]].filter(value).join(" ")'
Real Date: '"" + realDate'
Place Type: if(file.hasTag("ttrpg/place/poi"), "Point of Interest", if(file.hasTag("ttrpg/place/region"), "Region", if(file.hasTag("ttrpg/place/settlement"), "Settlement", "Unknown")))
Place Subtype: if(poiType, poiType, if(settlementType, settlementType, if(regionType, regionType)))
properties:
note.sessionNumber:
displayName: Num
note.summary:
displayName: Summary
note.realDate:
displayName: Date
note.ancestry:
displayName: Ancestry
note.pronouns:
displayName: Pronouns
note.languages:
displayName: Languages
note.factionType:
displayName: Type
note.leader:
displayName: Leader
note.itemType:
displayName: Item Type
views:
- type: cards
name: Player Character Cards
filters:
and:
- file.hasTag("ttrpg/person")
- personType == "pc"
order:
- formula.Note
- Player
- ancestry
- pronouns
image: note.image
- type: table
name: Sessions
filters:
and:
- file.hasTag("ttrpg/session")
order:
- formula.Note
- sessionNumber
- formula.Real Date
- formula.Game Date
- summary
sort:
- property: sessionNumber
direction: ASC
- type: table
name: Factions
filters:
and:
- file.hasTag("ttrpg/faction")
order:
- formula.Note
- factionType
- leader
- summary
sort:
- property: formula.Note
direction: ASC
columnSize:
formula.Note: 125
note.factionType: 102
- type: table
name: Nonplayer Characters
filters:
and:
- file.hasTag("ttrpg/person")
- personType != "pc"
order:
- formula.Note
- ancestry
- pronouns
- languages
- summary
columnSize:
formula.Note: 140
note.pronouns: 111
note.languages: 127
- type: table
name: Places
filters:
and:
- file.hasTag("ttrpg/place")
groupBy:
property: formula.Place Type
direction: ASC
order:
- formula.Note
- formula.Place Type
- formula.Place Subtype
- location
- summary
sort:
- property: formula.Note
direction: ASC
- property: location
direction: ASC
columnSize:
formula.Note: 86
formula.Place Type: 114
note.location: 107
note.summary: 134
formula.Place Subtype: 130
- type: table
name: Items
filters:
and:
- file.hasTag("ttrpg/item")
order:
- formula.Note
- itemType
- summary
columnSize:
note.itemType: 136

View File

@ -0,0 +1,43 @@
formulas:
Type: if(file.hasTag("ttrpg/faction"), "Faction (" + note.factionType + ")", if(file.hasTag("ttrpg/person"), "Person (" + note.personType + ")", "Other"))
Category: |-
if(
file.hasTag("ttrpg/faction"),
"Faction (" + factionType + ")",
if(
file.hasTag("ttrpg/person"),
"Person (" + personType + ")", "Unknown"
)
)
Note: file.asLink(if(note.title, note.title, file.basename))
properties:
note.summary:
displayName: Summary
views:
- type: table
name: Members
filters:
and:
- or:
- |-
list(factions).filter(
list(file(value).properties.factions)
.contains(this)
).length > 0
- list(factions).contains(this)
- list(this.leader).contains(file)
- or:
- file.hasTag("ttrpg/faction")
- file.hasTag("ttrpg/person")
order:
- formula.Note
- formula.Category
- summary
sort:
- property: file.name
direction: ASC
- property: formula.Category
direction: ASC
columnSize:
formula.Note: 151
formula.Category: 179

View File

@ -0,0 +1,27 @@
formulas:
Note: link(file,if(title,title,file.basename))
Place Type: if(file.hasTag("ttrpg/place/region"),"Region", if(file.hasTag("ttrpg/place/settlement"), "Settlement", "Point of Interest"))
Place Subtype: if(regionType, regionType, if(settlementType, settlementType, poiType))
views:
- type: table
name: Places
filters:
and:
- file.hasTag("ttrpg/place")
- or:
- |-
list(location).filter(
list(file(value).properties.location)
.contains(this) && file(value).hasTag("ttrpg/place/region")
).length > 0
- list(location).contains(this.file)
order:
- formula.Note
- formula.Place Type
- formula.Place Subtype
- summary
sort:
- property: file.name
direction: DESC
columnSize:
formula.Note: 135

View File

@ -0,0 +1,23 @@
filters:
and:
- list(this.campaigns).containsAny(list(campaigns))
- file.hasTag("ttrpg/session")
formulas:
Session: sessionNumber
Title: if(title, title, file.basename)
properties:
formula.Session:
displayName: Session Number
views:
- type: cards
name: Navigation
filters:
or:
- (sessionNUmber - this.sessionNumber).abs() == 1
order:
- formula.Title
- summary
sort:
- property: sessionNumber
direction: ASC
cardSize: 340

View File

@ -0,0 +1,59 @@
formulas:
Note: link(file, if(title, title, file.basename))
Place Type: if(file.hasTag("ttrpg/place/region"),"Region", if(file.hasTag("ttrpg/place/settlement"), "Settlement", "Point of Interest"))
Place Subtype: if(regionType, regionType, if(settlementType, settlementType, poiType))
views:
- type: table
name: Places
filters:
and:
- file.hasTag("ttrpg/place")
- or:
- |-
list(location).filter(
list(file(value).properties.location)
.contains(this)
).length > 0
- list(location).contains(this.file)
order:
- formula.Note
- formula.Place Type
- formula.Place Subtype
- summary
sort:
- property: file.name
direction: DESC
columnSize:
formula.Note: 135
- type: table
name: People
filters:
and:
- or:
- list(this.residents).contains(file)
- list(this.leader).contains(file)
- |-
list(this.leader).filter(
list(file.properties.factions)
.contains(value)
).length > 0
- |-
list(this.residents).filter(
list(file.properties.factions)
.contains(value)
).length > 0
- |-
list(location).filter(
list(file(value).properties.location)
.contains(this)
).length > 0
- list(location).contains(this)
- or:
- file.hasTag("ttrpg/person")
order:
- formula.Note
- pronunciation
- pronouns
- summary
columnSize:
formula.Note: 149

View File

@ -0,0 +1,13 @@
filters:
and:
- link(system).asFile() == this.file
formulas:
Note: file.asLink(if(title, title, file.basename))
views:
- type: list
name: Rules Helpers
filters:
and:
- file.hasTag("ttrpg/rules")
order:
- formula.Note

View File

@ -0,0 +1,33 @@
filters:
and:
- or:
- and:
- this.file.hasTag("ttrpg/setting")
- link(setting).asFile() == this.file
- and:
- this.file.hasTag("ttrpg/system")
- link(system).asFile() == this.file
- file.hasTag("ttrpg/campaign")
formulas:
Players: players.join(", ")
properties:
note.players:
displayName: Players
note.system:
displayName: System
note.gm:
displayName: GM
note.setting:
displayName: Setting
views:
- type: cards
name: Campaigns
order:
- file.name
- gm
- formula.Players
- system
- setting
cardSize: 200
imageAspectRatio: 0.65
image: note.image

View File

@ -0,0 +1,85 @@
function fileHasTag(file, tag) {
const cache = app.metadataCache.getFileCache(file);
const allTags = (cache?.frontmatter?.tags ?? []).concat(
cache?.tags?.map((t) => (t.tag[0] === "#" ? t.tag.slice(1) : t.tag)),
);
return allTags.some((t) => t === tag || t?.startsWith(`${tag}/`));
}
function fileInParentWithTag(file, tag) {
return app.vault
.getMarkdownFiles()
.filter(
(mdFile) =>
file.path.startsWith(mdFile.parent.path) && fileHasTag(mdFile, tag),
)?.[0];
}
function campaignData(file) {
const campaignFile =
fileInParentWithTag(file, "ttrpg/campaign") ||
app.vault.getFileByPath("index.md");
const data = {};
console.log("campaign file", campaignFile);
if (campaignFile) {
const cache = app.metadataCache.getFileCache(campaignFile);
const fm = cache?.frontmatter;
const settingFile = frontmatterLinksToTFiles(campaignFile, "setting")?.[0];
data.players = fm?.players;
data.gm = fm?.gm;
data.title = fm?.title || campaignFile.basename;
data.system = fm?.system;
data.setting = fm?.setting;
data.settingFile = settingFile;
data.file = campaignFile;
data.link = app.fileManager.generateMarkdownLink(
campaignFile,
file.path,
null,
data.title,
);
}
return data;
}
function frontmatterLinksToTFiles(sourceFile, property) {
const links = app.metadataCache.getFileCache(sourceFile)?.frontmatterLinks;
if (links) {
return app.metadataCache
.getFileCache(sourceFile)
?.frontmatterLinks?.filter((l) => l.key.startsWith(property))
?.map((l) =>
app.metadataCache.getFirstLinkpathDest(l.link, sourceFile.path),
)
?.filter((f) => f);
} else {
return [];
}
}
function settingData(file) {
const settingFile =
fileInParentWithTag(file, "ttrpg/setting") ||
campaignData(file)?.settingFile ||
app.vault.getFileByPath("index.md");
const data = {};
if (settingFile) {
const cache = app.metadataCache.getFileCache(settingFile);
const fm = cache?.frontmatter;
data.title = fm?.title || campaignFile.basename;
data.file = settingFile;
data.calendar = fm?.["fc-calendar"];
data.link = app.fileManager.generateMarkdownLink(
settingFile,
file.path,
null,
data.title,
);
}
return data;
}
module.exports = {
campaignData: campaignData,
settingData: settingData,
};

View File

@ -0,0 +1,113 @@
async function updateMetadata(tp, options) {
console.log("options", options);
const file = tp.config.target_file;
const data = options?.data ?? {};
const tags = new Set([options?.tags ?? []].flat());
const tagsToRemove = new Set([options?.tagsToRemove ?? []].flat());
const title = options?.title;
for (const tag of tags) {
const splitTag = tag.split("/");
for (let i = 1; i < splitTag.length; i++) {
tagsToRemove.add(splitTag.slice(0, i).join("/"));
}
}
if (tp.file.title === "Untitled" && title) {
await tp.file.rename(title);
}
tp.hooks.on_all_templates_executed(async () => {
await tp.app.fileManager.processFrontMatter(file, (frontmatter) => {
console.log("frontmatter before", frontmatter);
let fmTags = new Set([frontmatter.tags ?? []].flat());
fmTags = tags.difference(tagsToRemove).union(tags);
frontmatter.tags = Array.from(fmTags);
frontmatter.tags.sort();
for (const key in data) {
frontmatter[key] = data[key];
}
console.log("frontmatter before", frontmatter);
});
});
}
function getFileProperty(file, property) {
const frontmatter = app.metadataCache.getFileCache(file)?.frontmatter;
return frontmatter?.[property];
}
function hasPropertyValue(file, property, value) {
const propValue = getFileProperty(file, property);
if (Array.isArray(propValue)) {
return propValue.includes(value);
}
return propValue === value;
}
function frontmatterLinksToTFiles(sourceFile, property) {
const links = app.metadataCache.getFileCache(sourceFile)?.frontmatterLinks;
if (links) {
return app.metadataCache
.getFileCache(sourceFile)
?.frontmatterLinks?.filter((l) => l.key.startsWith(property))
?.map((l) =>
app.metadataCache.getFirstLinkpathDest(l.link, sourceFile.path),
)
?.filter((f) => f);
} else {
return [];
}
}
function slugify(input) {
if (!input) return "";
// Make lower case and trim
var slug = input.toLowerCase().trim();
// Remove accents from characters
slug = slug.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
// Replace invalid chars with spaces
slug = slug.replace(/[^a-z0-9\s-]/g, " ").trim();
// Replace multiple spaces or hyphens with a single hyphen
slug = slug.replace(/[\s-]+/g, "-");
return slug;
}
function getAllTags(file) {
const cache = app.metadataCache.getFileCache(file);
const fileTags =
cache?.tags?.map((t) => (t.tag[0] === "#" ? t.tag.slice(1) : t.tag)) || [];
const fmTags = [cache?.frontmatter?.tags || []].flat();
return fmTags.concat(fileTags);
}
function filesWithTag(tag) {
console.log("files with tag", tag);
const files = app.vault.getMarkdownFiles().filter((file) => {
const tags = getAllTags(file);
return tags?.includes(tag) || tags?.some((t) => t.startsWith(`${tag}/`));
});
return files;
}
function fileHasTag(file, tag) {
const cache = app.metadataCache.getFileCache(file);
const allTags = (cache?.frontmatter?.tags ?? []).concat(
cache?.tags?.map((t) => (t.tag[0] === "#" ? t.tag.slice(1) : t.tag)),
);
return allTags.some((t) => t === tag || t?.startsWith(`${tag}/`));
}
module.exports = {
slugify,
getAllTags,
filesWithTag,
fileHasTag,
frontmatterLinksToTFiles,
getFileProperty,
hasPropertyValue,
updateMetadata,
};

View File

@ -0,0 +1,16 @@
#!/bin/zsh
for file in **/*.md; do
echo "foo$file"
yq \
--front-matter="process" \
--inplace \
'
.tags = ["ttrpg/faction"] |
.icon = "users" |
.summary = .summary // "" |
.campaigns = ["[[Kingmaker|Kingmaker]]"] |
del(.type) |
del(.campaign)
' \
"${file}"
done

View File

@ -0,0 +1,31 @@
#!/bin/bash
files=Session*.md
for file in ${files[@]}; do
echo "$file"
export realDate=$(grep 'Real World Date' "$file" | cut -d' ' -f5)
yq \
--front-matter="process" \
--inplace \
'
.tags = ["ttrpg/session"] |
.icon = "book-open" |
.title = "Session " + .session_number |
.gm = "Mike" |
.players = ["Jeff", "Brian", "Oz", "Andy", "Oz"] |
.sessionNumber = .session_number |
.summary = .summary // .["aat-event-body"] // "" |
.aliases = ["Session " + .session_number] |
.realDate = strenv(realDate) |
.["fc-calendar"] = "Calendar of Golarion" |
.["fc-display-name"] = "Kingmaker Session " + .session_number |
.["fc-category"] = "Kingmaker" |
.campaigns = ["[[Kingmaker|Kingmaker]]"] |
del(.type) |
del(.timelines) |
del(.["aat-render-enabled"]) |
del(.session_number) |
del(.campaign) |
del(.["aat-event-body"])
' \
"${file}"
done

View File

@ -0,0 +1,78 @@
<%*
const title = (
tp.file.title === "Untitled"
? await tp.system.prompt("Campaign Title")
: tp.file.title
);
const gm = await tp.system.prompt("Add a GM to this campaign")
let isAddingPlayers = true;
const players = [];
while (isAddingPlayers) {
const player = await tp.system.prompt("Add a player to this campaign")
if (player) {
players.push(player)
} else {
isAddingPlayers = false;
}
}
const settingFiles = tp.user.util.filesWithTag("ttrpg/setting");
const settingFile = (
settingFiles.length > 0
? await tp.system.suggester((file) => file.basename, settingFiles, false, "Select a setting")
: null
);
const systemFiles = tp.user.util.filesWithTag("ttrpg/system");
const systemFile = (
systemFiles.length > 0
? await tp.system.suggester((file) => file.basename, systemFiles, false, "Select a system")
: null
);
const metadata = {
title,
tags: ["ttrpg/campaign"],
data: {
icon: "notebook-tabs",
title,
players,
gm,
pdfs: [],
campaignStatus: "planning",
},
};
if (settingFile) {
metadata.data.setting = tp.app.fileManager.generateMarkdownLink(
settingFile, tp.file.path(true), null, settingFile.basename
);
}
if (systemFile) {
metadata.data.system = tp.app.fileManager.generateMarkdownLink(
systemFile, tp.file.path(true), null, systemFile.basename
);
}
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>
## Player Characters
![[CampaignInfo.base#Player Character Cards]]
## Sessions
![[CampaignInfo.base#Sessions]]
## Factions
![[CampaignInfo.base#Factions]]
## NPCs
![[CampaignInfo.base#Nonplayer Characters]]
## Places
![[CampaignInfo.base#Places]]
## PDFs
![[PDFinfo.base]]

View File

@ -0,0 +1,28 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Creature Name")
: tp.file.title;
const type = tp.frontmatter.creatureType ?? ""
const metadata = {
tags: ['ttrpg/creature'],
data: {
icon: "squirrel",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
system: tp.frontmatter?.system ?? "",
creatureType: type,
adjective: tp.frontmatter?.adjective ?? "",
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>

View File

@ -0,0 +1,44 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Faction Name")
: tp.file.title;
const adjective = tp.frontmatter?.adjective ?? "";
const types = [
"family",
"military",
"secret society",
"political",
"government",
"religious",
"academic",
"criminal",
"social",
"commercial",
"ethnic group",
];
const type = tp.frontmatter.factionType ?? await tp.system.suggester(v => v, types, true, "Type of Faction");
const metadata = {
tags: ['ttrpg/faction'],
data: {
icon: "users",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
factionType: type,
headquarters: tp.frontmatter?.headquarters ?? "",
leader: tp.frontmatter?.leader ?? "",
adjective: tp.frontmatter?.adjective ?? "",
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>
## Members
![[FactionInfo.base#Members]]

View File

@ -0,0 +1,27 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Item Name")
: tp.file.title;
const type = tp.frontmatter.itemType ?? ""
const metadata = {
tags: ['ttrpg/item'],
data: {
icon: "amphora",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
system: tp.frontmatter?.system ?? "",
itemType: type,
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>

View File

@ -0,0 +1,43 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Person Name")
: tp.file.title;
const genders = {
"N/A": "it",
"Male": "he/him",
"Female": "she/her",
"Nonbinary": "they/them",
}
const types = {"npc": "Non-player Character", "pc": "Player Character"};
const type = tp.frontmatter.personType ?? await tp.system.suggester(v => types[v], Object.keys(types), true, "Type of Character");
const gender = tp.frontmatter?.gender ?? (await tp.system.suggester(v => v, Object.keys(genders), false, "Gender") ?? "N/A");
const pronouns = tp.frontmatter.pronouns ?? genders[gender];
const metadata = {
tags: ['ttrpg/person'],
data: {
icon: "user",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
personType: type,
gender,
pronouns,
ancestry: tp.frontmatter?.ancestry ?? "",
languages: tp.frontmatter?.languages ?? [],
factions: tp.frontmatter?.factions ?? [],
location: tp.frontmatter?.location ?? [],
},
title,
};
if (type === "pc") {
metadata.data.player = tp.frontmatter?.player ?? await tp.system.prompt("Player Name");
}
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>

View File

@ -0,0 +1,44 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Location Name")
: tp.file.title;
const adjective = tp.frontmatter?.adjective ?? "";
const types = [
"shop",
"landmark",
"residence",
"temple",
"government building",
"factory",
"fortress",
"military building",
"ruin",
"cave",
"ship",
];
const type = tp.frontmatter.poiType ?? await tp.system.suggester(v => v, types, true, "Type of PoI");
const metadata = {
tags: ['ttrpg/place/poi'],
data: {
icon: "map-pin",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
poiType: type,
location: tp.frontmatter?.location ?? "",
wares: tp.frontmatter?.wares ?? "",
proprietor: tp.frontmatter?.proprietor ?? "",
residents: tp.frontmatter?.residents ?? [],
factions: tp.frontmatter?.factions ?? [],
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>

View File

@ -0,0 +1,65 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Region Name")
: tp.file.title;
const adjective = tp.frontmatter?.adjective ?? "";
const types = [
"nation",
"duchy",
"county",
"state",
"star system",
"planet",
"sector",
"continent",
];
const govTypes = [
"anarchy",
"athenian democracy",
"caste",
"city-states",
"clan/tribal",
"corporate state",
"dictatorship",
"feudal",
"hive mind",
"representative democracy",
"technocracy",
"theocracy",
"bureaucracy",
"charismatic rule",
"cybercracy/machine civilization",
"meritocracy",
"military government",
"oligarchy",
"thaumatocracy",
];
const type = tp.frontmatter.regionType ?? await tp.system.suggester(v => v, types, true, "Type of Region");
const metadata = {
tags: ['ttrpg/place/region'],
data: {
icon: "map",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
regionType: type,
capital: tp.frontmatter?.capital ?? "",
location: tp.frontmatter?.location ?? "",
population: tp.frontmatter?.population ?? 0,
government: tp.frontmatter?.government ?? (await tp.system.suggester(v => v, govTypes, false, "Type of Government")) ?? "",
leader: tp.frontmatter?.leader ?? "",
adjective: tp.frontmatter?.adjective ?? "",
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>
![[zz_meta/bases/ttrpg/RegionInfo.base#Places|RegionInfo]]

View File

@ -0,0 +1,52 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const sessionNumber = Math.max(0, ...(
tp.user.util.filesWithTag("ttrpg/session")
.filter(f => tp.user.util.frontmatterLinksToTFiles(f, 'campaigns').includes(campaignData.file))
.map(f => tp.user.util.getFileProperty(f, "sessionNumber"))
.filter(n => n === 0 || n) || 0)
) + 1;
const title = tp.file.title === "Untitled" ? `Session ${sessionNumber}` : tp.file.title;
let padSessionNumber = `${sessionNumber}`
while (padSessionNumber.length < 3) {
padSessionNumber = `0${padSessionNumber}`
}
const metadata = {
tags: ["ttrpg/session"],
data: {
icon: "book-open",
title,
gm: campaignData.gm,
players: campaignData.players,
sessionNumber,
summary: "",
aliases: [
title,
`${campaignData?.title} ${title}`
],
campaigns: [campaignData.link],
realDate: tp.date.now('YYYY-MM-DD')
},
title: `Session ${padSessionNumber}_${tp.date.now('YYYY-MM-DD')}`
};
if (settingData?.calendar) {
metadata.data["fc-calendar"] = settingData.calendar;
metadata.data["fc-display-name"] = `${campaignData?.title} ${title}`;
metadata.data["fc-date"] = "";
metadata.data["fc-end"] = "";
metadata.data["fc-category"] = `${campaignData?.title}`;
}
await tp.user.util.updateMetadata(tp, metadata);
%>
## Recap
- <% tp.file.cursor() %>
## Session Info
-
---
![[SessionInfo.base#Navigation]]

View File

@ -0,0 +1,31 @@
<%*
const title = (
tp.file.title === "Untitled"
? await tp.system.prompt("Setting Title")
: tp.file.title
);
const calendarId = (
tp.frontmatter?.["fc-calendar"]
? tp.frontmatter["fc-calendar"]
: await tp.system.prompt("Setting Calendar ID", title)
)
const metadata = {
title,
tags: ["ttrpg/setting"],
data: {
icon: "globe",
title,
"fc-calendar": calendarId,
pdfs: tp.frontmatter.pdfs ?? [],
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
![[SystemSettingCampaigns.base]]
<% tp.file.cursor() %>
---
![[PDFinfo.base]]

View File

@ -0,0 +1,69 @@
<%*
const thisFile = tp.config.target_file;
const campaignData = tp.user.ttrpg.campaignData(thisFile)
const settingData = tp.user.ttrpg.settingData(thisFile);
const title = tp.file.title === "Untitled"
? await tp.system.prompt("Settlement Name")
: tp.file.title;
const adjective = tp.frontmatter?.adjective ?? "";
const types = [
"thorp",
"hamlet",
"village",
"small town",
"large town",
"city ward",
"neighborhood",
"small city",
"large city",
"metropolis",
];
const govTypes = [
"anarchy",
"athenian democracy",
"caste",
"clan/tribal",
"corporate state",
"dictatorship",
"feudal",
"hive mind",
"representative democracy",
"technocracy",
"theocracy",
"bureaucracy",
"charismatic rule",
"cybercracy/machine civilization",
"meritocracy",
"military government",
"oligarchy",
"thaumatocracy",
];
const type = tp.frontmatter.settlementType ?? await tp.system.suggester(v => v, types, true, "Type of Settlement");
const metadata = {
tags: ['ttrpg/place/settlement'],
data: {
icon: "building-2",
title,
pronunciation: tp.frontmatter.pronunciation ?? "",
summary: tp.frontmatter?.summary ?? "",
campaigns: [campaignData.link],
setting: settingData.link,
settlementType: type,
location: tp.frontmatter?.location ?? "",
population: tp.frontmatter?.population ?? 0,
government: tp.frontmatter?.government ?? (await tp.system.suggester(v => v, govTypes, false, "Type of Government")) ?? "",
leader: tp.frontmatter?.leader ?? "",
residents: tp.frontmatter?.residents ?? [],
adjective: tp.frontmatter?.adjective ?? "",
},
title,
};
await tp.user.util.updateMetadata(tp, metadata);
%>
<% tp.file.cursor() %>
![[zz_meta/bases/ttrpg/SettlementInfo.base#Places|SettlementInfo]]
![[zz_meta/bases/ttrpg/SettlementInfo.base#People|SettlementInfo]]

View File

@ -0,0 +1,24 @@
<%*
const title = (
tp.file.title === "Untitled"
? await tp.system.prompt("System Title")
: tp.file.title
);
const metadata = {
title,
tags: ["ttrpg/system"],
data: {
icon: "notebook",
title,
pdfs: tp.frontmatter.pdfs ?? [],
},
};
await tp.user.util.updateMetadata(tp, metadata);
%>
![[SystemSettingCampaigns.base]]
<% tp.file.cursor() %>
---
![[PDFinfo.base]]

View File

@ -0,0 +1,16 @@
---
image:
height: 768
width: 1024
pixelDistance: 100
unitDistance: 12
---
**Image Height:** `INPUT[number:image.height]`px
**Image Width:** `INPUT[number:image.width]`px
**Distance:** `INPUT[number:image.pixelDistance]`pixels = `INPUT[number:image.unitDistance]`units (feet, miles, km, parsecs, etc)
**Lower Bound:** 0, 0
**Upper Bound:** `VIEW[round({image.height}/({image.pixelDistance}/{image.unitDistance}), 3)][math]`, `VIEW[round({image.width}/({image.pixelDistance}/{image.unitDistance}), 3)][math]`
**Center Point:** `VIEW[round({image.height}/({image.pixelDistance}/{image.unitDistance})/2, 3)][math]`, `VIEW[round({image.width}/({image.pixelDistance}/{image.unitDistance})/2, 3)][math]`