diff --git a/src/assets/example-character.xml b/src/assets/example-character.xml index 01738fc7..f636eace 100644 --- a/src/assets/example-character.xml +++ b/src/assets/example-character.xml @@ -1,6 +1,6 @@ - + @@ -13,15 +13,17 @@ - + + string="Akademie der Magischen Rüstung zu Gareth " tarnidentitaet="Depp vom Dienst"> - + @@ -73,6 +75,13 @@ + + + + + + + @@ -90,6 +99,13 @@ + + + + + + + @@ -257,6 +273,59 @@ text="Sonderfertigkeit hinzugefügt" time="1758728180962" version="HS 5.5.3"/> + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -320,8 +389,9 @@ value="6"/> - - + + + @@ -506,6 +576,7 @@ + @@ -542,10 +613,10 @@ - D/lXw741ikWhJ+dIE/eCcUgT5vw= + a1RMsniSGUvFk5vUM6faRb5HF7M= - Yo5RyWxO8N8Z0ReQlPhESaEjbpFUFTANob25mAXlFTH0eCBano63WQ== + IoH2tMVRNhVL5zF5VrhsiYRdosA0GopNsJMf4tFpYVi5yPW6RhGqNQ== diff --git a/src/main.mjs b/src/main.mjs index 3b5a1000..34e2f082 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -1,10 +1,10 @@ -import { PlayerCharacterDataModel } from "./module/data/character.mjs"; +import {PlayerCharacterDataModel} from "./module/data/character.mjs"; import { SkillSheet } from "./module/sheets/skillSheet.mjs"; import { SpellSheet } from "./module/sheets/spellSheet.mjs"; -import { CharacterSheet } from "./module/sheets/characterSheet.mjs"; import { SkillDataModel } from "./module/data/skill.mjs"; import { SpellDataModel } from "./module/data/spell.mjs"; import { Character } from "./module/documents/character.mjs"; +import { CharacterSheet } from "./module/sheets/characterSheet.mjs"; Hooks.once("init", () => { diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index 6351e88b..6fa24d71 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -1,8 +1,5 @@ -import {SkillDataModel} from "./skill.mjs"; -import {SpellDataModel} from "./spell.mjs"; - const { - SchemaField, NumberField, StringField, ArrayField, BooleanField, ForeignDocumentField + SchemaField, NumberField, StringField, ArrayField, ForeignDocumentField } = foundry.data.fields; export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { @@ -13,7 +10,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { meta: new SchemaField({ spezies: new StringField(), kultur: new StringField(), - profession: new StringField(), + professions: new ArrayField(new StringField()), geschlecht: new StringField(), haarfarbe: new StringField(), groesse: new NumberField({ required: true, integer: false }), @@ -21,30 +18,120 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { geburtstag: new StringField(), alter: new NumberField({ required: true, integer: true }), gewicht: new NumberField({ required: true, integer: true }), + aussehen: new ArrayField(new StringField()), + familie: new ArrayField(new StringField()), + titel: new StringField(), + stand: new StringField(), }), attribute: new SchemaField({ - mu: new NumberField({ required: true, integer: true }), - kl: new NumberField({ required: true, integer: true }), - in: new NumberField({ required: true, integer: true }), - ch: new NumberField({ required: true, integer: true }), - ff: new NumberField({ required: true, integer: true }), - ge: new NumberField({ required: true, integer: true }), - ko: new NumberField({ required: true, integer: true }), - kk: new NumberField({ required: true, integer: true }), - mr: new NumberField({ required: true, integer: true }), - lep: new NumberField({ required: true, integer: true }), - aup: new NumberField({ required: true, integer: true }), - asp: new NumberField({ required: false, integer: true }), - kap: new NumberField({ required: false, integer: true }), - at: new NumberField({ required: true, integer: true }), - pa: new NumberField({ required: true, integer: true }), - fk: new NumberField({ required: true, integer: true }), - ini: new NumberField({ required: true, integer: true }), - so: new NumberField({ required: true, integer: true }), + mu: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + kl: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + in: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + ch: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + ff: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + ge: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + ko: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + kk: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + mr: new SchemaField({ + mod: new NumberField({ required: true, integer: true }), + }), + lep: new SchemaField({ + mod: new NumberField({ required: true, integer: true }), + }), + aup: new SchemaField({ + mod: new NumberField({ required: true, integer: true }), + }), + asp: new SchemaField({ + mod: new NumberField({ required: true, integer: true }), + }), + kap: new SchemaField({ + mod: new NumberField({ required: true, integer: true }), + }), + at: new SchemaField({ + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + pa: new SchemaField({ + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + fk: new SchemaField({ + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + ini: new SchemaField({ + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), + so: new SchemaField({ + start: new NumberField({ required: true, integer: true }), + aktuell: new NumberField({ required: true, integer: true }), + mod: new NumberField({ required: true, integer: true }), + }), gilde: new StringField(), }), - talente: new ArrayField ( new ForeignDocumentField(Item) ), - zauber: new ArrayField ( new ForeignDocumentField(Item) ), + vornachteile: new ArrayField(new SchemaField({ + name: new StringField(), + wert: new NumberField({ required: false, integer: true }), + })), + sonderfertigkeiten: new ArrayField(new SchemaField({ + name: new StringField(), + auswahlen: new ArrayField(new StringField()), + })), + + talente: new ArrayField(new SchemaField({ + talent: new ForeignDocumentField(Item), + taw: new NumberField({integer: true, required: true}), + }) + ), + zauber: new ArrayField(new SchemaField({ + talent: new ForeignDocumentField(Item), + zfw: new NumberField({integer: true, required: true}), + })), + liturgien: new ArrayField(new SchemaField({ + name: new StringField(), + })), + kampfwerte: new ArrayField(new SchemaField({ + name: new StringField(), + at: new NumberField({ required: true, integer: true }), + pa: new NumberField({ required: true, integer: true }), + })), + notizen: new ArrayField(new SchemaField({ + key: new StringField(), + notiz: new StringField(), + })), } } @@ -52,4 +139,49 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { super._initialize(options); } + _onCreate(data, options, userId) { + // prepare base talents + const talentsByName = [ + "Athletik", "Klettern", "Körperbeherrschung", "Schleichen", "Schwimmen", "Selbstbeherrschung", "Sich Verstecken", "Singen", "Sinnenschärfe", "Tanzen", "Zechen", + "Menschenkenntnis", "Überreden", + "Fährtensuchen", "Orientierung", "Wildnisleben", + "Götter/Kulte", "Rechnen", "Sagen/Legenden", + "Heilkunde: Wunden", "Holzbearbeitung", "Kochen", "Lederverarbeitung", "Malen/Zeichnen", "Schneidern" + ] + + const talente = [] + + talentsByName.forEach( talentName => { + const talent = game.items.getName(talentName); + console.log(talent); + if (talent) { + talente.push({ + taw: 0, + talent + }) + } else { + console.error(`${talentName} not found in items`) + } + }) + + // push base talents + game.actors.getName(data.name).update({system: {talente}}) + + const startEigenschaften = { + "mu": 10, + "kl": 10, + "in": 10, + "ch": 10, + "ff": 10, + "ge": 10, + "ko": 10, + "kk": 10, + } + + game.actors.getName(data.name).update({system: {attribute: startEigenschaften}}) + super._onCreate(data, options, userId); + + + } + } \ No newline at end of file diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index ebc67b42..84cb4353 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -1,4 +1,16 @@ +import {importCharacter} from "../xml-import/xml-import.mjs"; + export class Character extends Actor { + + import() { + let input = document.createElement('input') + input.type = 'file' + input.accept = '.xml' + input.onchange = e => { + importCharacter(this.id, e.target.files[0]) + } + input.click() + } /** * Augment the basic Item data model with additional dynamic data. */ @@ -7,4 +19,21 @@ export class Character extends Actor { this.prepareEmbeddedDocuments(); } + getRollData() { + const data = super.getRollData(); + + if (this.type !== 'character') return; + + // Copy the ability scores to the top level, so that rolls can use + // formulas like `@str.mod + 4`. + if (data.attribute) { + for (let [k, v] of Object.entries(data.attribute)) { + data[k] = foundry.utils.deepClone(v); + } + } + console.log(data); + return data; + } + + } \ No newline at end of file diff --git a/src/module/documents/skill.mjs b/src/module/documents/skill.mjs index ead10ed7..99b1992b 100644 --- a/src/module/documents/skill.mjs +++ b/src/module/documents/skill.mjs @@ -1,6 +1,5 @@ -import { BaseItem } from "./base-item.mjs"; -export class Skill extends BaseItem { +export class Skill extends Item { /** * Augment the basic Item data model with additional dynamic data. */ diff --git a/src/module/documents/spell.mjs b/src/module/documents/spell.mjs index f382a84c..05d34b42 100644 --- a/src/module/documents/spell.mjs +++ b/src/module/documents/spell.mjs @@ -1,6 +1,4 @@ -import { BaseItem } from "./base-item.mjs"; - -export class Spell extends BaseItem { +export class Spell extends Item { /** * Augment the basic Item data model with additional dynamic data. */ diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index e1be95eb..a776bca3 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -34,14 +34,63 @@ export class CharacterSheet extends ActorSheet { // Add the actor's data to context.data for easier access, as well as flags. context.system = actorData.system; context.flags = actorData.flags; + context.attributes = [ + { + eigenschaft: "mu", + name: "Mut", + wert: actorData.system.attribute.mu.aktuell ?? 0, + }, + { + eigenschaft: "kl", + name: "Klugheit", + wert: actorData.system.attribute.kl.aktuell ?? 0, + }, + { + eigenschaft: "in", + name: "Intuition", + wert: actorData.system.attribute.in.aktuell ?? 0, + }, + { + eigenschaft: "ch", + name: "Charisma", + wert: actorData.system.attribute.ch.aktuell ?? 0, + }, + { + eigenschaft: "ff", + name: "Fingerfertigkeit", + wert: actorData.system.attribute.ff.aktuell ?? 0, + }, + { + eigenschaft: "ge", + name: "Geschicklichkeit", + wert: actorData.system.attribute.ge.aktuell ?? 0, + }, + { + eigenschaft: "ko", + name: "Konstitution", + wert: actorData.system.attribute.ko.aktuell ?? 0, + }, + { + eigenschaft: "kk", + name: "Körperkraft", + wert: actorData.system.attribute.kk.aktuell ?? 0, + }, + + ]; context.skills = []; if ( context.system.talente?.length >= 0) { context.system.talente.forEach(talent => { - const tempTalent = talent(); - console.log(tempTalent.system.probe); + console.log(talent); + const taw = talent.taw; + const talentObjekt = game.items.get(talent.talent); + const eigenschaften = Object.values(talentObjekt.system.probe); context.skills.push({ - talentName: tempTalent.name, - probe: `ROLLDATA(${Object.values(tempTalent.system.probe).join("/")})` + talentName: talentObjekt.name, + taw: taw, + rollEigenschaft1: this.prepareEigenschaftRoll(actorData, eigenschaften[0]), + rollEigenschaft2: this.prepareEigenschaftRoll(actorData, eigenschaften[1]), + rollEigenschaft3: this.prepareEigenschaftRoll(actorData, eigenschaften[2]), + probe: `(${eigenschaften.join("/")})` }); }) @@ -51,9 +100,97 @@ export class CharacterSheet extends ActorSheet { return context; } + prepareEigenschaftRoll(actorData, name) { + return actorData.system.attribute[name.toLowerCase()] + } + + async _onTalentRoll(event) { + event.preventDefault(); + const dataset = event.currentTarget.dataset; + console.log(dataset) + if (dataset.rolleigenschaft1) { + let roll1 = new Roll("3d20", this.actor.getRollData()); + + let evaluated1 = (await roll1.evaluate()) + + const dsaDieRollEvaluated = this._evaluateRoll(evaluated1.terms[0].results, { + taw: dataset.taw, + werte: [dataset.rolleigenschaft1, dataset.rolleigenschaft2, dataset.rolleigenschaft3], + }) + + if (dsaDieRollEvaluated.tap >= 0) { // erfolg + evaluated1.toMessage({ + speaker: ChatMessage.getSpeaker({actor: this.actor}), + flavor: ` ${dsaDieRollEvaluated.meisterlich?'Meisterlich geschafft':'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, + rollMode: game.settings.get('core', 'rollMode'), + }) + } else { // misserfolg + evaluated1.toMessage({ + speaker: ChatMessage.getSpeaker({actor: this.actor}), + flavor: ` ${dsaDieRollEvaluated.meisterlich?'Gepatzt':''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, + rollMode: game.settings.get('core', 'rollMode'), + }) + } + + + } + } + + _evaluateRoll(rolledDice, { taw, lowerThreshold = 1, upperThreshold = 20, countToMeisterlich = 3, countToPatzer = 3, werte = [] } ) { + let tap = taw; + let meisterlichCounter = 0; + let patzerCounter = 0; + let failCounter = 0; + + rolledDice.forEach( (rolledDie, index) => { + if (tap < 0 && rolledDie.result > werte[index]) { + tap -= rolledDie.result - werte[index]; + if (tap <0) { // konnte nicht vollständig ausgeglichen werden + failCounter++; + } + } else if (rolledDie.result > werte[index]) { // taw ist bereits aufgebraucht und wert kann nicht ausgeglichen werden + tap -= rolledDie.result - werte[index]; + failCounter++; + } + if (rolledDie.result <= lowerThreshold) meisterlichCounter++; + if (rolledDie.result > upperThreshold) patzerCounter++; + }) + + return { + tap, + meisterlich: meisterlichCounter === countToMeisterlich, + patzer: patzerCounter === countToPatzer, + } + } + + _onAttributeRoll(event) { + event.preventDefault(); + const dataset = event.currentTarget.dataset; + if (dataset.roll) { + let label = dataset.label ? `[Attribut] ${dataset.label}` : ''; + let roll = new Roll(dataset.roll, this.actor.getRollData()); + roll.toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label, + rollMode: game.settings.get('core', 'rollMode'), + }); + return roll; + } + } + activateListeners(html) { super.activateListeners(html); + html.on('click', '.attribut.rollable', (evt) => { + console.log(evt); + this._onAttributeRoll(evt); + }); + + html.on('click', '.talent.rollable', (evt) => { + console.log(evt); + this._onTalentRoll(evt); + }); + // Everything below here is only needed if the sheet is editable if (!this.isEditable) return; diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs new file mode 100644 index 00000000..e7681a07 --- /dev/null +++ b/src/module/xml-import/xml-import.mjs @@ -0,0 +1,340 @@ +let months = [ + "Praios", + "Rondra", + "Efferd", + "Travia", + "Boron", + "Hesinde", + "Firun", + "Tsa", + "Phex", + "Peraine", + "Ingerimm", + "Rahja", + "Namenloser Tag" +] + + +/** + * Imports a character from a file created in the tool Helden-Software + * @param actorId the actor-id of the character + * @param file the file from which the character should be imported + */ +export async function importCharacter(actorId, file) { + let actor = game.actors.get(actorId) + let xmlString = await parseFileToString(file) + let domParser = new DOMParser() + let dom = domParser.parseFromString(xmlString, 'application/xml') + + let rawJson = getJsonFromXML(dom) + let characterJson = mapRawJson(rawJson) + + actor.update(characterJson) +} + +/** + * + * @param dom the XML-Dom from which the json should be extracted + * @returns {{}} the json parsed from the xml + */ +function getJsonFromXML(dom) { + let children = [...dom.children]; + + // initializing object to be returned. + let jsonResult = {}; + + let attributes = dom.attributes ? dom.attributes : [] + for (let attribute of attributes) { + jsonResult[attribute.name] = attribute.value + } + + if (children.length) { + for (let child of children) { + + // checking is child has siblings of same name. + let childIsArray = children.filter(eachChild => eachChild.nodeName === child.nodeName).length > 1; + + // if child is array, save the values as array, else as strings. + if (childIsArray) { + if (jsonResult[child.nodeName] === undefined) { + jsonResult[child.nodeName] = [getJsonFromXML(child)]; + } else { + jsonResult[child.nodeName].push(getJsonFromXML(child)); + } + } else { + jsonResult[child.nodeName] = getJsonFromXML(child); + } + } + } + + return jsonResult; +} + +/** + * gets the text content of a file + * @param file the file with the desired content + * @returns {Promise} a promise that returns the string contents of the file + */ +async function parseFileToString(file) { + return new Promise((resolve, reject) => { + let reader = new FileReader() + reader.readAsText(file, "utf-8") + reader.onload = event => { + resolve(event.target.result) + } + reader.onerror = event => { + reject(event) + } + }) +} + +/** + *Calculates a Birthdate String in the Calendar of Bosparans Fall + * @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" + */ +function calculateBirthdate(json) { + let day = json.gbtag + let month = months[parseInt(json.gbmonat) - 1] + let year = json.gbjahr + + return `${day}. ${month} ${year} BF` +} + +/** + * parses a json into a fitting character-json + * @param rawJson the json parsed from the Helden-Software XML + * @returns {{}} a json representation of the character + */ +function mapRawJson(rawJson) { + let json = {} + let held = rawJson.helden.held; + json.name = held.name + json.meta = {} + json.meta.spezies = held.basis.rasse.string + json.meta.kultur = held.basis.kultur.string + let professions = [] + for (let profession in held.basis.ausbildungen.ausbildung) { + profession = held.basis.ausbildungen.ausbildung[profession] + if (profession.tarnidentitaet) { + professions = [profession.tarnidentitaet] + break; + } + let professionString = profession.string + professions.push(professionString) + } + json.meta.professions = professions + 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, + ] + 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, + ] + 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.attribute.mr = { + mod: filterAttribute(attributes,"Magieresistenz").mod + } + json.attribute.lep = { + mod: filterAttribute(attributes,"Lebensenergie").mod + } + json.attribute.aup = { + mod: filterAttribute(attributes,"Ausdauer").mod + } + json.attribute.asp = { + mod: filterAttribute(attributes,"Astralenergie").mod + } + json.attribute.kap = { + mod: filterAttribute(attributes,"Karmaenergie").mod + } + let attribute = filterAttribute(attributes,"Karmaenergie") + json.attribute.at = { + mod: attribute.mod, + aktuell: attribute.value + } + attribute = filterAttribute(attributes,"at") + json.attribute.pa = { + mod: attribute.mod, + aktuell: attribute.value + } + attribute = filterAttribute(attributes,"pa") + json.attribute.at = { + mod: attribute.mod, + aktuell: attribute.value + } + attribute = filterAttribute(attributes,"fk") + json.attribute.fk = { + mod: attribute.mod, + aktuell: attribute.value + } + attribute = filterAttribute(attributes,"ini") + json.attribute.ini = { + mod: attribute.mod, + aktuell: attribute.value + } + json.attribute.so = getAttributeJson(attributes, "Sozialstatus") + let benefits = [] + for (let benefit in held.vt.vorteil) { + benefit = held.vt.vorteil[benefit] + let benefitJson = { + name: benefit.name, + } + if (benefit.value !== undefined) { + benefitJson.wert = benefit.value + } + benefits.push(benefitJson) + } + json.vornachteile = benefits + 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 talents = [] + for (let talent in held.talentliste.talent) { + talent = held.talentliste.talent[talent] + let talentItem = game.items.getName(talent.name) + if (talentItem) { + let talentJson = { + talent: talentItem, + taw: talent.value, + } + talents.push(talentJson) + } + } + json.talente = talents + let spells = [] + /*for (let spell in held.zauberliste.zauber) { + spell = held.zauberliste.zauber[spell] + spells.push({ + name: spell.name, + rep: spell.repraesentation, + hauszauber: spell.hauszauber === "true", + zfw: spell.value, + anmerkungen: spell.zauberkommentar, + komplexitaet: spell.k, + }) + }*/ + json.zauber = spells + 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 + 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: '', + callback: (li) => { + const actorId = li.getAttribute("data-entry-id") + const actor = game.actors.get(actorId) + actor.import() + } + }) +}) \ No newline at end of file diff --git a/src/packs/_source/talente-brw/körperlich/sich-verstecken.json b/src/packs/_source/talente-brw/körperlich/sich-verstecken.json index adc9d8de..8fce89fa 100644 --- a/src/packs/_source/talente-brw/körperlich/sich-verstecken.json +++ b/src/packs/_source/talente-brw/körperlich/sich-verstecken.json @@ -2,7 +2,7 @@ "_id": "o1nYjhmMP0Zzlcw6", "_key": "!items!o1nYjhmMP0Zzlcw6", "type": "Skill", - "name": "Sich verstecken", + "name": "Sich Verstecken", "system": { "gruppe": "Körperlich", "probe": [ diff --git a/src/templates/actor/actor-character-sheet.hbs b/src/templates/actor/actor-character-sheet.hbs index f2e44565..5a38a416 100644 --- a/src/templates/actor/actor-character-sheet.hbs +++ b/src/templates/actor/actor-character-sheet.hbs @@ -6,6 +6,18 @@

+
+ {{#each attributes}} + + {{/each}} +
@@ -34,9 +46,10 @@
    {{#each skills}} -
  • +
  • {{this.talentName}} {{this.probe}} + TAW: {{this.taw}}
  • {{/each}}
diff --git a/src/templates/sheets/character-sheet.hbs b/src/templates/sheets/character-sheet.hbs new file mode 100644 index 00000000..ea1316a9 --- /dev/null +++ b/src/templates/sheets/character-sheet.hbs @@ -0,0 +1,10 @@ +
+
+
+

{{actor.name}}

+
+
+
+ +
+
\ No newline at end of file