commit 0c123ddeacd82c061b1ef87d261fdc444a8506b6 Author: Mike Bloy Date: Sat Jan 10 14:30:32 2026 -0600 initial commit diff --git a/zz_meta/bases/PDFinfo.base b/zz_meta/bases/PDFinfo.base new file mode 100644 index 0000000..6360279 --- /dev/null +++ b/zz_meta/bases/PDFinfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/CampaignInfo.base b/zz_meta/bases/ttrpg/CampaignInfo.base new file mode 100644 index 0000000..ec8ff40 --- /dev/null +++ b/zz_meta/bases/ttrpg/CampaignInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/FactionInfo.base b/zz_meta/bases/ttrpg/FactionInfo.base new file mode 100644 index 0000000..e31dbb3 --- /dev/null +++ b/zz_meta/bases/ttrpg/FactionInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/RegionInfo.base b/zz_meta/bases/ttrpg/RegionInfo.base new file mode 100644 index 0000000..7eafc6e --- /dev/null +++ b/zz_meta/bases/ttrpg/RegionInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/SessionInfo.base b/zz_meta/bases/ttrpg/SessionInfo.base new file mode 100644 index 0000000..64d81d8 --- /dev/null +++ b/zz_meta/bases/ttrpg/SessionInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/SettlementInfo.base b/zz_meta/bases/ttrpg/SettlementInfo.base new file mode 100644 index 0000000..fed2a33 --- /dev/null +++ b/zz_meta/bases/ttrpg/SettlementInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/SystemInfo.base b/zz_meta/bases/ttrpg/SystemInfo.base new file mode 100644 index 0000000..008920a --- /dev/null +++ b/zz_meta/bases/ttrpg/SystemInfo.base @@ -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 diff --git a/zz_meta/bases/ttrpg/SystemSettingCampaigns.base b/zz_meta/bases/ttrpg/SystemSettingCampaigns.base new file mode 100644 index 0000000..cad0781 --- /dev/null +++ b/zz_meta/bases/ttrpg/SystemSettingCampaigns.base @@ -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 diff --git a/zz_meta/js/templater/ttrpg.js b/zz_meta/js/templater/ttrpg.js new file mode 100644 index 0000000..ba91375 --- /dev/null +++ b/zz_meta/js/templater/ttrpg.js @@ -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, +}; diff --git a/zz_meta/js/templater/util.js b/zz_meta/js/templater/util.js new file mode 100644 index 0000000..364620e --- /dev/null +++ b/zz_meta/js/templater/util.js @@ -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, +}; diff --git a/zz_meta/shell/ttrpg/update_faction_metadata.sh b/zz_meta/shell/ttrpg/update_faction_metadata.sh new file mode 100755 index 0000000..11de0da --- /dev/null +++ b/zz_meta/shell/ttrpg/update_faction_metadata.sh @@ -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 diff --git a/zz_meta/shell/ttrpg/update_session_metadata.sh b/zz_meta/shell/ttrpg/update_session_metadata.sh new file mode 100755 index 0000000..09d3b67 --- /dev/null +++ b/zz_meta/shell/ttrpg/update_session_metadata.sh @@ -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 diff --git a/zz_meta/templater/ttrpg/campaign.md b/zz_meta/templater/ttrpg/campaign.md new file mode 100644 index 0000000..55a4e32 --- /dev/null +++ b/zz_meta/templater/ttrpg/campaign.md @@ -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]] \ No newline at end of file diff --git a/zz_meta/templater/ttrpg/creature.md b/zz_meta/templater/ttrpg/creature.md new file mode 100644 index 0000000..40609a8 --- /dev/null +++ b/zz_meta/templater/ttrpg/creature.md @@ -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() %> diff --git a/zz_meta/templater/ttrpg/faction.md b/zz_meta/templater/ttrpg/faction.md new file mode 100644 index 0000000..9af1d32 --- /dev/null +++ b/zz_meta/templater/ttrpg/faction.md @@ -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]] + diff --git a/zz_meta/templater/ttrpg/item.md b/zz_meta/templater/ttrpg/item.md new file mode 100644 index 0000000..306cca7 --- /dev/null +++ b/zz_meta/templater/ttrpg/item.md @@ -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() %> diff --git a/zz_meta/templater/ttrpg/person.md b/zz_meta/templater/ttrpg/person.md new file mode 100644 index 0000000..ba85fca --- /dev/null +++ b/zz_meta/templater/ttrpg/person.md @@ -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() %> diff --git a/zz_meta/templater/ttrpg/point-of-interest.md b/zz_meta/templater/ttrpg/point-of-interest.md new file mode 100644 index 0000000..4552846 --- /dev/null +++ b/zz_meta/templater/ttrpg/point-of-interest.md @@ -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() %> diff --git a/zz_meta/templater/ttrpg/region.md b/zz_meta/templater/ttrpg/region.md new file mode 100644 index 0000000..b91fd76 --- /dev/null +++ b/zz_meta/templater/ttrpg/region.md @@ -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]] diff --git a/zz_meta/templater/ttrpg/session.md b/zz_meta/templater/ttrpg/session.md new file mode 100644 index 0000000..bbbc230 --- /dev/null +++ b/zz_meta/templater/ttrpg/session.md @@ -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]] \ No newline at end of file diff --git a/zz_meta/templater/ttrpg/setting.md b/zz_meta/templater/ttrpg/setting.md new file mode 100644 index 0000000..81881cb --- /dev/null +++ b/zz_meta/templater/ttrpg/setting.md @@ -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]] \ No newline at end of file diff --git a/zz_meta/templater/ttrpg/settlement.md b/zz_meta/templater/ttrpg/settlement.md new file mode 100644 index 0000000..a54afcc --- /dev/null +++ b/zz_meta/templater/ttrpg/settlement.md @@ -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]] + diff --git a/zz_meta/templater/ttrpg/system.md b/zz_meta/templater/ttrpg/system.md new file mode 100644 index 0000000..c12a736 --- /dev/null +++ b/zz_meta/templater/ttrpg/system.md @@ -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]] \ No newline at end of file diff --git a/zz_meta/utility/Leaflet Bounds Calculator.md b/zz_meta/utility/Leaflet Bounds Calculator.md new file mode 100644 index 0000000..0476265 --- /dev/null +++ b/zz_meta/utility/Leaflet Bounds Calculator.md @@ -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]` + +