From dacc18b47fec3f23c17037feb2a950a407c44e7f Mon Sep 17 00:00:00 2001 From: Luca Gioppo Date: Sun, 17 Sep 2023 17:39:32 +0200 Subject: [PATCH] feature: NPC sheet export (#90) Added new mapping field for NPC and new mapping fo 5e --- mappings/dnd5eV11-npc.mapping | 200 ++++++++++++++++++++++++++++++++++ pdf/npc sheet 5e.pdf | Bin 0 -> 61367 bytes scripts/pdfsheet.js | 119 +++++++++++++++++++- 3 files changed, 316 insertions(+), 3 deletions(-) create mode 100644 mappings/dnd5eV11-npc.mapping create mode 100644 pdf/npc sheet 5e.pdf diff --git a/mappings/dnd5eV11-npc.mapping b/mappings/dnd5eV11-npc.mapping new file mode 100644 index 0000000..93bfef0 --- /dev/null +++ b/mappings/dnd5eV11-npc.mapping @@ -0,0 +1,200 @@ +/* PDF: https://media.wizards.com/2016/dnd/downloads/5E_CharacterSheet_Fillable.pdf */ +[ + { "pdf": "NpcName", "foundry": @name }, + { "pdf": "Race", "foundry": @system.details.race }, + { "pdf": "Type", "foundry": @system.details.type.value + " (" + game.dnd5e.config.actorSizes[@system.traits.size] + ")" + " - " + @system.details.alignment}, + { "pdf": "str", "foundry": @system.abilities.str.value }, + { "pdf": "STRmod", "foundry": @system.abilities.str.mod + " (sv: " + @system.abilities.str.save + ")"}, + { "pdf": "dex", "foundry": @system.abilities.dex.value }, + { "pdf": "DEXmod", "foundry": @system.abilities.dex.mod + " (sv: " + @system.abilities.dex.save + ")" }, + { "pdf": "con", "foundry": @system.abilities.con.value }, + { "pdf": "CONmod", "foundry": @system.abilities.con.mod + " (sv: " + @system.abilities.con.save + ")" }, + { "pdf": "int", "foundry": @system.abilities.int.value }, + { "pdf": "INTmod", "foundry": @system.abilities.int.mod + " (sv: " + @system.abilities.int.save + ")" }, + { "pdf": "wis", "foundry": @system.abilities.wis.value }, + { "pdf": "WISmod", "foundry": @system.abilities.wis.mod + " (sv: " + @system.abilities.wis.save + ")" }, + { "pdf": "cha", "foundry": @system.abilities.cha.value }, + { "pdf": "CHAmod", "foundry": @system.abilities.cha.mod + " (sv: " + @system.abilities.cha.save + ")" }, + { "pdf": "str-prof", "foundry": @system.abilities.str.proficient }, + { "pdf": "dex-prof", "foundry": @system.abilities.dex.proficient }, + { "pdf": "con-prof", "foundry": @system.abilities.con.proficient }, + { "pdf": "int-prof", "foundry": @system.abilities.int.proficient }, + { "pdf": "wis-prof", "foundry": @system.abilities.wis.proficient }, + { "pdf": "cha-prof", "foundry": @system.abilities.cha.proficient }, + { "pdf": "ProfBonus", "foundry": @system.attributes.prof }, + { "pdf": "AC", "foundry": @system.attributes.ac.value }, + { "pdf": "initiative", "foundry": @system.attributes.init.total }, + { "pdf": "HPMax", "foundry": @system.attributes.hp.max }, + { "pdf": "HPCurrent", "foundry": @system.attributes.hp.value }, + { "pdf": "Speed", "foundry": (function() { + const mo = actor.system.attributes.movement; + const mt = Object.entries(game.dnd5e.config.movementTypes).map(e => e[0]); + const ma = Object.entries(mo).filter(e => e[1] && mt.includes(e[0])); + if (mo.walk && ma?.length === 1) { + return `${ma[0][1]}${mo.units}${mo.hover ? "\n(hover)" : ""}`; + } else { + return ma.map(m => `${m[0].substring(0,2)}:${m[1]}${mo.units}`).join('\n').concat(mo.hover ? "\n(hover)" : ""); + } + })() + }, + { "pdf": "features", "foundry": @items.filter(i => ["feat", "trait"].includes(i.type)).slice(0, 16).map(i => `${i.name} - ${i.system.source}: \n${((h) => { + const d = document.createElement("div"); + d.innerHTML = h; + return d.textContent || d.innerText || ""; + })(i.system.description.value.substring(0,599))}${(i.system.description.value.length>600)?'...':''}\n`).join("\n") + }, + { "pdf": "Wpn1 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[0]?.name || "" }, + { "pdf": "Wpn1 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[0]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn1 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[0]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn2 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[1]?.name || "" }, + { "pdf": "Wpn2 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[1]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn2 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[1]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn3 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[2]?.name || "" }, + { "pdf": "Wpn3 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[2]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn3 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[2]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn4 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[3]?.name || "" }, + { "pdf": "Wpn4 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[3]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn4 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[3]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn5 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[4]?.name || "" }, + { "pdf": "Wpn5 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[4]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn5 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[4]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn6 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[5]?.name || "" }, + { "pdf": "Wpn6 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[5]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn6 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[5]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Wpn7 Name", "foundry": @items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[6]?.name || "" }, + { "pdf": "Wpn7 AtkBonus", "foundry": (function() { + const theWeapon = actor.items.filter(i => i.type === 'weapon' && i.system.equipped && i.hasAttack && i.hasDamage)[6]; + theWeapon?.prepareFinalAttributes(); + return theWeapon?.labels?.toHit?.replace(/^\+ $/,"0") || "" + })() + }, + { "pdf": "Wpn7 Damage", "foundry": (function() { + const dda = Array.from(actor.itemTypes.weapon.filter(i => i.system.equipped && i.hasAttack && i.hasDamage))?.[6]?.labels.derivedDamage; + return !dda ? "" : dda.map(dd => `${dd.formula || ""} ${game.dnd5e.config.damageTypes[dd.damageType]}`).join('\n'); + })() + }, + { "pdf": "Skills", "foundry": (function() { + let skill_text = ""; + Object.keys(actor.system.skills).forEach(key => { + let row = game.dnd5e.config.skills[key].label + ": " + actor.system.skills[key].mod; + skill_text += row + "\n"; + }); + return skill_text; + })() + }, + { "pdf": "PersonalityTraits", "foundry": (function(h) { + const d = document.createElement("div"); + d.innerHTML = h; + return d.textContent || d.innerText || ""; + })(@system.details.trait) + }, + { "pdf": "Ideals", "foundry": (function(h) { + const d = document.createElement("div"); + d.innerHTML = h; + return d.textContent || d.innerText || ""; + })(@system.details.ideal) + }, + { "pdf": "Bonds", "foundry": (function(h) { + const d = document.createElement("div"); + d.innerHTML = h; + return d.textContent || d.innerText || ""; + })(@system.details.bond) + }, + { "pdf": "HD", "foundry": @system.attributes.hp.formula }, + { "pdf": "Flaws", "foundry": (function(h) { + const d = document.createElement("div"); + d.innerHTML = h; + return d.textContent || d.innerText || ""; + })(@system.details.flaw) + }, + { "pdf": "equipment", "foundry": @items.filter(i => ['weapon', 'equipment', 'tool'].includes(i.type)).map(i => (i.system.quantity <= 1) ? i.name : `${i.name} (${i.system.quantity})`).join(', ') }, + { "pdf": "CP", "foundry": @system.currency.cp || "" }, + { "pdf": "SP", "foundry": @system.currency.sp || "" }, + { "pdf": "EP", "foundry": @system.currency.ep || "" }, + { "pdf": "GP", "foundry": @system.currency.gp || "" }, + { "pdf": "PP", "foundry": @system.currency.pp || "" }, + { "pdf": "PPerception", "foundry": @system.skills.prc.passive }, + { "pdf": "biography", "foundry": (function(h) { + const d = document.createElement("div"); + d.innerHTML = h.value; + return d.textContent || d.innerText || ""; + })(@system.details.biography) + }, + { "pdf": "senses", "foundry": (function() { + let senses_text = ""; + Object.keys(actor.system.attributes.senses).forEach(key => { + if(key != "units" && actor.system.attributes.senses[key] > 0){ + let row = key + ": " + actor.system.attributes.senses[key] + " " + actor.system.attributes.senses["units"]; + senses_text += row + "\n"; + }; + }); + return senses_text; + })() + }, + { "pdf": "spells", "foundry": (function() { + let spell_text = ""; + actor.items.filter(i => i.type === 'spell').sort((a,b)=>{return (a.system.level - b.system.level || a.name.localeCompare(b.name)) }).map(x => {x.name = x.name + ((typeof x.flags['items-with-spells-5e'] !== 'undefined') ? '[' +fromUuidSync(x.flags['items-with-spells-5e']['parent-item']).name + ']' : '');return x} ).forEach(object => { + let row = object.system.level + " - " + object.name; + spell_text += row + "\n"; + }); + + return spell_text; + })() + }, + + { "pdf": "", "foundry": "" } +] diff --git a/pdf/npc sheet 5e.pdf b/pdf/npc sheet 5e.pdf new file mode 100644 index 0000000000000000000000000000000000000000..268815566225b2f471aff07429a829e558ef117f GIT binary patch literal 61367 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 literal 0 HcmV?d00001 diff --git a/scripts/pdfsheet.js b/scripts/pdfsheet.js index 259a283..4651306 100644 --- a/scripts/pdfsheet.js +++ b/scripts/pdfsheet.js @@ -11,6 +11,15 @@ Hooks.on("init", () => { default: "[]", }); + game.settings.register(Pdfconfig.ID, "mapping-npc", { + name: "pdfsheet.settings.mapping-npc.Name", + hint: "pdfsheet.settings.mapping-npc.Hint", + scope: "world", + config: true, + type: String, + default: "[]", + }); + if (game.version && isNewerVersion(game.version, "9.230")) { game.keybindings.register(Pdfconfig.ID, "showConfig", { name: "Show Config", @@ -35,10 +44,15 @@ Hooks.on("renderSettingsConfig", (app, html) => { // Get the old text box const oldTextBox = html[0].querySelector("[name='pdf-sheet.mapping']"); + // NPC part (just duplicate the previous fields) + let editorNPC, newTextBoxNPC; + + // Get the old text box + const oldTextBoxNPC = html[0].querySelector("[name='pdf-sheet.mapping-npc']"); + // If Ace Library is enabled use an Ace Editor if (game.modules.get("acelib")?.active) { /* global ace */ - // Create an editor newTextBox = document.createElement("div"); editor = ace.edit(newTextBox); @@ -60,12 +74,37 @@ Hooks.on("renderSettingsConfig", (app, html) => { "changeAnnotation", debounce(() => editor.getSession().setAnnotations(), 1) ); + newTextBoxNPC = document.createElement("div"); + editorNPC = ace.edit(newTextBoxNPC); + + // Set to the default options + editorNPC.setOptions(ace.userSettings); + + // Set to JavaScript mode + editorNPC.session.setMode("ace/mode/javascript"); + + // Copy the value from the old textbox into the Ace Editor + editorNPC.setValue(oldTextBoxNPC.value); + + // After a short wait (to make sure the editor is loaded), beautify the editor contents + setTimeout(() => editorNPC.execCommand("beautify"), 500); + + // Hide annotations + editorNPC.getSession().on( + "changeAnnotation", + debounce(() => editorNPC.getSession().setAnnotations(), 1) + ); } else { // Otherwise create new textarea newTextBox = document.createElement("textarea"); // Copy the value from the old textbox into the new one newTextBox.value = oldTextBox.value; + // Otherwise create new textarea NPC + newTextBoxNPC = document.createElement("textarea"); + + // Copy the value from the old textbox into the new one + newTextBoxNPC.value = oldTextBoxNPC.value; } // Don't show the old textbox @@ -80,18 +119,38 @@ Hooks.on("renderSettingsConfig", (app, html) => { // Insert the new textbox right after the old one oldTextBox.after(newTextBox); + // Don't show the old textbox NPC + oldTextBoxNPC.style.display = "none"; + + // Give the editor some height + newTextBoxNPC.style.height = "20em"; + + // Make the editor take up the full width + oldTextBoxNPC.parentElement.style.flex = "100%"; + + // Insert the new textbox right after the old one + oldTextBoxNPC.after(newTextBoxNPC); + if (game.modules.get("acelib")?.active) { // Update whenever the ace editor changes editor.on("change", () => { // Copy the value from the ace editor to the old textbox oldTextBox.value = editor.getValue(); }); + editorNPC.on("change", () => { + // Copy the value from the ace editor to the old textbox + oldTextBoxNPC.value = editorNPC.getValue(); + }); } else { // Update whenever the new textbox changes newTextBox.addEventListener("change", () => { // Copy the value from the new textbox to the old one oldTextBox.value = newTextBox.value; }); + newTextBoxNPC.addEventListener("change", () => { + // Copy the value from the new textbox to the old one + oldTextBoxNPC.value = newTextBoxNPC.value; + }); } // Create mapping select menu @@ -116,6 +175,28 @@ Hooks.on("renderSettingsConfig", (app, html) => { }); }); + // Create mapping select menu NPC + const mappingSelectNPC = document.createElement("select"); + mappingSelectNPC.style.margin = "10px 0"; + oldTextBoxNPC.parentNode.before(mappingSelectNPC); + + // Browse and get list of included mapping files + FilePicker.browse("data", "modules/pdf-sheet/mappings", { extensions: [".mapping"] }).then(results => { + // Add the default option first + results.files.unshift(""); + + // Add options for each included mapping + results.files.forEach(name => { + // Create the option + const option = document.createElement("option"); + mappingSelectNPC.append(option); + + // Add just the name of the system as the text + name = name.split("/").at(-1).replace(".mapping", ""); + option.innerHTML = name; + }); + }); + // Resize the Settings Config App app.setPosition(); @@ -138,13 +219,34 @@ Hooks.on("renderSettingsConfig", (app, html) => { newTextBox.value = mapping; } }); + mappingSelectNPC.addEventListener("change", async () => { + // Fetch selected mapping if not empty + const mapping = mappingSelectNPC.value + ? await fetch(getRoute(`/modules/pdf-sheet/mappings/${mappingSelectNPC.value}.mapping`)).then(response => + response.text() + ) + : ""; + + // Copy the mapping to the old text box + oldTextBoxNPC.value = mapping; + if (game.modules.get("acelib")?.active) { + // Copy the mapping to the ace editor + editorNPC.setValue(mapping); + } else { + // Copy the mapping to the new textbox + newTextBoxNPC.value = mapping; + } + }); } }); // Add button to Actor Sheet for opening app Hooks.on("getActorSheetHeaderButtons", (sheet, buttons) => { + console.log("check the sheet") + console.log(sheet) + console.log(sheet.actor) // If this is not a player character sheet, return without adding the button - if (!["character", "PC", "Player"].includes(sheet.actor.type ?? sheet.actor.data.type)) return; + if (!["character", "PC", "Player", "npc"].includes(sheet.actor.type ?? sheet.actor.data.type)) return; buttons.unshift({ label: "Export to PDF", @@ -237,11 +339,22 @@ class Pdfconfig extends FormApplication { console.log("PDF fields:", pdfFields); // Get mapping from settings - let mapping = game.settings.get(Pdfconfig.ID, "mapping"); + let mapping = "" + + if (["character", "PC", "Player"].includes(actor.type ?? actor.data.type)) { + console.log("got mapping for PC") + mapping = game.settings.get(Pdfconfig.ID, "mapping"); + } + if (["npc"].includes(actor.type ?? actor.data.type)) { + console.log("got mapping for NPC") + mapping = game.settings.get(Pdfconfig.ID, "mapping-npc"); + } + // Parse dynamic keys mapping = mapping.replaceAll("@", game.release.generation > 10 ? "actor." : "actor.data."); + // Log un-evaluated mapping console.log("Raw mapping:", mapping);