From 32031eb5483305c3caf2b26bb706dc05991af25b Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 1 Oct 2025 22:27:21 +0200 Subject: [PATCH 1/6] When a character is created, its base-skills are now added from compendium and added to the actor as an embedded document. --- src/main.mjs | 51 ++++- src/module/data/character.mjs | 102 +++++++-- src/module/data/skill.mjs | 53 ++++- .../extensions/DragDropApplicationMixin.mjs | 62 ------ src/module/extensions/DragDropDSA41.mjs | 54 ----- src/module/sheets/characterSheet.mjs | 201 ++++++++++++------ src/module/sheets/skillSheet.mjs | 60 +----- src/module/sheets/vornachteilSheet.mjs | 5 +- src/templates/actor/actor-character-sheet.hbs | 6 +- src/templates/ui/partial-rollable-button.hbs | 2 +- 10 files changed, 324 insertions(+), 272 deletions(-) delete mode 100644 src/module/extensions/DragDropApplicationMixin.mjs delete mode 100644 src/module/extensions/DragDropDSA41.mjs diff --git a/src/main.mjs b/src/main.mjs index ed282e4f..7ffea535 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -7,7 +7,6 @@ import { VornachteileDataModel } from "./module/data/vornachteile.mjs"; import { Character } from "./module/documents/character.mjs"; import { CharacterSheet } from "./module/sheets/characterSheet.mjs"; import { VornachteilSheet } from "./module/sheets/vornachteilSheet.mjs"; -import {DragDropDSA41} from "./module/extensions/DragDropDSA41.mjs"; async function preloadHandlebarsTemplates() { return loadTemplates([ @@ -21,6 +20,10 @@ async function preloadHandlebarsTemplates() { Hooks.once("init", () => { + game.DSA41 = { + rollItemMacro + } + // Configure custom Document implementations. CONFIG.Actor.documentClass = Character; @@ -35,7 +38,10 @@ Hooks.once("init", () => { Advantage: VornachteileDataModel } - CONFIG.ux.DragDrop = DragDropDSA41; + CONFIG.Combat.initiative = { + formula: `1d6 + @attribute.ini`, + decimals: 0 + } console.log("DSA 4.1 is ready for development!") @@ -67,4 +73,43 @@ Hooks.once("init", () => { Hooks.on('dropActorSheetData', (actor, sheet, data) => { CharacterSheet.onDroppedData(actor, sheet, data); -} ) \ No newline at end of file +} ) + +Hooks.once("ready", async function() { + // Wait to register hotbar drop hook on ready so that modules could register earlier if they want to + Hooks.on("hotbarDrop", (bar, data, slot) => createBoilerplateMacro(data, slot)); +}); + +async function createBoilerplateMacro(data, slot) { + console.log(data, slot) + if (data.type !== "Item") return; + if (!("data" in data)) return ui.notifications.warn("You can only create macro buttons for owned Items"); + const item = data.data; + + // Create the macro command + const command = `game.DSA41.rollItemMacro("${item.name}");`; + let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command)); + if (!macro) { + macro = await Macro.create({ + name: item.name, + type: "script", + img: item.img, + command: command, + flags: { "dsa41.itemMacro": true } + }); + } + game.user.assignHotbarMacro(macro, slot); + return false; +} + +function rollItemMacro(itemName) { + const speaker = ChatMessage.getSpeaker(); + let actor; + if (speaker.token) actor = game.actors.tokens[speaker.token]; + if (!actor) actor = game.actors.get(speaker.actor); + const item = actor ? actor.items.find(i => i.name === itemName) : null; + if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`); + + // Trigger the item roll + return item.roll(); +} \ No newline at end of file diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index 8f977b3d..33194c51 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -1,9 +1,41 @@ +import {Skill} from "../documents/skill.mjs"; + const { - SchemaField, NumberField, StringField, ArrayField, ForeignDocumentField + SchemaField, NumberField, StringField, EmbeddedDocumentField, DocumentIdField, ArrayField, ForeignDocumentField } = foundry.data.fields; +/** + * @extends {Map>} + */ +class SkillMap extends Map { + /** @inheritDoc */ + get(key, { type }={}) { + const result = super.get(key); + if ( !result?.size || !type ) return result; + return result.filter(i => i.type === type); + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + set(key, value) { + if ( !this.has(key) ) super.set(key, new Set()); + this.get(key).add(value); + return this; + } +} + export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { + + /** + * Mapping of item identifiers to the items. + * @type {SkillMap>} + */ + skills = this.skills + + + static defineSchema() { return { name: new StringField(), @@ -103,7 +135,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { gilde: new StringField(), }), vornachteile: new ArrayField(new SchemaField({ - vornachteil: new ForeignDocumentField(Item), + vornachteil: new DocumentIdField(Item), wert: new NumberField({ required: false, integer: true }), })), sonderfertigkeiten: new ArrayField(new SchemaField({ @@ -112,12 +144,12 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { })), talente: new ArrayField(new SchemaField({ - talent: new ForeignDocumentField(Item), + talent: new DocumentIdField(Item), taw: new NumberField({integer: true, required: true}), }) ), zauber: new ArrayField(new SchemaField({ - talent: new ForeignDocumentField(Item), + talent: new DocumentIdField(), zfw: new NumberField({integer: true, required: true}), })), liturgien: new ArrayField(new SchemaField({ @@ -139,8 +171,13 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { super._initialize(options); } - async _onCreate(data, options, userId) { - // prepare base talents + /** + * Adds base skills according to the BRW to the given actor + * @param actor + * @returns {Promise} + */ + async #createBaseSkills(actor) { + const compendiumOfSkills = await game.packs.get('DSA_4-1.talente-brw'); const talentsByName = [ "Athletik", "Klettern", "Körperbeherrschung", "Schleichen", "Schwimmen", "Selbstbeherrschung", "Sich Verstecken", "Singen", "Sinnenschärfe", "Tanzen", "Zechen", "Menschenkenntnis", "Überreden", @@ -151,22 +188,36 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { 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`) - } + const mappedCompendiumItems = talentsByName.map( talentName => { + const talent = compendiumOfSkills.index.find( skill => skill.name === talentName) + return talent._id }) - // push base talents - await game.actors.getName(data.name).update({system: {talente}}) + for (const talentId of mappedCompendiumItems) { + const talent = await compendiumOfSkills.getDocument(talentId); + try { + const embeddedDocument = (await thisCharacter.createEmbeddedDocuments('Item', [talent]))[0] + if (embeddedDocument.type === "Skill") { + if (talent) { + talente.push({ + taw: 0, + talent: embeddedDocument.id, + }) + } + } + } catch (error) { + console.error(`${talentId} not found in items`) + } + } + await actor.update({system: { talente: talente}}) + } + /** + * Sets the attributes of the given actor to their default values + * @param actor + * @returns {Promise} + */ + async #setBaseAttributes(actor) { const startEigenschaften = { "mu": { start: 10, @@ -210,10 +261,17 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { } } - await game.actors.getName(data.name).update({system: {attribute: startEigenschaften}}) - super._onCreate(data, options, userId); + await actor.update({system: {attribute: startEigenschaften}}) + } + async _onCreate(data, options, userId) { + const thisCharacter = await game.actors.getName(data.name); + + await this.#createBaseSkills(thisCharacter) + await this.#setBaseAttributes(thisCharacter) + + super._onCreate(data, options, userId); } -} \ No newline at end of file +} diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index 5056e80a..e8464566 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -34,6 +34,57 @@ export class SkillDataModel extends BaseItem { * @param {Event} event The originating click event * @private */ - async roll() { } + async roll() { + console.log(this.parent) + 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: [this.system.probe[0], this.system.probe[1], this.system.probe[2]], + }) + + 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, + } + } } \ No newline at end of file diff --git a/src/module/extensions/DragDropApplicationMixin.mjs b/src/module/extensions/DragDropApplicationMixin.mjs deleted file mode 100644 index ecc9284a..00000000 --- a/src/module/extensions/DragDropApplicationMixin.mjs +++ /dev/null @@ -1,62 +0,0 @@ -import {DragDropDSA41} from "./DragDropDSA41.mjs"; - -export default function DragDropApplicationMixin(Base) { - return class DragDropApplication extends Base { - /** @override */ - _onDragOver(event) { - const data = DragDropDSA41.getPayload(event); - DragDropDSA41.dropEffect = event.dataTransfer.dropEffect = (foundry.utils.getType(data) === "Object") - ? this._dropBehavior(event, data) : "copy"; - } - - /* -------------------------------------------- */ - - /** - * The behavior for the dropped data. When called during the drop event, ensure this is called before awaiting - * anything or the drop behavior will be lost. - * @param {DragEvent} event The drag event. - * @param {object} [data] The drag payload. - * @returns {DropEffectValue} - */ - _dropBehavior(event, data) { - data ??= DragDropDSA41.getPayload(event); - const allowed = this._allowedDropBehaviors(event, data); - let behavior = DragDropDSA41.dropEffect ?? event.dataTransfer?.dropEffect; - - if ( event.type === "dragover" ) { - if ( areKeysPressed(event, "dragMove") ) behavior = "move"; - else if ( areKeysPressed(event, "dragCopy") ) behavior = "copy"; - else behavior = this._defaultDropBehavior(event, data); - } - - if ( (behavior !== "none") && !allowed.has(behavior) ) return allowed.first() ?? "none"; - return behavior || "copy"; - } - - /* -------------------------------------------- */ - - /** - * Types of allowed drop behaviors based on the origin & target of a drag event. - * @param {DragEvent} event The drag event. - * @param {object} [data] The drag payload. - * @returns {Set} - * @protected - */ - _allowedDropBehaviors(event, data) { - return new Set(); - } - - /* -------------------------------------------- */ - - /** - * Determine the default drop behavior for the provided operation. - * @param {DragEvent} event The drag event. - * @param {object} [data] The drag payload. - * @returns {DropEffectValue} - * @protected - */ - _defaultDropBehavior(event, data) { - return "copy"; - } - }; -} diff --git a/src/module/extensions/DragDropDSA41.mjs b/src/module/extensions/DragDropDSA41.mjs deleted file mode 100644 index 6344455e..00000000 --- a/src/module/extensions/DragDropDSA41.mjs +++ /dev/null @@ -1,54 +0,0 @@ -export class DragDropDSA41 extends foundry.applications.ux.DragDrop { - - /** - * Drop effect used for current drag operation. - * @type {DropEffectValue|null} - */ - static dropEffect = null; - - /* -------------------------------------------- */ - - /** - * Stored drag event payload. - * @type {{ data: any, event: DragEvent }|null} - */ - static #payload = null; - - /* -------------------------------------------- */ - - /** @override */ - async _handleDragStart(event) { - await this.callback(event, "dragstart"); - if ( event.dataTransfer.items.length ) { - console.log(event) - event.stopPropagation(); - let data = event.dataTransfer.getData("application/json") || event.dataTransfer.getData("text/plain"); - try { data = JSON.parse(data); } catch(err) {} - DragDropDSA41.#payload = data ? { event, data } : null; - } else { - DragDropDSA41.#payload = null; - } - } - - /* -------------------------------------------- */ - - /** @override */ - async _handleDragEnd(event) { - await this.callback(event, "dragend"); - DragDropDSA41.dropEffect = null; - DragDropDSA41.#payload = null; - } - - /* -------------------------------------------- */ - - /** - * Get the data payload for the current drag event. - * @param {DragEvent} event - * @returns {any} - */ - static getPayload(event) { - if ( !DragDropDSA41.#payload?.data ) return null; - return DragDropDSA41.#payload.data; - } - -} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index f8eae1d8..8087f4b7 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -1,5 +1,3 @@ -import {DragDropDSA41} from "../extensions/DragDropDSA41.mjs"; - export class CharacterSheet extends ActorSheet { /**@override */ static get defaultOptions() { @@ -24,10 +22,6 @@ export class CharacterSheet extends ActorSheet { /** @override */ getData() { - // Retrieve the data structure from the base sheet. You can inspect or log - // the context variable to see the structure, but some key properties for - // sheets are the actor object, the data object, whether or not it's - // editable, the items array, and the effects array. const context = super.getData(); // Use a safe clone of the actor data for further operations. @@ -36,6 +30,89 @@ 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; + + this.#addSkillsToContext(context) + this.#addAdvantagesToContext(context) + this.#addAttributesToContext(context) + + return context; + } + + #addSkillsToContext(context) { + const actorSkills = {} + const actorData = context.data; + context.skills = {}; + context.flatSkills = []; + + Object.values(actorData.items).forEach( (item) => { + if (item.type === "Skill") { + actorSkills[item._id] = item; + } + } + ); + + if ( context.system.talente?.length >= 0) { + context.system.talente.forEach( ( { taw, talent }, index) => { + if (actorSkills[talent]) { + const talentObjekt = actorSkills[talent]; + if (talentObjekt.type === 'Skill') { + const talentGruppe = talentObjekt.system.gruppe; + const eigenschaften = Object.values(talentObjekt.system.probe); + const werte = [ + {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, + {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, + {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} + ] + if (context.skills[talentGruppe] == null) { + context.skills[talentGruppe] = []; + } + const obj = { + type: "talent", + gruppe: talentGruppe, + name: talentObjekt.name, + taw: "" + taw, + tawPath: `system.talente.${index}.taw`, + werte, + rollEigenschaft1: werte[0].value, + rollEigenschaft2: werte[1].value, + rollEigenschaft3: werte[2].value, + eigenschaft1: werte[0].name, + eigenschaft2: werte[1].name, + eigenschaft3: werte[2].name, + probe: `(${eigenschaften.join("/")})` + }; + context.skills[talentGruppe].push(obj); + context.flatSkills.push(obj); + } + } + }) + } + } + + #addAdvantagesToContext(context) { + const actorAdvantages = {} + const actorData = context.data; + Object.values(actorData.items).forEach( (item) => { + if (item.type === "Advantage") { + actorAdvantages[item._id] = item; + } + } + ); + if ( context.system.vornachteile.length >= 0) { + context.system.vornachteile.forEach( ( { vornachteil }, index) => { + context.vornachteile.push( + { + name: vornachteil.name, + value: vornachteil.value, + auswahl: vornachteil.auswahl, + } + ) + }) + } + } + + #addAttributesToContext(context) { + const actorData = context.data; context.attributes = [ { eigenschaft: "mu", @@ -87,46 +164,7 @@ export class CharacterSheet extends ActorSheet { }, ]; - context.skills = {}; - context.flatSkills = []; - if ( context.system.talente?.length >= 0) { - context.system.talente.forEach( (talent, index) => { - if (talent.talent) { - const taw = talent.taw; - const talentObjekt = game.items.get(talent.talent); - console.log(talent); - const talentGruppe = talentObjekt.system.gruppe; - const eigenschaften = Object.values(talentObjekt.system.probe); - const werte = [ - {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, - {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, - {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} - ] - - if (context.skills[talentGruppe] == null) { - context.skills[talentGruppe] = []; - } - - const obj = { - type: "talent", - gruppe: talentGruppe, - name: talentObjekt.name, - taw: "" + taw, - tawPath: `system.talente.${index}.taw`, - werte, - rollEigenschaft1: werte[0].value, - rollEigenschaft2: werte[1].value, - rollEigenschaft3: werte[2].value, - probe: `(${eigenschaften.join("/")})` - }; - - context.skills[talentGruppe].push(obj); - context.flatSkills.push(obj); - } - }) - } - return context; } prepareEigenschaftRoll(actorData, name) { @@ -165,6 +203,18 @@ export class CharacterSheet extends ActorSheet { } } + _onDropDocument(event, item) { + console.log(item) + + } + + _onDragStart(event) { + super._onDragStart(event); + const src = event.target + console.log(event) + event.dataTransfer.setData("plain/text", src.dataset.name); + } + _evaluateRoll(rolledDice, { taw, lowerThreshold = 1, upperThreshold = 20, countToMeisterlich = 3, countToPatzer = 3, werte = [] } ) { let tap = taw; let meisterlichCounter = 0; @@ -237,29 +287,33 @@ export class CharacterSheet extends ActorSheet { this._onRoll(evt); }); - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; + + let handler = ev => this._onDragStart(ev); + // Find all items on the character sheet. + html.find('.talent.rollable').each((i, li) => { + // Add draggable attribute and dragstart listener. + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); } - static onDroppedData(actor, characterSheet, data) { - const item = game.items.get(foundry.utils.parseUuid(data.uuid).id) - console.log(); + async #handleDroppedSkill(actor, data) { let alreadyInSet = false; let previousTaw = 0; + const id = foundry.utils.parseUuid(data.uuid).id; + + const item = (await actor.createEmbeddedDocuments('Item', [await game.items.get(id)]))[0] + actor.system.talente.forEach(({taw, talent}) => { - if (talent._id === item._id) { - alreadyInSet = talent; - previousTaw = taw; + if (talent) { + if (talent._id === item._id) { + alreadyInSet = talent; + previousTaw = taw; + } } }) - - - - const myContent = ` - TaW: - -`; + const myContent = `TaW: `; new Dialog({ title: `Talent ${item.name} ${alreadyInSet?'ersetzen':'hinzufügen'}`, content: myContent, @@ -275,17 +329,23 @@ export class CharacterSheet extends ActorSheet { async function myCallback(html) { const taw = html.find("input#taw").val(); - let index = actor.system.talente.findIndex( predicate => predicate.talent._id === alreadyInSet._id ) + let index = actor.system.talente.findIndex( predicate => predicate.talent && predicate.talent._id === alreadyInSet._id ) let sorted = []; if (alreadyInSet) { actor.system.talente[index].taw = taw; sorted = actor.system.talente; } else { - sorted = [{ + const newItem = { taw: taw, talent: {_id: item._id, name: item.name} - }, ...actor.system.talente].sort((a, b) => a.talent.name.localeCompare(b.talent.name)); + } + console.log(newItem, await game.items.get(item._id)) + sorted = [newItem, ...actor.system.talente].sort((a, b) => { + + return a.talent.name.localeCompare(b.talent.name) + } + ); } const serialised = sorted.map(({taw, talent}) => { @@ -303,12 +363,23 @@ export class CharacterSheet extends ActorSheet { ] } }); - await characterSheet.render(true); ui.notifications.info(`Talent ${item.name} auf TaW ${taw} hinzugefügt`); } + } + static onDroppedData(actor, characterSheet, data) { + const item = game.items.get(foundry.utils.parseUuid(data.uuid).id) + + switch (item.type) { + case "Skill": + characterSheet.#handleDroppedSkill(actor, data); + default: + console.log(item, item.type); + } + + // maybe dont actor.items.clear() } -} \ No newline at end of file +} diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index 9f73ce7d..abffa724 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -1,7 +1,4 @@ -import {DragDropDSA41} from "../extensions/DragDropDSA41.mjs"; -import DragDropApplicationMixin from "../extensions/DragDropApplicationMixin.mjs"; - -export class SkillSheet extends DragDropApplicationMixin(foundry.appv1.sheets.ItemSheet) { +export class SkillSheet extends ItemSheet { /**@override */ static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { @@ -58,59 +55,4 @@ export class SkillSheet extends DragDropApplicationMixin(foundry.appv1.sheets.It if (!this.isEditable) return; } - - /* -------------------------------------------- */ - /* Drag & Drop */ - /* -------------------------------------------- */ - - /** @override */ - _allowedDropBehaviors(event, data) { - console.log(data, event); - if ( !data?.uuid ) return new Set(["copy", "link"]); - const allowed = new Set(["copy", "move", "link"]); - const s = foundry.utils.parseUuid(data.uuid); - const t = foundry.utils.parseUuid(this.document.uuid); - const sCompendium = s.collection instanceof foundry.documents.collections.CompendiumCollection; - const tCompendium = t.collection instanceof foundry.documents.collections.CompendiumCollection; - - // If either source or target are within a compendium, but not inside the same compendium, move not allowed - if ( (sCompendium || tCompendium) && (s.collection !== t.collection) ) allowed.delete("move"); - - return allowed; - } - - /* -------------------------------------------- */ - - /** @override */ - _defaultDropBehavior(event, data) { - if ( !data?.uuid ) return "copy"; - const d = foundry.utils.parseUuid(data.uuid); - const t = foundry.utils.parseUuid(this.document.uuid); - const base = d.embedded?.length ? "document" : "primary"; - console.log(d, t, base); - return (d.collection === t.collection) && (d[`${base}Id`] === t[`${base}Id`]) - && (d[`${base}Type`] === t[`${base}Type`]) ? "move" : "copy"; - } - - /* -------------------------------------------- */ - - /** @inheritDoc */ - async _onDragStart(event) { - await super._onDragStart(event); - if ( !this.document.isOwner || this.document.collection?.locked ) { - event.dataTransfer.effectAllowed = "copyLink"; - } - } - - _onDragOver(event) { - super._onDragOver(event); - console.log(event); - } - - _dropBehavior(event, data) { - console.log(event, data); - return super._dropBehavior(event, data); - - } - } \ No newline at end of file diff --git a/src/module/sheets/vornachteilSheet.mjs b/src/module/sheets/vornachteilSheet.mjs index 746b1b47..842bd24f 100644 --- a/src/module/sheets/vornachteilSheet.mjs +++ b/src/module/sheets/vornachteilSheet.mjs @@ -1,7 +1,4 @@ -import {DragDropDSA41} from "../extensions/DragDropDSA41.mjs"; -import DragDropApplicationMixin from "../extensions/DragDropApplicationMixin.mjs"; - -export class VornachteilSheet extends DragDropApplicationMixin(foundry.appv1.sheets.ItemSheet) { +export class VornachteilSheet extends ItemSheet { /**@override */ static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { diff --git a/src/templates/actor/actor-character-sheet.hbs b/src/templates/actor/actor-character-sheet.hbs index 09975c89..a4f65d6e 100644 --- a/src/templates/actor/actor-character-sheet.hbs +++ b/src/templates/actor/actor-character-sheet.hbs @@ -60,7 +60,11 @@
- +
    + {{#each items}} +
  • {{this.name}}
  • + {{/each}} +
diff --git a/src/templates/ui/partial-rollable-button.hbs b/src/templates/ui/partial-rollable-button.hbs index 92bc7e45..f3894269 100644 --- a/src/templates/ui/partial-rollable-button.hbs +++ b/src/templates/ui/partial-rollable-button.hbs @@ -1,4 +1,4 @@ -
+
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} From 1afdd483e6ae6a2e8bb18fb88af9380d05b9cf35 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 2 Oct 2025 16:52:56 +0200 Subject: [PATCH 2/6] Character Creation with Default Values is no longer possible (got to be but its not scope of MVP anyway). Skills either from Compendia or Imported Entries can now be uniquely added to a Character. This approach will help us later with adding other Elements like Advantages (these need a "uniqueness" Attribute), Spells (always unique), Miracles (also always unique), Equipment --- src/main.mjs | 4 +- src/module/data/character.mjs | 135 +-------------------------- src/module/data/skill.mjs | 6 +- src/module/documents/character.mjs | 101 +++++++++++++++++++- src/module/sheets/characterSheet.mjs | 125 +++++++------------------ src/module/xml-import/xml-import.mjs | 33 ++++--- 6 files changed, 159 insertions(+), 245 deletions(-) diff --git a/src/main.mjs b/src/main.mjs index 7ffea535..a5618d70 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -72,7 +72,7 @@ Hooks.once("init", () => { }) Hooks.on('dropActorSheetData', (actor, sheet, data) => { - CharacterSheet.onDroppedData(actor, sheet, data); + return CharacterSheet.onDroppedData(actor, sheet, data); } ) Hooks.once("ready", async function() { @@ -112,4 +112,4 @@ function rollItemMacro(itemName) { // Trigger the item roll return item.roll(); -} \ No newline at end of file +} diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index 33194c51..7c86ddc0 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -1,41 +1,12 @@ import {Skill} from "../documents/skill.mjs"; +import {SkillDataModel} from "./skill.mjs"; const { SchemaField, NumberField, StringField, EmbeddedDocumentField, DocumentIdField, ArrayField, ForeignDocumentField } = foundry.data.fields; -/** - * @extends {Map>} - */ -class SkillMap extends Map { - /** @inheritDoc */ - get(key, { type }={}) { - const result = super.get(key); - if ( !result?.size || !type ) return result; - return result.filter(i => i.type === type); - } - - /* -------------------------------------------- */ - - /** @inheritDoc */ - set(key, value) { - if ( !this.has(key) ) super.set(key, new Set()); - this.get(key).add(value); - return this; - } -} - export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { - - /** - * Mapping of item identifiers to the items. - * @type {SkillMap>} - */ - skills = this.skills - - - static defineSchema() { return { name: new StringField(), @@ -143,11 +114,7 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { auswahlen: new ArrayField(new StringField()), })), - talente: new ArrayField(new SchemaField({ - talent: new DocumentIdField(Item), - taw: new NumberField({integer: true, required: true}), - }) - ), + talente: new ArrayField(new DocumentIdField(Item)), zauber: new ArrayField(new SchemaField({ talent: new DocumentIdField(), zfw: new NumberField({integer: true, required: true}), @@ -171,106 +138,8 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { super._initialize(options); } - /** - * Adds base skills according to the BRW to the given actor - * @param actor - * @returns {Promise} - */ - async #createBaseSkills(actor) { - const compendiumOfSkills = await game.packs.get('DSA_4-1.talente-brw'); - 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 = [] - - const mappedCompendiumItems = talentsByName.map( talentName => { - const talent = compendiumOfSkills.index.find( skill => skill.name === talentName) - return talent._id - }) - - for (const talentId of mappedCompendiumItems) { - const talent = await compendiumOfSkills.getDocument(talentId); - try { - const embeddedDocument = (await thisCharacter.createEmbeddedDocuments('Item', [talent]))[0] - if (embeddedDocument.type === "Skill") { - if (talent) { - talente.push({ - taw: 0, - talent: embeddedDocument.id, - }) - } - } - } catch (error) { - console.error(`${talentId} not found in items`) - } - } - await actor.update({system: { talente: talente}}) - } - - /** - * Sets the attributes of the given actor to their default values - * @param actor - * @returns {Promise} - */ - async #setBaseAttributes(actor) { - const startEigenschaften = { - "mu": { - start: 10, - aktuell: 10, - mod: 0 - }, - "kl": { - start: 10, - aktuell: 10, - mod: 0 - }, - "in": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ch": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ff": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ge": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ko": { - start: 10, - aktuell: 10, - mod: 0 - }, - "kk": { - start: 10, - aktuell: 10, - mod: 0 - } - } - - await actor.update({system: {attribute: startEigenschaften}}) - } - async _onCreate(data, options, userId) { - const thisCharacter = await game.actors.getName(data.name); - await this.#createBaseSkills(thisCharacter) - await this.#setBaseAttributes(thisCharacter) - - super._onCreate(data, options, userId); } diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index e8464566..5032a4c1 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -8,6 +8,7 @@ export class SkillDataModel extends BaseItem { return { name: new StringField({ required: true }), gruppe: new StringField({ required: true }), + taw: new NumberField({ integer: true, initial: 0 }), probe: new ArrayField(new StringField(), { exact: 3 }), // References one of the eight attributes by name voraussetzung: new SchemaField({ talent: new StringField({ model: SkillDataModel }), @@ -15,7 +16,7 @@ export class SkillDataModel extends BaseItem { }), // Required skills at a given level talent: new HTMLField({ required: true }), behinderung: new NumberField({ required: false}), // BE-X - komplexität: new NumberField({ required: false }), // In case of languages + komplexität: new NumberField({ required: false }), // In case of languages } } /** @@ -86,5 +87,4 @@ export class SkillDataModel extends BaseItem { patzer: patzerCounter === countToPatzer, } } - -} \ No newline at end of file +} diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index b7c4c35a..fbea8dc0 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -41,4 +41,103 @@ export class Character extends Actor { } -} \ No newline at end of file + async addSkillFromCompendiumByNameToActor(talentName, actor) { + const compendiumOfSkills = game.packs.get('DSA_4-1.talente-brw'); + const talentId = compendiumOfSkills.index.find( skill => skill.name === talentName) + let talentObject = {} + const talent = await compendiumOfSkills.getDocument(talentId); + try { + const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [talent]))[0] + if (embeddedDocument.type === "Skill") { + if (talent) { + talentObject = { + taw: 0, + talent: embeddedDocument.id, + } + } + } + } catch (error) { + console.error(`${talentName} not found in items`, error) + } + await actor.update({system: { talente: talentObject, ...actor.system.talente}}) + } + + /** + * Adds base skills according to the BRW to the given actor + * @param actor + * @returns {Promise} + */ + async #createBaseSkills(actor) { + 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 => { + + this.addSkillFromCompendiumByNameToActor( + talentName, + ) + }) + + await actor.update({system: { talente: talente}}) + } + + /** + * Sets the attributes of the given actor to their default values + * @param actor + * @returns {Promise} + */ + async #setBaseAttributes(actor) { + const startEigenschaften = { + "mu": { + start: 10, + aktuell: 10, + mod: 0 + }, + "kl": { + start: 10, + aktuell: 10, + mod: 0 + }, + "in": { + start: 10, + aktuell: 10, + mod: 0 + }, + "ch": { + start: 10, + aktuell: 10, + mod: 0 + }, + "ff": { + start: 10, + aktuell: 10, + mod: 0 + }, + "ge": { + start: 10, + aktuell: 10, + mod: 0 + }, + "ko": { + start: 10, + aktuell: 10, + mod: 0 + }, + "kk": { + start: 10, + aktuell: 10, + mod: 0 + } + } + + await actor.update({system: {attribute: startEigenschaften}}) + } + +} diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 8087f4b7..9bbbf59d 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -39,25 +39,15 @@ export class CharacterSheet extends ActorSheet { } #addSkillsToContext(context) { - const actorSkills = {} const actorData = context.data; context.skills = {}; context.flatSkills = []; - Object.values(actorData.items).forEach( (item) => { + Object.values(actorData.items).forEach( (item, index) => { if (item.type === "Skill") { - actorSkills[item._id] = item; - } - } - ); - if ( context.system.talente?.length >= 0) { - context.system.talente.forEach( ( { taw, talent }, index) => { - if (actorSkills[talent]) { - const talentObjekt = actorSkills[talent]; - if (talentObjekt.type === 'Skill') { - const talentGruppe = talentObjekt.system.gruppe; - const eigenschaften = Object.values(talentObjekt.system.probe); + const talentGruppe = item.system.gruppe; + const eigenschaften = Object.values(item.system.probe); const werte = [ {name: eigenschaften[0], value: this.prepareEigenschaftRoll(actorData, eigenschaften[0])}, {name: eigenschaften[1], value: this.prepareEigenschaftRoll(actorData, eigenschaften[1])}, @@ -69,9 +59,9 @@ export class CharacterSheet extends ActorSheet { const obj = { type: "talent", gruppe: talentGruppe, - name: talentObjekt.name, - taw: "" + taw, - tawPath: `system.talente.${index}.taw`, + name: item.name, + taw: "" + item.system.taw, + tawPath: `system.items.${index}.taw`, werte, rollEigenschaft1: werte[0].value, rollEigenschaft2: werte[1].value, @@ -84,9 +74,8 @@ export class CharacterSheet extends ActorSheet { context.skills[talentGruppe].push(obj); context.flatSkills.push(obj); } - } - }) - } + } + ); } #addAdvantagesToContext(context) { @@ -298,88 +287,40 @@ export class CharacterSheet extends ActorSheet { } - async #handleDroppedSkill(actor, data) { - let alreadyInSet = false; - let previousTaw = 0; - const id = foundry.utils.parseUuid(data.uuid).id; - - const item = (await actor.createEmbeddedDocuments('Item', [await game.items.get(id)]))[0] - - actor.system.talente.forEach(({taw, talent}) => { - if (talent) { - if (talent._id === item._id) { - alreadyInSet = talent; - previousTaw = taw; - } + #handleDroppedSkill(actor, skill) { + const array = Array.from(actor.items); + for ( let i = 0; i < array.length; i++ ) { + if (array[i].name === skill.name) { + return false; } - }) - const myContent = `TaW: `; - new Dialog({ - title: `Talent ${item.name} ${alreadyInSet?'ersetzen':'hinzufügen'}`, - content: myContent, - buttons: { - button1: { - label: "hinzufügen", - callback: (html) => myCallback(html), - icon: `` - } - } - }).render(true); - - async function myCallback(html) { - const taw = html.find("input#taw").val(); - - let index = actor.system.talente.findIndex( predicate => predicate.talent && predicate.talent._id === alreadyInSet._id ) - let sorted = []; - if (alreadyInSet) { - actor.system.talente[index].taw = taw; - sorted = actor.system.talente; - - } else { - const newItem = { - taw: taw, - talent: {_id: item._id, name: item.name} - } - console.log(newItem, await game.items.get(item._id)) - sorted = [newItem, ...actor.system.talente].sort((a, b) => { - - return a.talent.name.localeCompare(b.talent.name) - } - ); - } - - const serialised = sorted.map(({taw, talent}) => { - return { - taw: taw, - talent: talent._id - } - }); - - await actor.update({ - system: { - talente: [ - - ...serialised - ] - } - }); - ui.notifications.info(`Talent ${item.name} auf TaW ${taw} hinzugefügt`); - } } + static getElementByName(collection, id) { + const array = Array.from(collection); + for (const element of array) { + if (element._id === id) { + return element; + } + } + } + static onDroppedData(actor, characterSheet, data) { - const item = game.items.get(foundry.utils.parseUuid(data.uuid).id) - - switch (item.type) { + const uuid = foundry.utils.parseUuid(data.uuid); + const collection = uuid.collection.index ?? uuid.collection; + const document = CharacterSheet.getElementByName(collection, uuid.id); + const { + name, + type + } = document + console.log(name, type) + switch (type) { case "Skill": - characterSheet.#handleDroppedSkill(actor, data); + return characterSheet.#handleDroppedSkill(actor, document); // on false cancel this whole operation default: - console.log(item, item.type); + return false; } - // maybe dont - actor.items.clear() } } diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index e7681a07..241aeef7 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -101,6 +101,22 @@ function calculateBirthdate(json) { return `${day}. ${month} ${year} BF` } +function mapSkills(rawJson) { + 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) + } + } + return talents +} + /** * parses a json into a fitting character-json * @param rawJson the json parsed from the Helden-Software XML @@ -248,19 +264,8 @@ function mapRawJson(rawJson) { } 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 + + json.talente = mapSkills(rawJson) let spells = [] /*for (let spell in held.zauberliste.zauber) { spell = held.zauberliste.zauber[spell] @@ -337,4 +342,4 @@ Hooks.on("getActorContextOptions", (application, menuItems) => { actor.import() } }) -}) \ No newline at end of file +}) From 21479ce0826a446237ce3b64338fb4fa17564c90 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 2 Oct 2025 17:45:52 +0200 Subject: [PATCH 3/6] Updates Rollables (Attributes, Skills) to include a ContextMenu to delete or adjust their values. Also added the capability to open SkillsSheets. --- src/module/sheets/characterSheet.mjs | 72 ++++++++++++++++++- src/style/_rollable.scss | 5 +- src/templates/item/item-skill-sheet.hbs | 8 ++- src/templates/ui/partial-attribute-button.hbs | 4 +- src/templates/ui/partial-rollable-button.hbs | 6 +- 5 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 9bbbf59d..73f24e17 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -69,7 +69,8 @@ export class CharacterSheet extends ActorSheet { eigenschaft1: werte[0].name, eigenschaft2: werte[1].name, eigenschaft3: werte[2].name, - probe: `(${eigenschaften.join("/")})` + probe: `(${eigenschaften.join("/")})`, + id: item._id, }; context.skills[talentGruppe].push(obj); context.flatSkills.push(obj); @@ -123,7 +124,7 @@ export class CharacterSheet extends ActorSheet { }, { eigenschaft: "ch", - name: "IN", + name: "CH", tooltip: "Charisma", wert: actorData.system.attribute.ch.aktuell ?? 0, }, @@ -147,7 +148,7 @@ export class CharacterSheet extends ActorSheet { }, { eigenschaft: "kk", - name: "KO", + name: "KK", tooltip: "Körperkraft", wert: actorData.system.attribute.kk.aktuell ?? 0, }, @@ -261,6 +262,43 @@ export class CharacterSheet extends ActorSheet { } } + _onOpenSkill(documentId) { + console.log(this.object.items.get(documentId).sheet); + this.object.items.get(documentId).sheet.render(true) + } + + showAdjustAttributeDialog(attributeName, attributeField, previousValue) { + const thisActor = this; + const myContent = ` + Value: + + `; + + function updateAttribute(html) { + const value = html.find("input#attributeValue").val(); + const attribute = {} + attribute[attributeField.toLowerCase()] = { + aktuell: value + } + thisActor.object.update({ system: { attribute }}) + } + + new Dialog({ + title: `${attributeName} ändern auf`, + content: myContent, + buttons: { + button1: { + label: "Ändern", + callback: (html) => { + updateAttribute(html) + }, + icon: `` + } + } + }).render(true); + + } + activateListeners(html) { super.activateListeners(html); @@ -276,6 +314,34 @@ export class CharacterSheet extends ActorSheet { this._onRoll(evt); }); + html.on('click', '.talent .name', (evt) => { + this._onOpenSkill(evt.target.dataset.id); + evt.stopPropagation(); + }) + + new ContextMenu(html, '.talent.rollable', [ + { + name: "Entfernen", + icon: '', + callback: (event) => { + this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) + }, + condition: () => true + } + ]); + + + new ContextMenu(html, '.attribute.rollable', [ + { + name: "Anpassen", + icon: '', + callback: (event) => { + this.showAdjustAttributeDialog(event[0].dataset.name, event[0].dataset.label, event[0].dataset.value) + }, + condition: () => true + } + ]); + let handler = ev => this._onDragStart(ev); // Find all items on the character sheet. diff --git a/src/style/_rollable.scss b/src/style/_rollable.scss index 40c2d4fb..d0e71cf2 100644 --- a/src/style/_rollable.scss +++ b/src/style/_rollable.scss @@ -24,13 +24,13 @@ $rollable_colours: ( height: 32px; position: relative; margin: 4px; - z-index: 2; .die { width: 32px; height: 32px; display: inline-block; position: relative; + z-index: 1; .border { fill: #0000; @@ -64,7 +64,6 @@ $rollable_colours: ( left: 16px; top: 0; height: 32px; - z-index: -1; padding-left: 24px; span.name { @@ -205,4 +204,4 @@ $rollable_colours: ( @include coloring("Gesellschaft"); @include coloring("Wissen"); @include coloring("Sprachen"); -@include coloring("Handwerk"); \ No newline at end of file +@include coloring("Handwerk"); diff --git a/src/templates/item/item-skill-sheet.hbs b/src/templates/item/item-skill-sheet.hbs index 89449c4f..22cd7fd3 100644 --- a/src/templates/item/item-skill-sheet.hbs +++ b/src/templates/item/item-skill-sheet.hbs @@ -17,6 +17,12 @@
+
+ +
    - {{#each items}} -
  • {{this.name}}
  • + {{#each this.advantages}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • {{/each}}
@@ -161,4 +161,4 @@
- \ No newline at end of file + diff --git a/src/templates/item/item-advantage-sheet.hbs b/src/templates/item/item-advantage-sheet.hbs index 7902b570..d50d00ce 100644 --- a/src/templates/item/item-advantage-sheet.hbs +++ b/src/templates/item/item-advantage-sheet.hbs @@ -8,7 +8,7 @@ {{!-- Sheet Body --}}
-
{{json}}
+
{{json}}
- \ No newline at end of file + diff --git a/src/templates/ui/partial-advantage-button.hbs b/src/templates/ui/partial-advantage-button.hbs new file mode 100644 index 00000000..8e1ff713 --- /dev/null +++ b/src/templates/ui/partial-advantage-button.hbs @@ -0,0 +1,3 @@ +
+ {{this.name}} +
diff --git a/src/templates/ui/partial-rollable-button.hbs b/src/templates/ui/partial-rollable-button.hbs index 3764e086..9d2aa61e 100644 --- a/src/templates/ui/partial-rollable-button.hbs +++ b/src/templates/ui/partial-rollable-button.hbs @@ -1,4 +1,4 @@ -
+
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} From b6814c9f74bb0ee6aa7e0001a350a1bbe5922ed7 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 2 Oct 2025 20:28:31 +0200 Subject: [PATCH 5/6] Repairs XML-Import for SKills/Talents --- src/module/documents/character.mjs | 106 --------------------------- src/module/xml-import/xml-import.mjs | 35 +++++---- 2 files changed, 21 insertions(+), 120 deletions(-) diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index fbea8dc0..e692fb6a 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -34,110 +34,4 @@ export class Character extends Actor { console.log(data); return data; } - - - static onDroppedData(character, characterSheet, uuid) { - - } - - - async addSkillFromCompendiumByNameToActor(talentName, actor) { - const compendiumOfSkills = game.packs.get('DSA_4-1.talente-brw'); - const talentId = compendiumOfSkills.index.find( skill => skill.name === talentName) - let talentObject = {} - const talent = await compendiumOfSkills.getDocument(talentId); - try { - const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [talent]))[0] - if (embeddedDocument.type === "Skill") { - if (talent) { - talentObject = { - taw: 0, - talent: embeddedDocument.id, - } - } - } - } catch (error) { - console.error(`${talentName} not found in items`, error) - } - await actor.update({system: { talente: talentObject, ...actor.system.talente}}) - } - - /** - * Adds base skills according to the BRW to the given actor - * @param actor - * @returns {Promise} - */ - async #createBaseSkills(actor) { - 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 => { - - this.addSkillFromCompendiumByNameToActor( - talentName, - ) - }) - - await actor.update({system: { talente: talente}}) - } - - /** - * Sets the attributes of the given actor to their default values - * @param actor - * @returns {Promise} - */ - async #setBaseAttributes(actor) { - const startEigenschaften = { - "mu": { - start: 10, - aktuell: 10, - mod: 0 - }, - "kl": { - start: 10, - aktuell: 10, - mod: 0 - }, - "in": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ch": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ff": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ge": { - start: 10, - aktuell: 10, - mod: 0 - }, - "ko": { - start: 10, - aktuell: 10, - mod: 0 - }, - "kk": { - start: 10, - aktuell: 10, - mod: 0 - } - } - - await actor.update({system: {attribute: startEigenschaften}}) - } - } diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index 241aeef7..18c70fc7 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -27,7 +27,7 @@ export async function importCharacter(actorId, file) { let dom = domParser.parseFromString(xmlString, 'application/xml') let rawJson = getJsonFromXML(dom) - let characterJson = mapRawJson(rawJson) + let characterJson = mapRawJson(actor, rawJson) actor.update(characterJson) } @@ -70,6 +70,22 @@ function getJsonFromXML(dom) { return jsonResult; } +async function addSkillFromCompendiumByNameToActor(talentName, taw, actor) { + const compendiumOfSkills = game.packs.get('DSA_4-1.talente-brw'); + const talentId = compendiumOfSkills.index.find( skill => skill.name === talentName) + if (talentId) { + + const talent = await compendiumOfSkills.getDocument(talentId._id); + + try { + const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [talent]))[0] + embeddedDocument.update({system: {taw: taw}}); + } catch (error) { + console.error(`${talentName} not found in items`, error) + } + } +} + /** * gets the text content of a file * @param file the file with the desired content @@ -101,20 +117,11 @@ function calculateBirthdate(json) { return `${day}. ${month} ${year} BF` } -function mapSkills(rawJson) { - let talents = [] +function mapSkills(actor, held) { 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) - } + addSkillFromCompendiumByNameToActor(talent.name, talent.value, actor) } - return talents } /** @@ -122,7 +129,7 @@ function mapSkills(rawJson) { * @param rawJson the json parsed from the Helden-Software XML * @returns {{}} a json representation of the character */ -function mapRawJson(rawJson) { +function mapRawJson(actor, rawJson) { let json = {} let held = rawJson.helden.held; json.name = held.name @@ -265,7 +272,7 @@ function mapRawJson(rawJson) { json.sonderfertigkeiten = specialAbilities json.liturgien = liturgies - json.talente = mapSkills(rawJson) + mapSkills(actor, held) let spells = [] /*for (let spell in held.zauberliste.zauber) { spell = held.zauberliste.zauber[spell] From 41045cb4829ed7ddc44914728dfd7363a6511021 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 2 Oct 2025 20:43:50 +0200 Subject: [PATCH 6/6] Repairs XML-Import for Advantages/Vornachteile --- src/module/xml-import/xml-import.mjs | 36 ++++++++++++++++++---------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index 18c70fc7..5d9af9b6 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -86,6 +86,22 @@ async function addSkillFromCompendiumByNameToActor(talentName, taw, actor) { } } +async function addAdvantageFromCompendiumByNameToActor(advantageName, advantageValue, actor) { + const compendiumOfAdvantages = game.packs.get('DSA_4-1.Advantage'); + const advantageId = compendiumOfAdvantages.index.find( skill => skill.name === advantageName) + if (advantageId) { + + const advantage = await compendiumOfAdvantages.getDocument(advantageId._id); + + try { + const embeddedDocument = (await actor.createEmbeddedDocuments('Item', [advantage]))[0] + embeddedDocument.update({system: {value: advantageValue}}); + } catch (error) { + console.error(`${advantageName} not found in items`, error) + } + } +} + /** * gets the text content of a file * @param file the file with the desired content @@ -124,6 +140,13 @@ function mapSkills(actor, held) { } } +function mapAdvantages(actor, held) { + for (let advantage in held.vt.vorteil) { + advantage = held.vt.vorteil[advantage] + addAdvantageFromCompendiumByNameToActor(advantage.name, advantage.value, actor) + } +} + /** * parses a json into a fitting character-json * @param rawJson the json parsed from the Helden-Software XML @@ -224,18 +247,7 @@ function mapRawJson(actor, rawJson) { 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 + mapAdvantages(actor, held) let specialAbilities = [] let liturgies = [] for (let specialAbility in held.sf.sonderfertigkeit) {