From 1afdd483e6ae6a2e8bb18fb88af9380d05b9cf35 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 2 Oct 2025 16:52:56 +0200 Subject: [PATCH] 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 +})