repackages xml-import into class and adds configuration dialog to it

pull/61/head
macniel 2025-10-21 11:02:19 +02:00
parent 53c5c7b53a
commit 1c9d4a1f1f
7 changed files with 740 additions and 523 deletions

View File

@ -27,6 +27,8 @@ import {CultureDataModel} from "./module/data/culture.mjs";
import {CultureSheet} from "./module/sheets/CultureSheet.mjs"; import {CultureSheet} from "./module/sheets/CultureSheet.mjs";
import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs"; import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs";
import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs"; import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs";
import {XmlImport} from "./module/xml-import/xml-import.mjs";
import {XmlImportDialog} from "./module/dialog/xmlImportDialog.mjs";
async function preloadHandlebarsTemplates() { async function preloadHandlebarsTemplates() {
return foundry.applications.handlebars.loadTemplates([ return foundry.applications.handlebars.loadTemplates([
@ -219,6 +221,20 @@ Hooks.once("ready", async function () {
}); });
}); });
Hooks.on("getActorContextOptions", (application, menuItems) => {
menuItems.push({
name: "Import from XML",
icon: '<i class="fas fa-file"></i>',
callback: (li) => {
const actorId = li.getAttribute("data-entry-id")
const actor = game.actors.get(actorId)
//actor.import()
new XmlImportDialog(actor).render(true)
}
})
})
async function createTalentMacro(data, slot) { async function createTalentMacro(data, slot) {
console.log(data, slot) console.log(data, slot)
if (data.type !== "Item") return; if (data.type !== "Item") return;

View File

@ -0,0 +1,88 @@
import {XmlImport} from "../xml-import/xml-import.mjs";
const {ApplicationV2, HandlebarsApplicationMixin} = foundry.applications.api
export class XmlImportDialog extends HandlebarsApplicationMixin(ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ['dsa41', 'dialog', 'xmlimport'],
tag: "form",
position: {
width: 320,
height: 478
},
window: {
resizable: false,
},
form: {
submitOnChange: false,
closeOnSubmit: true,
handler: XmlImportDialog.#onSubmitForm
},
}
static PARTS = {
form: {
template: 'systems/DSA_4-1/templates/dialog/xml-import.hbs',
}
}
/**
* @type {Actor}
* @private
*/
_actor = null
/**
* @type {XmlImport}
* @private
*/
_xmlImport = null
constructor(actor) {
super();
this._actor = actor
this._xmlImport = new XmlImport()
}
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
console.log("lets go", formData.object)
const options = {}
formData.object.importOption.forEach(p => {
options[p] = true
})
const file = form.querySelector('input[type="file"]').files[0]
try {
form.querySelector('button[type="submit"]').setAttribute("disabled", true)
await this._xmlImport.importCharacter(this._actor._id, file, options)
form.querySelector('button[type="submit"]').setAttribute("disabled", false)
return true
} catch (e) {
console.error(e)
form.querySelector('button[type="submit"]').setAttribute("disabled", false)
return false
}
}
_configureRenderOptions(options) {
super._configureRenderOptions(options)
options.window.title = `${this._actor.name} importieren`
return options
}
async _prepareContext(options) {
const context = await super._prepareContext(options)
context.options = XmlImport.getOptions()
return context
}
_onRender(context, options) {
}
}

View File

@ -1,10 +1,10 @@
import {importCharacter} from "../xml-import/xml-import.mjs";
import {LiturgyData} from "../data/miracle/liturgydata.mjs"; import {LiturgyData} from "../data/miracle/liturgydata.mjs";
import {Zonenruestung, Zonenwunde, Wunde} from "../data/Trefferzone.js"; import {Zonenruestung, Zonenwunde, Wunde} from "../data/Trefferzone.js";
import {PlayerCharacterDataModel} from "../data/character.mjs"; import {PlayerCharacterDataModel} from "../data/character.mjs";
export class Character extends Actor { export class Character extends Actor {
/**
import() { import() {
let input = document.createElement('input') let input = document.createElement('input')
input.type = 'file' input.type = 'file'
@ -13,7 +13,7 @@ export class Character extends Actor {
importCharacter(this.id, e.target.files[0]) importCharacter(this.id, e.target.files[0])
} }
input.click() input.click()
} }*/
/** /**
* @override * @override

View File

@ -4,7 +4,8 @@ import {Profession} from "../documents/profession.mjs";
import {Culture} from "../documents/culture.mjs"; import {Culture} from "../documents/culture.mjs";
import {Species} from "../documents/species.mjs"; import {Species} from "../documents/species.mjs";
let months = [ export class XmlImport {
#months = [
"Praios", "Praios",
"Rondra", "Rondra",
"Efferd", "Efferd",
@ -22,9 +23,11 @@ let months = [
/** /**
* @typedef ImportOptions * @typedef ImportOptions
* @property {Boolean} skipMeta
* @property {Boolean} skipSpecies * @property {Boolean} skipSpecies
* @property {Boolean} skipCulture * @property {Boolean} skipCulture
* @property {Boolean} skipProfessions * @property {Boolean} skipProfessions
* @property {Boolean} skipAttributes
* @property {Boolean} skipAdvantages * @property {Boolean} skipAdvantages
* @property {Boolean} skipSpecialAbilities * @property {Boolean} skipSpecialAbilities
* @property {Boolean} skipEquipment * @property {Boolean} skipEquipment
@ -33,25 +36,44 @@ let months = [
* @property {Boolean} skipSkills * @property {Boolean} skipSkills
**/ **/
static getOptions() {
return {
skipMeta: "Meta",
skipSpecies: "Rasse",
skipCulture: "Kultur",
skipProfessions: "Professionen",
skipAttribution: "Eigenschaften",
skipAdvantages: "Vor und Nachteile",
skipSpecialAbilities: "Sonderfertigkeiten",
skipEquipment: "Inventar",
skipSpells: "Zauber",
skipLiturgies: "Liturgien",
skipSkills: "Talente"
}
}
/** /**
* Imports a character from a file created in the tool Helden-Software * Imports a character from a file created in the tool Helden-Software
* @param actorId the actor-id of the character * @param actorId the actor-id of the character
* @param file the file from which the character should be imported * @param file the file from which the character should be imported
* @param {ImportOptions?} options the set of item types the import should skip * @param {ImportOptions?} options the set of item types the import should skip
*/ */
export async function importCharacter(actorId, file, options = undefined) { async importCharacter(actorId, file, options = undefined) {
let actor = game.actors.get(actorId) let actor = game.actors.get(actorId)
let xmlString = await parseFileToString(file) console.log("starting import with following options", options)
let xmlString = await this.#parseFileToString(file)
let domParser = new DOMParser() let domParser = new DOMParser()
let dom = domParser.parseFromString(xmlString, 'application/xml') let dom = domParser.parseFromString(xmlString, 'application/xml')
let rawJson = getJsonFromXML(dom) let rawJson = this.#getJsonFromXML(dom)
if (!options) { if (!options) {
options = { options = {
skipMeta: false,
skipSpecies: false, skipSpecies: false,
skipCulture: false, skipCulture: false,
skipProfessions: false, skipProfessions: false,
skipAttributes: false,
skipAdvantages: false, skipAdvantages: false,
skipSpecialAbilities: false, skipSpecialAbilities: false,
skipEquipment: false, skipEquipment: false,
@ -61,17 +83,18 @@ export async function importCharacter(actorId, file, options = undefined) {
} }
} }
let characterJson = mapRawJson(actor, rawJson, options) let characterJson = this.#mapRawJson(actor, rawJson, options)
actor.update(characterJson) actor.update(characterJson)
} }
/** /**
* *
* @param dom the XML-Dom from which the json should be extracted * @param dom the XML-Dom from which the json should be extracted
* @returns {{}} the json parsed from the xml * @returns {{}} the json parsed from the xml
*/ */
function getJsonFromXML(dom) { #getJsonFromXML(dom) {
let children = [...dom.children]; let children = [...dom.children];
// initializing object to be returned. // initializing object to be returned.
@ -91,12 +114,12 @@ function getJsonFromXML(dom) {
// if child is array, save the values as array, else as strings. // if child is array, save the values as array, else as strings.
if (childIsArray) { if (childIsArray) {
if (jsonResult[child.nodeName] === undefined) { if (jsonResult[child.nodeName] === undefined) {
jsonResult[child.nodeName] = [getJsonFromXML(child)]; jsonResult[child.nodeName] = [this.#getJsonFromXML(child)];
} else { } else {
jsonResult[child.nodeName].push(getJsonFromXML(child)); jsonResult[child.nodeName].push(this.#getJsonFromXML(child));
} }
} else { } else {
jsonResult[child.nodeName] = getJsonFromXML(child); jsonResult[child.nodeName] = this.#getJsonFromXML(child);
} }
} }
} }
@ -109,7 +132,7 @@ function getJsonFromXML(dom) {
* @param file the file with the desired content * @param file the file with the desired content
* @returns {Promise<String>} a promise that returns the string contents of the file * @returns {Promise<String>} a promise that returns the string contents of the file
*/ */
async function parseFileToString(file) { async #parseFileToString(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let reader = new FileReader() let reader = new FileReader()
reader.readAsText(file, "utf-8") reader.readAsText(file, "utf-8")
@ -122,21 +145,196 @@ async function parseFileToString(file) {
}) })
} }
/** /**
*Calculates a Birthdate String in the Calendar of Bosparans Fall *Calculates a Birthdate String in the Calendar of Bosparans Fall
* @param json json with the day, the month and the year of the birthday * @param json json with the day, the month and the year of the birthday
* @returns {string} a string in the format of "DD.MMMM.YYYY BF" * @returns {string} a string in the format of "DD.MMMM.YYYY BF"
*/ */
function calculateBirthdate(json) { #calculateBirthdate(json) {
let day = json.gbtag let day = json.gbtag
let month = months[parseInt(json.gbmonat) - 1] let month = this.#months[parseInt(json.gbmonat) - 1]
let year = json.gbjahr let year = json.gbjahr
return `${day}. ${month} ${year} BF` return `${day}. ${month} ${year} BF`
} }
async function addSkillFromCompendiumByNameToActor(talentName, taw, actor, combatStatistics, attributes) { /**
* parses a json into a fitting character-json
* @param {Character} actor
* @param rawJson the json parsed from the Helden-Software XML
* @param {ImportOptions} options
* @returns {{}} a json representation of the character
*/
#mapRawJson(actor, rawJson, options) {
let json = {}
let held = rawJson.helden.held;
json.name = held.name
json.meta = {}
if (!options.skipSpecies) this.#mapSpezies(actor, held.basis.rasse) // as string includes the demonymized form
if (!options.skipCulture) this.#mapKultur(actor, held.basis.kultur) // as string includes the demonymized form
if (!options.skipProfessions) this.#mapProfessions(actor, held.basis.ausbildungen.ausbildung)
if (!options.skipMeta) {
json.meta.geschlecht = held.basis.geschlecht.name
json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe
json.meta.groesse = held.basis.rasse.groesse.value
json.meta.augenfarbe = held.basis.rasse.aussehen.augenfarbe
json.meta.geburtstag = this.#calculateBirthdate(held.basis.rasse.aussehen)
json.meta.alter = held.basis.rasse.aussehen.alter
json.meta.gewicht = held.basis.rasse.groesse.gewicht
json.meta.aussehen = [
held.basis.rasse.aussehen.aussehentext0,
held.basis.rasse.aussehen.aussehentext1,
held.basis.rasse.aussehen.aussehentext2,
held.basis.rasse.aussehen.aussehentext3].join('\n')
json.meta.familie = [
held.basis.rasse.aussehen.familietext0,
held.basis.rasse.aussehen.familietext1,
held.basis.rasse.aussehen.familietext2,
held.basis.rasse.aussehen.familietext3,
held.basis.rasse.aussehen.familietext4,
held.basis.rasse.aussehen.familietext5].join('\n')
json.meta.titel = held.basis.rasse.aussehen.titel
json.meta.stand = held.basis.rasse.aussehen.stand
}
let attributes = held.eigenschaften.eigenschaft
json.attribute = {}
if (!options.skipAttributes) {
if (held.basis.gilde) {
json.attribute.gilde = held.basis.gilde.name
}
json.attribute.mu = this.#getAttributeJson(attributes, "Mut")
json.attribute.kl = this.#getAttributeJson(attributes, "Klugheit")
json.attribute.in = this.#getAttributeJson(attributes, "Intuition")
json.attribute.ch = this.#getAttributeJson(attributes, "Charisma")
json.attribute.ff = this.#getAttributeJson(attributes, "Fingerfertigkeit")
json.attribute.ge = this.#getAttributeJson(attributes, "Gewandtheit")
json.attribute.ko = this.#getAttributeJson(attributes, "Konstitution")
json.attribute.kk = this.#getAttributeJson(attributes, "Körperkraft")
json.mr = {
mod: this.#filterAttribute(attributes, "Magieresistenz").mod
}
json.lep = {
mod: this.#filterAttribute(attributes, "Lebensenergie").mod
}
json.aup = {
mod: this.#filterAttribute(attributes, "Ausdauer").mod
}
json.asp = {
mod: this.#filterAttribute(attributes, "Astralenergie").mod
}
json.kap = {
mod: this.#filterAttribute(attributes, "Karmaenergie").mod
}
let attribute = this.#filterAttribute(attributes, "ini")
json.ini = {
mod: attribute.mod,
aktuell: attribute.value
}
json.attribute.so = this.#getAttributeJson(attributes, "Sozialstatus")
}
if (!options.skipAdvantages) this.#mapAdvantages(actor, held)
let specialAbilities = []
let liturgies = []
for (let specialAbility in held.sf.sonderfertigkeit) {
specialAbility = held.sf.sonderfertigkeit[specialAbility]
if (specialAbility.name.startsWith("Liturgie:")) {
if (!options.skipLiturgies) {
liturgies.push({
name: specialAbility.name.replace("Liturgie:", "").trim(),
})
}
} else {
if (!options.skipSpecialAbilities) {
let specialAbilityJson = {
name: specialAbility.name,
auswahlen: []
}
let fields = Object.keys(specialAbility)
if (fields.length > 1) {
for (let field in fields) {
field = fields[field]
if (field !== "name") {
let choices = specialAbility[field]
if (choices.hasOwnProperty("name")) {
specialAbilityJson.auswahlen.push(choices.name)
} else {
for (let choice in choices.wahl) {
choice = choices.wahl[choice]
specialAbilityJson.auswahlen.push(choice.value)
}
}
}
}
}
specialAbilities.push(specialAbilityJson)
}
}
}
json.sonderfertigkeiten = specialAbilities
json.liturgien = liturgies
let combatValues = []
for (let combatValue in held.kampf.kampfwerte) {
combatValue = held.kampf.kampfwerte[combatValue]
combatValues.push({
name: combatValue.name,
at: combatValue.attacke.value,
pa: combatValue.parade.value,
})
}
json.kampfwerte = combatValues
if (!options.skipSkills) this.#mapSkills(actor, held, combatValues)
if (!options.skipSpells) this.#mapSpells(actor, held)
if (!options.skipLiturgies) this.#mapLiturgies(actor, liturgies)
let notes = []
for (let note in held.kommentare) {
note = held.kommentare[note]
if (note.hasOwnProperty("key")) {
notes.push({
key: note.key,
notiz: note.kommentar,
})
}
}
json.notizen = notes
return {
name: held.name,
system: json,
}
}
/**
* @param attributes an array with the attributes
* @param name the name of the chosen attribute
* @returns {{}} a representation of the chosen Attribute
*/
#getAttributeJson(attributes, name) {
let attribute = this.#filterAttribute(attributes, name)
return {
start: parseInt(attribute.startwert),
aktuell: parseInt(attribute.value),
mod: parseInt(attribute.mod),
}
}
/**
* filters a given attribute array based on the name of an attribute
* @param attributes the attribute array
* @param name the name of the desired attribute
* @returns {{}} the json of the desired attribute
*/
#filterAttribute(attributes, name) {
return attributes.filter(attribute => attribute.name === name)[0]
}
async #addSkillFromCompendiumByNameToActor(talentName, taw, actor, combatStatistics, attributes) {
const compendiumOfSkills = game.packs.get('DSA_4-1.talente'); const compendiumOfSkills = game.packs.get('DSA_4-1.talente');
const talentId = compendiumOfSkills.index.find(skill => skill.name === talentName) const talentId = compendiumOfSkills.index.find(skill => skill.name === talentName)
if (talentId) { if (talentId) {
@ -166,7 +364,7 @@ async function addSkillFromCompendiumByNameToActor(talentName, taw, actor, comba
} }
} }
async function addAdvantageFromCompendiumByNameToActor(advantageName, advantageValue, actor) { async #addAdvantageFromCompendiumByNameToActor(advantageName, advantageValue, actor) {
const compendiumOfAdvantages = game.packs.get('DSA_4-1.Advantage'); const compendiumOfAdvantages = game.packs.get('DSA_4-1.Advantage');
const advantageId = compendiumOfAdvantages.index.find(skill => skill.name === advantageName) const advantageId = compendiumOfAdvantages.index.find(skill => skill.name === advantageName)
if (advantageId) { if (advantageId) {
@ -182,8 +380,7 @@ async function addAdvantageFromCompendiumByNameToActor(advantageName, advantageV
} }
} }
async function addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) { async #addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) {
const compendiumOfSpells = game.packs.get('DSA_4-1.spells'); const compendiumOfSpells = game.packs.get('DSA_4-1.spells');
const SCREAMING_NAME = spellName.toUpperCase() const SCREAMING_NAME = spellName.toUpperCase()
const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME) const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME)
@ -200,7 +397,7 @@ async function addSpellsFromCompendiumByNameToActor(spellName, zfw, representati
} }
} }
async function addLiturgiesFromCompendiumByNameToActor(liturgyName, actor) { async #addLiturgiesFromCompendiumByNameToActor(liturgyName, actor) {
const compendiumOfLiturgies = game.packs.get('DSA_4-1.liturgien'); const compendiumOfLiturgies = game.packs.get('DSA_4-1.liturgien');
const liturgyId = compendiumOfLiturgies.index.find(liturgy => { const liturgyId = compendiumOfLiturgies.index.find(liturgy => {
return liturgy.name === LiturgyData.lookupAlias(liturgyName.split(" (")[0]) return liturgy.name === LiturgyData.lookupAlias(liturgyName.split(" (")[0])
@ -217,7 +414,7 @@ async function addLiturgiesFromCompendiumByNameToActor(liturgyName, actor) {
} }
} }
function mapSkills(actor, held, kampfwerte) { #mapSkills(actor, held, kampfwerte) {
if (actor.itemTypes["Skill"].length > 0) { if (actor.itemTypes["Skill"].length > 0) {
actor.itemTypes["Skill"].forEach(s => { actor.itemTypes["Skill"].forEach(s => {
actor.items.get(s._id).delete() actor.items.get(s._id).delete()
@ -248,12 +445,12 @@ function mapSkills(actor, held, kampfwerte) {
} else { } else {
// proceed // proceed
const eigenschaften = held.eigenschaften.eigenschaft const eigenschaften = held.eigenschaften.eigenschaft
addSkillFromCompendiumByNameToActor(talent.name, talent.value, actor, kampfwerte, eigenschaften) this.#addSkillFromCompendiumByNameToActor(talent.name, talent.value, actor, kampfwerte, eigenschaften)
} }
} }
} }
function mapAdvantages(actor, held) { #mapAdvantages(actor, held) {
if (actor.itemTypes["Advantage"].length > 0) { if (actor.itemTypes["Advantage"].length > 0) {
actor.itemTypes["Advantage"].forEach(a => { actor.itemTypes["Advantage"].forEach(a => {
actor.items.get(a._id).delete() actor.items.get(a._id).delete()
@ -261,11 +458,11 @@ function mapAdvantages(actor, held) {
} }
for (let advantage in held.vt.vorteil) { for (let advantage in held.vt.vorteil) {
advantage = held.vt.vorteil[advantage] advantage = held.vt.vorteil[advantage]
addAdvantageFromCompendiumByNameToActor(advantage.name, advantage.value, actor) this.#addAdvantageFromCompendiumByNameToActor(advantage.name, advantage.value, actor)
} }
} }
function mapSpells(actor, held) { #mapSpells(actor, held) {
if (actor.itemTypes["Spell"].length > 0) { if (actor.itemTypes["Spell"].length > 0) {
actor.itemTypes["Spell"].forEach(s => { actor.itemTypes["Spell"].forEach(s => {
actor.items.get(s._id).delete() actor.items.get(s._id).delete()
@ -273,11 +470,11 @@ function mapSpells(actor, held) {
} }
for (let spell in held.zauberliste.zauber) { for (let spell in held.zauberliste.zauber) {
spell = held.zauberliste.zauber[spell] spell = held.zauberliste.zauber[spell]
addSpellsFromCompendiumByNameToActor(spell.name, spell.value, spell.repraesentation, spell.hauszauber === "true", actor) this.#addSpellsFromCompendiumByNameToActor(spell.name, spell.value, spell.repraesentation, spell.hauszauber === "true", actor)
} }
} }
function mapLiturgies(actor, liturgies) { #mapLiturgies(actor, liturgies) {
if (actor.itemTypes["Liturgy"].length > 0) { if (actor.itemTypes["Liturgy"].length > 0) {
actor.itemTypes["Liturgy"].forEach(l => { actor.itemTypes["Liturgy"].forEach(l => {
actor.items.get(l._id).delete() actor.items.get(l._id).delete()
@ -285,11 +482,11 @@ function mapLiturgies(actor, liturgies) {
} }
for (let liturgy in liturgies) { for (let liturgy in liturgies) {
liturgy = liturgies[liturgy] liturgy = liturgies[liturgy]
addLiturgiesFromCompendiumByNameToActor(liturgy.name, actor) this.#addLiturgiesFromCompendiumByNameToActor(liturgy.name, actor)
} }
} }
async function mapProfessions(actor, professions) { async #mapProfessions(actor, professions) {
if (actor.itemTypes["Profession"].length > 0) { if (actor.itemTypes["Profession"].length > 0) {
actor.itemTypes["Profession"].forEach(p => { actor.itemTypes["Profession"].forEach(p => {
actor.items.get(p._id).delete() actor.items.get(p._id).delete()
@ -311,10 +508,9 @@ async function mapProfessions(actor, professions) {
}) })
]) ])
}) })
// actor.update({"system.meta.professions": professions})
} }
async function mapSpezies(actor, spezies) { async #mapSpezies(actor, spezies) {
if (actor.itemTypes["Species"].length > 0) { if (actor.itemTypes["Species"].length > 0) {
actor.itemTypes["Species"].forEach(s => { actor.itemTypes["Species"].forEach(s => {
actor.items.get(s._id).delete() actor.items.get(s._id).delete()
@ -346,7 +542,7 @@ async function mapSpezies(actor, spezies) {
} }
async function mapKultur(actor, kultur) { async #mapKultur(actor, kultur) {
if (actor.itemTypes["Culture"].length > 0) { if (actor.itemTypes["Culture"].length > 0) {
actor.itemTypes["Culture"].forEach(c => { actor.itemTypes["Culture"].forEach(c => {
actor.items.get(c._id).delete() actor.items.get(c._id).delete()
@ -379,180 +575,4 @@ async function mapKultur(actor, kultur) {
} }
/**
* parses a json into a fitting character-json
* @param {Character} actor
* @param rawJson the json parsed from the Helden-Software XML
* @param {ImportOptions} options
* @returns {{}} a json representation of the character
*/
function mapRawJson(actor, rawJson, options) {
let json = {}
let held = rawJson.helden.held;
json.name = held.name
json.meta = {}
if (!options.skipSpecies) mapSpezies(actor, held.basis.rasse) // as string includes the demonymized form
if (!options.skipCulture) mapKultur(actor, held.basis.kultur) // as string includes the demonymized form
if (!options.skipProfessions) mapProfessions(actor, held.basis.ausbildungen.ausbildung)
json.meta.geschlecht = held.basis.geschlecht.name
json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe
json.meta.groesse = held.basis.rasse.groesse.value
json.meta.augenfarbe = held.basis.rasse.aussehen.augenfarbe
json.meta.geburtstag = calculateBirthdate(held.basis.rasse.aussehen)
json.meta.alter = held.basis.rasse.aussehen.alter
json.meta.gewicht = held.basis.rasse.groesse.gewicht
json.meta.aussehen = [
held.basis.rasse.aussehen.aussehentext0,
held.basis.rasse.aussehen.aussehentext1,
held.basis.rasse.aussehen.aussehentext2,
held.basis.rasse.aussehen.aussehentext3].join('\n')
json.meta.familie = [
held.basis.rasse.aussehen.familietext0,
held.basis.rasse.aussehen.familietext1,
held.basis.rasse.aussehen.familietext2,
held.basis.rasse.aussehen.familietext3,
held.basis.rasse.aussehen.familietext4,
held.basis.rasse.aussehen.familietext5].join('\n')
json.meta.titel = held.basis.rasse.aussehen.titel
json.meta.stand = held.basis.rasse.aussehen.stand
let attributes = held.eigenschaften.eigenschaft
json.attribute = {}
if (held.basis.gilde) {
json.attribute.gilde = held.basis.gilde.name
} }
json.attribute.mu = getAttributeJson(attributes, "Mut")
json.attribute.kl = getAttributeJson(attributes, "Klugheit")
json.attribute.in = getAttributeJson(attributes, "Intuition")
json.attribute.ch = getAttributeJson(attributes, "Charisma")
json.attribute.ff = getAttributeJson(attributes, "Fingerfertigkeit")
json.attribute.ge = getAttributeJson(attributes, "Gewandtheit")
json.attribute.ko = getAttributeJson(attributes, "Konstitution")
json.attribute.kk = getAttributeJson(attributes, "Körperkraft")
json.mr = {
mod: filterAttribute(attributes, "Magieresistenz").mod
}
json.lep = {
mod: filterAttribute(attributes, "Lebensenergie").mod
}
json.aup = {
mod: filterAttribute(attributes, "Ausdauer").mod
}
json.asp = {
mod: filterAttribute(attributes, "Astralenergie").mod
}
json.kap = {
mod: filterAttribute(attributes, "Karmaenergie").mod
}
let attribute = filterAttribute(attributes, "Karmaenergie")
attribute = filterAttribute(attributes, "ini")
json.ini = {
mod: attribute.mod,
aktuell: attribute.value
}
json.attribute.so = getAttributeJson(attributes, "Sozialstatus")
if (!options.skipAdvantages) mapAdvantages(actor, held)
let specialAbilities = []
let liturgies = []
for (let specialAbility in held.sf.sonderfertigkeit) {
specialAbility = held.sf.sonderfertigkeit[specialAbility]
if (specialAbility.name.startsWith("Liturgie:")) {
liturgies.push({
name: specialAbility.name.replace("Liturgie:", "").trim(),
})
} else {
let specialAbilityJson = {
name: specialAbility.name,
auswahlen: []
}
let fields = Object.keys(specialAbility)
if (fields.length > 1) {
for (let field in fields) {
field = fields[field]
if (field !== "name") {
let choices = specialAbility[field]
if (choices.hasOwnProperty("name")) {
specialAbilityJson.auswahlen.push(choices.name)
} else {
for (let choice in choices.wahl) {
choice = choices.wahl[choice]
specialAbilityJson.auswahlen.push(choice.value)
}
}
}
}
}
specialAbilities.push(specialAbilityJson)
}
}
json.sonderfertigkeiten = specialAbilities
json.liturgien = liturgies
let combatValues = []
for (let combatValue in held.kampf.kampfwerte) {
combatValue = held.kampf.kampfwerte[combatValue]
combatValues.push({
name: combatValue.name,
at: combatValue.attacke.value,
pa: combatValue.parade.value,
})
}
json.kampfwerte = combatValues
if (!options.skipSkills) mapSkills(actor, held, combatValues)
if (!options.skipSpells) mapSpells(actor, held)
if (!options.skipLiturgies) mapLiturgies(actor, liturgies)
let notes = []
for (let note in held.kommentare) {
note = held.kommentare[note]
if (note.hasOwnProperty("key")) {
notes.push({
key: note.key,
notiz: note.kommentar,
})
}
}
json.notizen = notes
return {
name: held.name,
system: json,
}
}
/**
*
* @param attributes an array with the attributes
* @param name the name of the chosen attribute
* @returns {{}} a representation of the chosen Attribute
*/
function getAttributeJson(attributes, name) {
let attribute = filterAttribute(attributes, name)
return {
start: parseInt(attribute.startwert),
aktuell: parseInt(attribute.value),
mod: parseInt(attribute.mod),
}
}
/**
* filters a given attribute array based on the name of an attribute
* @param attributes the attribute array
* @param name the name of the desired attribute
* @returns {{}} the json of the desired attribute
*/
function filterAttribute(attributes, name) {
return attributes.filter(attribute => attribute.name === name)[0]
}
Hooks.on("getActorContextOptions", (application, menuItems) => {
menuItems.push({
name: "Import from XML",
icon: '<i class="fas fa-file"></i>',
callback: (li) => {
const actorId = li.getAttribute("data-entry-id")
const actor = game.actors.get(actorId)
actor.import()
}
})
})

View File

@ -0,0 +1,71 @@
.application.dsa41.dialog.xmlimport {
section.window-content {
section {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 32px 1fr 32px;
gap: 8px 0;
grid-template-areas: "file" "options" "actions";
.file-input {
grid-area: file;
display: flex;
gap: 8px;
label {
flex: 0;
height: 32px;
line-height: 32px;
vertical-align: middle;
width: 80px;
}
input {
flex: 1;
}
}
fieldset {
grid-area: options;
border-left: 0;
border-bottom: 0;
border-right: 0;
legend {
padding: 0 16px;
text-align: center;
}
div {
label {
height: 21px;
input {
line-height: 21px;
height: 21px;
}
span {
line-height: 21px;
height: 21px;
vertical-align: 2px;
}
}
}
}
button {
grid-area: actions;
width: 100%;
height: 32px;
}
}
}
}

View File

@ -23,4 +23,5 @@
@use "organisms/culture-sheet"; @use "organisms/culture-sheet";
@use "organisms/species-sheet"; @use "organisms/species-sheet";
@use "organisms/profession-sheet"; @use "organisms/profession-sheet";
@use "organisms/xml-import-dialog";

View File

@ -0,0 +1,21 @@
<section>
<div class="file-input">
<label for="file"><span>Quelldatei</span></label><input id="file" type="file" name="file" accept=".xml">
</div>
<fieldset>
<legend>Folgendes <strong>nicht</strong> importieren</legend>
{{#each options}}
<div><label><input type="checkbox" name="importOption" value="{{@key}}"><span>{{this}}</span></label>
</div>
{{/each}}
</fieldset>
<button type="submit"><i class="fas fa-upload"></i>Import starten</button>
</section>