From 64ae1b44b51a6c6b9131fadec716f03442bb109c Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 15:50:27 +0200 Subject: [PATCH 01/40] migrates Skill sheet to DocumentV2 --- src/module/sheets/skillSheet.mjs | 88 ++++++++++------- src/style/_richtext-editor.scss | 3 + .../{_talent-sheet.scss => _skill-sheet.scss} | 10 +- src/style/_tabs.scss | 60 +++++++++++- src/style/styles.scss | 3 +- src/templates/item/item-skill-sheet.hbs | 97 ------------------- src/templates/item/skill/main-sheet.hbs | 14 +++ src/templates/item/skill/tab-description.hbs | 32 ++++++ src/templates/item/skill/tab-meta.hbs | 68 +++++++++++++ 9 files changed, 237 insertions(+), 138 deletions(-) create mode 100644 src/style/_richtext-editor.scss rename src/style/{_talent-sheet.scss => _skill-sheet.scss} (91%) delete mode 100644 src/templates/item/item-skill-sheet.hbs create mode 100644 src/templates/item/skill/main-sheet.hbs create mode 100644 src/templates/item/skill/tab-description.hbs create mode 100644 src/templates/item/skill/tab-meta.hbs diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index 6f72b3c3..b08807af 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -1,35 +1,64 @@ -export class SkillSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'skill'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'skill'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SkillSheet.#onSubmitForm + } + } + + // MIGRATE to tabs + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'description', group: 'sheet', label: 'Beschreibung'}, ], - }); + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/skill/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/skill/tab-meta.hbs` + }, + description: { + template: `systems/DSA_4-1/templates/item/skill/tab-description.hbs` + } + } + + /** + * Handle form submission + * @this {MyClass} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-skill-sheet.hbs`; - } + async _prepareContext(options) { - /** @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(); + const context = await super._prepareContext(options) // Use a safe clone of the actor data for further operations. - const skillData = context.data; + const skillData = context.document; // Add the actor's data to context.data for easier access, as well as flags. context.system = skillData.system; @@ -48,18 +77,9 @@ export class SkillSheet extends foundry.appv1.sheets.ItemSheet { context.isCombat = context.system.gruppe === "Kampf" context.isTalent = context.system.gruppe !== "Kampf" context.isLanguage = context.system.gruppe === "Sprachen" || context.system.gruppe === "Schriften" - context.hasRequirement = context.system.voraussetzung.talent != null + context.hasRequirement = context.system.voraussetzung?.talent != null ?? false return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - - } - } - } \ No newline at end of file diff --git a/src/style/_richtext-editor.scss b/src/style/_richtext-editor.scss new file mode 100644 index 00000000..4a2f4c21 --- /dev/null +++ b/src/style/_richtext-editor.scss @@ -0,0 +1,3 @@ +.editor.prosemirror.active, .editor.prosemirror.inactive { + flex: 1; +} diff --git a/src/style/_talent-sheet.scss b/src/style/_skill-sheet.scss similarity index 91% rename from src/style/_talent-sheet.scss rename to src/style/_skill-sheet.scss index 0cfc8857..211e3949 100644 --- a/src/style/_talent-sheet.scss +++ b/src/style/_skill-sheet.scss @@ -1,6 +1,6 @@ .sheet.item.skill { - .tab.meta.active { + .meta-details { display: grid; grid-template-areas: @@ -8,9 +8,7 @@ "taw statistics ebe" "language language language" "attack attack attack"; - - gap: 8px; - margin: 8px; + height: unset; .category { grid-area: category; @@ -48,4 +46,8 @@ } + .description-details { + + } + } diff --git a/src/style/_tabs.scss b/src/style/_tabs.scss index 7f872530..a0a5676a 100644 --- a/src/style/_tabs.scss +++ b/src/style/_tabs.scss @@ -10,7 +10,7 @@ display: flow; border-top: unset; border-bottom: unset; - margin-bottom: 9px; + margin-bottom: 0; a.item[data-tab] { @@ -25,7 +25,6 @@ background: assets.$tab-background; position: relative; z-index: 2; - } } @@ -46,3 +45,60 @@ } } + +// Tabs v2 + +.sheet-tabs { + + position: relative; + display: flow; + border-top: unset; + border-bottom: unset; + margin-bottom: 0; + + a[data-action="tab"] { + + background-color: colours.$tab-inactive-background-color; + display: inline-block; + height: 32px; + line-height: 32px; + vertical-align: middle; + padding: 0 16px; + + span { + + } + + &.active { + + border-left: numbers.$tab-border-width solid colours.$tab-border-color; + border-top: numbers.$tab-border-width solid colours.$tab-border-color; + border-right: numbers.$tab-border-width solid colours.$tab-border-color; + border-bottom: 0; + top: numbers.$tab-border-width*2; + background: assets.$tab-background; + position: relative; + z-index: 2; + + span { + + } + + } + + } +} + +section.tab { + border: numbers.$tab-border-width solid colours.$tab-border-color; + background: assets.$tab-pane-background; + flex: 1; + + & > div { + display: flex; + flex-direction: column; + height: 100%; + gap: 8px; + padding: 8px; + } +} \ No newline at end of file diff --git a/src/style/styles.scss b/src/style/styles.scss index e30542c1..ea91cf78 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -11,6 +11,7 @@ @use "_player-action"; @use "_modify-liturgy"; @use "_liturgy-banner"; -@use "_talent-sheet"; +@use "_skill-sheet"; @use "_active-effect-sheet"; @use "_advantage-sheet"; +@use "_richtext-editor"; \ No newline at end of file diff --git a/src/templates/item/item-skill-sheet.hbs b/src/templates/item/item-skill-sheet.hbs deleted file mode 100644 index 72ad0f8a..00000000 --- a/src/templates/item/item-skill-sheet.hbs +++ /dev/null @@ -1,97 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- -
-
- -
- {{#if isTalent}} -
- -
- -
-
-
- -
-
- {{/if}} -
- -
- {{#if isLanguage}} -
- -
- {{/if}} - {{#if isCombat}} -
-
- -
-
- -
-
- {{/if}} - -
-
-
- - {{editor system.talent target="system.talent" button=true owner=owner editable=editable}} -
- {{#if hasRequirement}} -
- -
    - {{#each system.voraussetzung}} -
  • - - -
  • - {{/each}} -
-
- {{/if}} -
- - -
-
diff --git a/src/templates/item/skill/main-sheet.hbs b/src/templates/item/skill/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/skill/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/skill/tab-description.hbs b/src/templates/item/skill/tab-description.hbs new file mode 100644 index 00000000..960cc9a0 --- /dev/null +++ b/src/templates/item/skill/tab-description.hbs @@ -0,0 +1,32 @@ +{{!-- Individual Tab Template --}} +
+ {{!-- Tab content here --}} +
+ + + + {{{system.talent}}} + + + {{#if hasRequirement}} +
+ +
    + {{#each system.voraussetzung}} +
  • + + +
  • + {{/each}} +
+
+ {{/if}} +
+
diff --git a/src/templates/item/skill/tab-meta.hbs b/src/templates/item/skill/tab-meta.hbs new file mode 100644 index 00000000..5d08d3f9 --- /dev/null +++ b/src/templates/item/skill/tab-meta.hbs @@ -0,0 +1,68 @@ +{{!-- Individual Tab Template --}} +
+ {{!-- Tab content here --}} +
+
+ +
+
+ +
+ {{#if isTalent}} +
+ +
+ +
+
+
+ +
+
+ {{/if}} +
+ +
+ {{#if isLanguage}} +
+ +
+ {{/if}} + {{#if isCombat}} +
+
+ +
+
+ +
+
+ {{/if}} +
+
\ No newline at end of file -- 2.43.0 From 232347aae53c2193b61231cc5a6e5b2443c74cdd Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 16:24:35 +0200 Subject: [PATCH 02/40] fixes typos and stuff --- src/module/sheets/skillSheet.mjs | 14 ++++---------- src/templates/item/skill/tab-meta.hbs | 2 +- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index b08807af..cf1e2b4d 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -14,8 +14,6 @@ export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { } } - // MIGRATE to tabs - static TABS = { sheet: { tabs: [ @@ -56,11 +54,8 @@ export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { async _prepareContext(options) { const context = await super._prepareContext(options) - - // Use a safe clone of the actor data for further operations. const skillData = context.document; - // Add the actor's data to context.data for easier access, as well as flags. context.system = skillData.system; context.flags = skillData.flags; context.categoryOptions = { @@ -74,12 +69,11 @@ export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { Handwerk: "Handwerk" } - context.isCombat = context.system.gruppe === "Kampf" - context.isTalent = context.system.gruppe !== "Kampf" - context.isLanguage = context.system.gruppe === "Sprachen" || context.system.gruppe === "Schriften" - context.hasRequirement = context.system.voraussetzung?.talent != null ?? false + context.isCombat = skillData.gruppe === "Kampf" + context.isTalent = skillData.gruppe !== "Kampf" + context.isLanguage = skillData.gruppe === "Sprachen" || skillData.gruppe === "Schriften" + context.hasRequirement = skillData.voraussetzung?.talent != null ?? false return context; } - } \ No newline at end of file diff --git a/src/templates/item/skill/tab-meta.hbs b/src/templates/item/skill/tab-meta.hbs index 5d08d3f9..ebc0cf24 100644 --- a/src/templates/item/skill/tab-meta.hbs +++ b/src/templates/item/skill/tab-meta.hbs @@ -45,7 +45,7 @@ {{#if isLanguage}}
-
-- 2.43.0 From 3869982927c99deeafb8a76f0740bcc063991fc5 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 16:24:51 +0200 Subject: [PATCH 03/40] migrates advantages to DocumentV2 --- src/main.mjs | 4 +- src/module/sheets/advantageSheet.mjs | 65 +++++++++++++++++++ src/module/sheets/vornachteilSheet.mjs | 56 ---------------- src/templates/item/advantage/main-sheet.hbs | 14 ++++ .../item/advantage/tab-advantage.hbs | 33 ++++++++++ 5 files changed, 114 insertions(+), 58 deletions(-) create mode 100644 src/module/sheets/advantageSheet.mjs delete mode 100644 src/module/sheets/vornachteilSheet.mjs create mode 100644 src/templates/item/advantage/main-sheet.hbs create mode 100644 src/templates/item/advantage/tab-advantage.hbs diff --git a/src/main.mjs b/src/main.mjs index fa69514f..a2c0ed6a 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -6,7 +6,7 @@ import {SpellDataModel} from "./module/data/spell.mjs"; 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 {AdvantageSheet} from "./module/sheets/advantageSheet.mjs"; import {GroupDataModel} from "./module/data/group.mjs"; import {GroupSheet} from "./module/sheets/groupSheet.mjs"; import {EquipmentDataModel} from "./module/data/equipment.mjs"; @@ -106,7 +106,7 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.SpellLabels.Item', }); - foundry.documents.collections.Items.registerSheet('dsa41.advantage', VornachteilSheet, { + foundry.documents.collections.Items.registerSheet('dsa41.advantage', AdvantageSheet, { types: ["Advantage"], makeDefault: true, label: 'DSA41.VornachteilLabels.Item' diff --git a/src/module/sheets/advantageSheet.mjs b/src/module/sheets/advantageSheet.mjs new file mode 100644 index 00000000..eff15fb4 --- /dev/null +++ b/src/module/sheets/advantageSheet.mjs @@ -0,0 +1,65 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class AdvantageSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'advantage'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: AdvantageSheet.#onSubmitForm + } + } + + static TABS = { + sheet: { + tabs: [ + {id: 'advantage', group: 'sheet', label: 'Vorteil'}, + ], + initial: 'advantage' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/advantage/main-sheet.hbs` + }, + advantage: { + template: `systems/DSA_4-1/templates/item/advantage/tab-advantage.hbs` + } + } + + /** + * Handle form submission + * @this {MyClass} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + const advantageData = context.document; + + context.system = advantageData.system; + context.flags = context.system.flags; + context.hasChoices = context.system.auswahl.length > 0; + context.choices = {} + context.system.auswahl.forEach(a => { + context.choices[a] = a + }) + context.hasModality = context.system.value != null + + return context; + } +} diff --git a/src/module/sheets/vornachteilSheet.mjs b/src/module/sheets/vornachteilSheet.mjs deleted file mode 100644 index 6a9278c6..00000000 --- a/src/module/sheets/vornachteilSheet.mjs +++ /dev/null @@ -1,56 +0,0 @@ -export class VornachteilSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'advantage'], - width: 520, - height: 480, - tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, - ], - }); - } - - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-advantage-sheet.hbs`; - } - - /** @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. - const advantageData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = advantageData.system; - context.flags = advantageData.flags; - context.hasChoices = context.system.auswahl.length > 0; - context.choices = {} - context.system.auswahl.forEach(a => { - context.choices[a] = a - }) - context.hasModality = context.system.value != null - - return context; - } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - - } - } - -} diff --git a/src/templates/item/advantage/main-sheet.hbs b/src/templates/item/advantage/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/advantage/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/advantage/tab-advantage.hbs b/src/templates/item/advantage/tab-advantage.hbs new file mode 100644 index 00000000..2b11c313 --- /dev/null +++ b/src/templates/item/advantage/tab-advantage.hbs @@ -0,0 +1,33 @@ +
+
+ + + +
+ {{#if hasModality}} +
+ + {{#if hasChoices}} + + {{else}} + + {{/if}} +
+ {{/if}} +
+ + + {{{ system.description}}} + +
+ +
\ No newline at end of file -- 2.43.0 From 343d18056848c52827cd552f76c833974fc16ff7 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 16:25:11 +0200 Subject: [PATCH 04/40] removes old sheet --- src/templates/item/item-advantage-sheet.hbs | 35 --------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/templates/item/item-advantage-sheet.hbs diff --git a/src/templates/item/item-advantage-sheet.hbs b/src/templates/item/item-advantage-sheet.hbs deleted file mode 100644 index cf02f991..00000000 --- a/src/templates/item/item-advantage-sheet.hbs +++ /dev/null @@ -1,35 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
-
- - - -
- {{#if hasModality}} -
- - {{#if hasChoices}} - - {{else}} - - {{/if}} -
- {{/if}} -
- - {{editor system.description target="system.description" button=true owner=owner editable=editable}} -
- -
-
-
-- 2.43.0 From 3f5ef8fbd7cba429b2a54478757efd50d578e049 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 19:55:13 +0200 Subject: [PATCH 05/40] migrates spells and equipment to DocumentV2 --- src/main.mjs | 4 +- src/module/sheets/advantageSheet.mjs | 2 +- src/module/sheets/equipmentSheet.mjs | 240 ++++++++++++++---- src/module/sheets/skillSheet.mjs | 2 +- src/module/sheets/spellSheet.mjs | 96 ++++--- src/style/_equipment-sheet.scss | 28 +- src/templates/item/equipment/main-sheet.hbs | 14 + src/templates/item/equipment/tab-armor.hbs | 37 +++ .../item/equipment/tab-container.hbs | 7 + src/templates/item/equipment/tab-melee.hbs | 43 ++++ src/templates/item/equipment/tab-meta.hbs | 40 +++ src/templates/item/equipment/tab-ranged.hbs | 32 +++ src/templates/item/item-equipment-sheet.hbs | 164 ------------ src/templates/item/spell/main-sheet.hbs | 14 + src/templates/item/spell/tab-commonality.hbs | 21 ++ src/templates/item/spell/tab-meta.hbs | 48 ++++ src/templates/item/spell/tab-variants.hbs | 26 ++ 17 files changed, 543 insertions(+), 275 deletions(-) create mode 100644 src/templates/item/equipment/main-sheet.hbs create mode 100644 src/templates/item/equipment/tab-armor.hbs create mode 100644 src/templates/item/equipment/tab-container.hbs create mode 100644 src/templates/item/equipment/tab-melee.hbs create mode 100644 src/templates/item/equipment/tab-meta.hbs create mode 100644 src/templates/item/equipment/tab-ranged.hbs delete mode 100644 src/templates/item/item-equipment-sheet.hbs create mode 100644 src/templates/item/spell/main-sheet.hbs create mode 100644 src/templates/item/spell/tab-commonality.hbs create mode 100644 src/templates/item/spell/tab-meta.hbs create mode 100644 src/templates/item/spell/tab-variants.hbs diff --git a/src/main.mjs b/src/main.mjs index a2c0ed6a..942b340e 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -10,7 +10,7 @@ import {AdvantageSheet} from "./module/sheets/advantageSheet.mjs"; import {GroupDataModel} from "./module/data/group.mjs"; import {GroupSheet} from "./module/sheets/groupSheet.mjs"; import {EquipmentDataModel} from "./module/data/equipment.mjs"; -import {AusruestungSheet} from "./module/sheets/equipmentSheet.mjs"; +import {EquipmentSheet} from "./module/sheets/equipmentSheet.mjs"; import {CreatureDataModel} from "./module/data/creature.mjs"; import {CreatureSheet} from "./module/sheets/creatureSheet.mjs"; import {LiturgySheet} from "./module/sheets/liturgySheet.mjs"; @@ -111,7 +111,7 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.VornachteilLabels.Item' }) - foundry.documents.collections.Items.registerSheet('dsa41.equipment', AusruestungSheet, { + foundry.documents.collections.Items.registerSheet('dsa41.equipment', EquipmentSheet, { types: ["Equipment"], makeDefault: false, label: 'DSA41.AusruestungLabels.Item' diff --git a/src/module/sheets/advantageSheet.mjs b/src/module/sheets/advantageSheet.mjs index eff15fb4..62696148 100644 --- a/src/module/sheets/advantageSheet.mjs +++ b/src/module/sheets/advantageSheet.mjs @@ -35,7 +35,7 @@ export class AdvantageSheet extends HandlebarsApplicationMixin(DocumentSheetV2) /** * Handle form submission - * @this {MyClass} + * @this {AdvantageSheet} * @param {SubmitEvent} event * @param {HTMLFormElement} form * @param {FormDataExtended} formData diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs index d3d769f8..2e12f378 100644 --- a/src/module/sheets/equipmentSheet.mjs +++ b/src/module/sheets/equipmentSheet.mjs @@ -1,42 +1,121 @@ -export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'equipment'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +/** + * @typedef ApplicationTab + * @property {string} id + * @property {string} group + * @property {boolean} active + * @property {string} cssClass + * @property {string} [label] + * @property {string} [icon] + * @property {string} [tooltip] + */ + +export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 640, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'equipment'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: EquipmentSheet.#onSubmitForm + }, + actions: { + editImage: + DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage + + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + // Additional Tabs are added based on the nature of this item + ], - }); + initial: 'meta' + } } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-equipment-sheet.hbs`; + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/equipment/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/equipment/tab-meta.hbs` + }, + melee: { + template: `systems/DSA_4-1/templates/item/equipment/tab-melee.hbs` + }, + ranged: { + template: `systems/DSA_4-1/templates/item/equipment/tab-ranged.hbs` + }, + container: { + template: `systems/DSA_4-1/templates/item/equipment/tab-container.hbs` + }, + armor: { + template: `systems/DSA_4-1/templates/item/equipment/tab-armor.hbs` + } } - /** @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(); + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() - // Use a safe clone of the actor data for further operations. - const equipmentData = context.data; + let normalisedFormData = {} - // Add the actor's data to context.data for easier access, as well as flags. - context.system = equipmentData.system; - context.flags = equipmentData.flags; + Object.entries(formData.object).forEach(([key, value]) => { + if (Array.isArray(value)) { + normalisedFormData[key] = value[0] + } else { + normalisedFormData[key] = value + } + }) - context.quantity = context.system.quantity; - context.description = context.system.description; + await this.document.update(normalisedFormData) // Note: formData.object + } + + async _preparePartContext(partId, context) { + switch (partId) { + case 'meta': + this.#prepareMetaContext(context) + break; + case 'melee': + this.#prepareMeleeContext(context) + break; + case 'ranged': + this.#prepareRangedContext(context) + break; + case 'container': + this.#prepareContainerContext(context) + break; + case 'armor': + this.#prepareArmorContext(context) + break; + } + context.tab = context.tabs[partId] + return context + } + + #prepareMetaContext(context) { + const equipmentData = context.document.system; + context.system = equipmentData; + context.quantity = equipmentData.quantity; + context.description = equipmentData.description; + context.name = context.document.name; + context.img = context.document.img; context.categoryAndOptions = { options: { @@ -46,23 +125,22 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { Behälter: "Behälter", Rüstung: "Rüstung", }, - entries: context.system.category, + entries: equipmentData.category, targetField: "category" }; - context.isMeleeWeapon = context.system.category.includes("Nahkampfwaffe"); - context.isRangedWeapon = context.system.category.includes("Fernkampfwaffe"); - context.isContainer = context.system.category.includes("Behälter"); - context.isArmor = context.system.category.includes("Rüstung"); - context.price = context.system.price; - context.weight = context.system.weight; + } + + #prepareMeleeContext(context) { + const equipmentData = context.document.system; + context.system = equipmentData; context.meleeSkillsAndOptions = { options: { "": "", Dolche: "Dolche", Fechtwaffen: "Fechtwaffen", - Säbel: "Säbel", + "Säbel": "Säbel", Schwerter: "Schwerter", - Anderthalbhänder: "Anderthalbhänder", + "Anderthalbhänder": "Anderthalbhänder", "Zweihandschwerter/-säbel": "Zweihandschwerter/-säbel", "Infanteriewaffen": "Infanteriewaffen", "Speere": "Speere", @@ -72,9 +150,13 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { "Kettenwaffen": "Kettenwaffen", "Raufen": "Raufen" }, - entries: context.system.meleeSkills, + entries: equipmentData.meleeSkills, targetField: "meleeSkills" } + } + + #prepareRangedContext(context) { + const equipmentData = context.document.system; context.rangedSkillsAndOptions = { options: { "": "", @@ -84,24 +166,86 @@ export class AusruestungSheet extends foundry.appv1.sheets.ItemSheet { "Armbrust": "Armbrust", "Bogen": "Bogen", }, - entries: context.system.rangedSkills, + entries: equipmentData.rangedSkills, targetField: "rangedSkills" } - return context; } - activateListeners(html) { - super.activateListeners(html); + #prepareContainerContext(context) { - html.on('change', '.array-editor select', (evt) => { + } + + #prepareArmorContext(context) { + + } + + /** + * Adds Tabs based on the items nature + * + * @param {String} tabGroup + * @private + */ + _prepareTabs(tabGroup) { + + const currentTabs = super._prepareTabs(tabGroup); + + const category = this.document.system.category + /** + * + * @type {[{ApplicationTab}]} + */ + let tabs = currentTabs; + + if (category.includes("Nahkampfwaffe")) { + tabs.melee = { + id: 'melee', group: tabGroup, label: 'Nahkampfwaffe' + } + } + if (category.includes("Fernkampfwaffe")) { + tabs.ranged = { + id: 'ranged', group: tabGroup, label: 'Fernkampfwaffe' + } + } + if (category.includes("Behälter")) { + tabs.container = { + id: 'container', group: tabGroup, label: 'Behälter' + } + } + if (category.includes("Rüstung")) { + tabs.armor = { + id: 'armor', group: tabGroup, label: 'Rüstung' + } + } + + return tabs + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options); + context.price = context.document.system.price + context.weight = context.document.system.weight + + return context + } + + /** + * Actions performed after any render of the Application. + * Post-render steps are not awaited by the render process. + * @param {ApplicationRenderContext} context Prepared context data + * @param {RenderOptions} options Provided render options + * @protected + */ + _onRender(context, options) { + this.element.querySelector('.array-editor select').addEventListener('change', (evt) => { const addingValue = evt.currentTarget.value; const fieldToTarget = evt.currentTarget.dataset.targetField; - const newSkills = [...this.object.system[fieldToTarget], addingValue]; + const newSkills = [...this.document.system[fieldToTarget], addingValue]; - this.object.update({system: {[fieldToTarget]: newSkills}}); + this.document.update({system: {[fieldToTarget]: newSkills}}); evt.currentTarget.value = ""; }) - } } diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index cf1e2b4d..07654deb 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -39,7 +39,7 @@ export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { /** * Handle form submission - * @this {MyClass} + * @this {SkillSheet} * @param {SubmitEvent} event * @param {HTMLFormElement} form * @param {FormDataExtended} formData diff --git a/src/module/sheets/spellSheet.mjs b/src/module/sheets/spellSheet.mjs index 3713a24b..2e793d9e 100644 --- a/src/module/sheets/spellSheet.mjs +++ b/src/module/sheets/spellSheet.mjs @@ -1,49 +1,69 @@ -export class SpellSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'spell'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpellSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'spell'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpellSheet.#onSubmitForm + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'variants', group: 'sheet', label: 'Varianten'}, + {id: 'commonality', group: 'sheet', label: 'Verbreitung'}, ], - }); + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/spell/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/item/spell/tab-meta.hbs` + }, + variants: { + template: `systems/DSA_4-1/templates/item/spell/tab-variants.hbs` + }, + commonality: { + template: `systems/DSA_4-1/templates/item/spell/tab-commonality.hbs` + } + } + + /** + * Handle form submission + * @this {SpellSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-spell-sheet.hbs`; - } + async _prepareContext(options) { + const context = await super._prepareContext(options); + const spellData = context.document; - /** @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. - const skillData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = skillData.system; - context.flags = skillData.flags; + context.system = spellData.system; + context.flags = spellData.flags; return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - } - } \ No newline at end of file diff --git a/src/style/_equipment-sheet.scss b/src/style/_equipment-sheet.scss index 80f041f0..859793e5 100644 --- a/src/style/_equipment-sheet.scss +++ b/src/style/_equipment-sheet.scss @@ -1,28 +1,15 @@ @use "./_colours"; @use "./_numbers"; -.app.window-app.dsa41.sheet.item.equipment { +.application.sheet.dsa41.item.equipment { - .sheet-body { + .tab.meta.active > div { - position: relative; - - .tab.active { - padding: 4px; - top: 0; - bottom: 0; - left: 0; - right: 0; - } - - .tab.meta.active { - - position: absolute; display: grid; grid-auto-columns: 1fr 1fr; grid-template-columns: 80px auto; - grid-template-rows: 24px 48px auto 48px; - gap: 0 0; + grid-template-rows: 32px 48px auto 48px; + gap: 8px; grid-template-areas: "category category" "quantity name" @@ -57,6 +44,7 @@ grid-area: bottomline; display: grid; grid-template-columns: repeat(2, 1fr); + gap: 8px; .named-value { position: relative; @@ -104,7 +92,7 @@ ul { list-style-type: none; - padding: 0; + padding: 0 32px 0 0; margin: 0; text-indent: 0; @@ -124,6 +112,7 @@ position: absolute; right: 0; top: 0; + width: 24px; } } @@ -153,7 +142,4 @@ } - - } - } diff --git a/src/templates/item/equipment/main-sheet.hbs b/src/templates/item/equipment/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/equipment/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-armor.hbs b/src/templates/item/equipment/tab-armor.hbs new file mode 100644 index 00000000..7bfcd6de --- /dev/null +++ b/src/templates/item/equipment/tab-armor.hbs @@ -0,0 +1,37 @@ +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-container.hbs b/src/templates/item/equipment/tab-container.hbs new file mode 100644 index 00000000..2a8282ef --- /dev/null +++ b/src/templates/item/equipment/tab-container.hbs @@ -0,0 +1,7 @@ +
+
+ Behälter Specs +
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-melee.hbs b/src/templates/item/equipment/tab-melee.hbs new file mode 100644 index 00000000..fcd7a83d --- /dev/null +++ b/src/templates/item/equipment/tab-melee.hbs @@ -0,0 +1,43 @@ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-meta.hbs b/src/templates/item/equipment/tab-meta.hbs new file mode 100644 index 00000000..1409724a --- /dev/null +++ b/src/templates/item/equipment/tab-meta.hbs @@ -0,0 +1,40 @@ +
+
+
+ {{name}} + +
+
+ +
+
+
+ + + {{{system.description}}} + +
+
+ + +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-ranged.hbs b/src/templates/item/equipment/tab-ranged.hbs new file mode 100644 index 00000000..4eb4f520 --- /dev/null +++ b/src/templates/item/equipment/tab-ranged.hbs @@ -0,0 +1,32 @@ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
\ No newline at end of file diff --git a/src/templates/item/item-equipment-sheet.hbs b/src/templates/item/item-equipment-sheet.hbs deleted file mode 100644 index c8334090..00000000 --- a/src/templates/item/item-equipment-sheet.hbs +++ /dev/null @@ -1,164 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- - -
-
- -
-
-
- - {{editor system.description target="system.description" button=true owner=owner editable=editable}} -
-
- - -
-
- - {{#if isMeleeWeapon}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} - {{#if isRangedWeapon}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} - {{#if isContainer}} -
- Behälter Specs -
- {{/if}} - {{#if isArmor}} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- {{/if}} -
-
diff --git a/src/templates/item/spell/main-sheet.hbs b/src/templates/item/spell/main-sheet.hbs new file mode 100644 index 00000000..21d661ee --- /dev/null +++ b/src/templates/item/spell/main-sheet.hbs @@ -0,0 +1,14 @@ +
+ {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-commonality.hbs b/src/templates/item/spell/tab-commonality.hbs new file mode 100644 index 00000000..351998d0 --- /dev/null +++ b/src/templates/item/spell/tab-commonality.hbs @@ -0,0 +1,21 @@ +
+ +
+ +
+
+ +
+
+ +
+ +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-meta.hbs b/src/templates/item/spell/tab-meta.hbs new file mode 100644 index 00000000..7dc4079b --- /dev/null +++ b/src/templates/item/spell/tab-meta.hbs @@ -0,0 +1,48 @@ +
+ +
+ +
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+ + +
\ No newline at end of file diff --git a/src/templates/item/spell/tab-variants.hbs b/src/templates/item/spell/tab-variants.hbs new file mode 100644 index 00000000..334d3786 --- /dev/null +++ b/src/templates/item/spell/tab-variants.hbs @@ -0,0 +1,26 @@ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+ +
\ No newline at end of file -- 2.43.0 From 962fc482a8ff7736429dbdf90e5727c01454c8cc Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 19:55:24 +0200 Subject: [PATCH 06/40] Removes old spell sheet --- src/templates/item/item-spell-sheet.hbs | 98 ------------------------- 1 file changed, 98 deletions(-) delete mode 100644 src/templates/item/item-spell-sheet.hbs diff --git a/src/templates/item/item-spell-sheet.hbs b/src/templates/item/item-spell-sheet.hbs deleted file mode 100644 index f2471a68..00000000 --- a/src/templates/item/item-spell-sheet.hbs +++ /dev/null @@ -1,98 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
- -
-
- -
-
-
- -
-
- -
-
- -
-
- -
- -
-
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
- -
-
- -
-
-- 2.43.0 From f505a233dfd2c30ccdd3f51ae8cc6b6c2b429128 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 20:10:52 +0200 Subject: [PATCH 07/40] Migrates Specialabilities and Liturgies to DocumentV2 --- src/main.mjs | 12 +-- src/module/sheets/liturgySheet.mjs | 84 ++++++++------- src/module/sheets/specialAbilitySheet.mjs | 101 ++++++++++-------- src/templates/item/item-liturgy-sheet.hbs | 14 --- src/templates/item/liturgy/main-sheet.hbs | 4 + src/templates/item/liturgy/tab-json.hbs | 8 ++ .../item/specialability/main-sheet.hbs | 4 + .../item/specialability/tab-json.hbs | 8 ++ 8 files changed, 134 insertions(+), 101 deletions(-) delete mode 100644 src/templates/item/item-liturgy-sheet.hbs create mode 100644 src/templates/item/liturgy/main-sheet.hbs create mode 100644 src/templates/item/liturgy/tab-json.hbs create mode 100644 src/templates/item/specialability/main-sheet.hbs create mode 100644 src/templates/item/specialability/tab-json.hbs diff --git a/src/main.mjs b/src/main.mjs index 942b340e..21a59bc2 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -117,20 +117,20 @@ Hooks.once("init", () => { label: 'DSA41.AusruestungLabels.Item' }) foundry.documents.collections.Items.registerSheet('dsa41.liturgy', LiturgySheet, { - types: ["SpecialAbility"], - makeDefault: true, - label: 'DSA41.SpecialAbilityLabels.Item' - }) - foundry.documents.collections.Items.registerSheet('dsa41.specialAbility', SpecialAbilitySheet, { types: ["Liturgy"], makeDefault: true, label: 'DSA41.LiturgyLabels.Item' }) + foundry.documents.collections.Items.registerSheet('dsa41.specialAbility', SpecialAbilitySheet, { + types: ["SpecialAbility"], + makeDefault: true, + label: 'DSA41.SpecialAbilityLabels.Item' + }) foundry.documents.collections.Items.registerSheet('dsa41.activeEffect', ActiveEffectSheet, { types: ['ActiveEffect'], makeDefault: true, - label: 'DSA41.ActiveEffectLabels.ActiveFfect' + label: 'DSA41.ActiveEffectLabels.ActiveEffect' }) game.settings.register('DSA_4-1', 'optional_trefferzonen', { diff --git a/src/module/sheets/liturgySheet.mjs b/src/module/sheets/liturgySheet.mjs index 3bb34124..d2e0f14e 100644 --- a/src/module/sheets/liturgySheet.mjs +++ b/src/module/sheets/liturgySheet.mjs @@ -1,50 +1,62 @@ -export class LiturgySheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'liturgy'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class LiturgySheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'liturgy'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: LiturgySheet.#onSubmitForm + }, + } + + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'json', group: 'sheet', label: 'JSON'}, ], - }); + initial: 'json' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/liturgy/main-sheet.hbs` + }, + json: { + template: `systems/DSA_4-1/templates/item/liturgy/tab-json.hbs` + }, + } + + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-liturgy-sheet.hbs`; - } + async _prepareContext(options) { + const context = await super._prepareContext(options); - /** @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(); + const liturgyData = context.document; - // Use a safe clone of the actor data for further operations. - const liturgyData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. context.system = liturgyData.system; context.flags = liturgyData.flags; context.json = JSON.stringify(liturgyData); return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (this.isEditable) { - - } - } - } diff --git a/src/module/sheets/specialAbilitySheet.mjs b/src/module/sheets/specialAbilitySheet.mjs index 533f1a8a..4828dbf2 100644 --- a/src/module/sheets/specialAbilitySheet.mjs +++ b/src/module/sheets/specialAbilitySheet.mjs @@ -1,51 +1,62 @@ -export class SpecialAbilitySheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'item', 'specialability'], - width: 520, - height: 480, +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'specialability'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpecialAbilitySheet.#onSubmitForm + }, + } + + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'json', group: 'sheet', label: 'JSON'}, ], - }); - } - - /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-special-ability-sheet.hbs`; - } - - /** @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. - const advantageData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = advantageData.system; - context.flags = advantageData.flags; - context.json = JSON.stringify(advantageData.system, null, 4); - - return context; - } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) { - + initial: 'json' } } + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/specialability/main-sheet.hbs` + }, + json: { + template: `systems/DSA_4-1/templates/item/specialability/tab-json.hbs` + }, + } + + /** + * Handle form submission + * @this {EquipmentSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + const context = await super._prepareContext(options); + + const specialabilityData = context.document; + + context.system = specialabilityData.system; + context.flags = specialabilityData.flags; + context.json = JSON.stringify(specialabilityData); + return context; + } + } diff --git a/src/templates/item/item-liturgy-sheet.hbs b/src/templates/item/item-liturgy-sheet.hbs deleted file mode 100644 index d50d00ce..00000000 --- a/src/templates/item/item-liturgy-sheet.hbs +++ /dev/null @@ -1,14 +0,0 @@ -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
-
{{json}}
-
-
-
diff --git a/src/templates/item/liturgy/main-sheet.hbs b/src/templates/item/liturgy/main-sheet.hbs new file mode 100644 index 00000000..38015a2f --- /dev/null +++ b/src/templates/item/liturgy/main-sheet.hbs @@ -0,0 +1,4 @@ +
+ + Alveranische Baustelle, bitte gehen Sie weiter, hier gibt es nichts zu sehen. +
\ No newline at end of file diff --git a/src/templates/item/liturgy/tab-json.hbs b/src/templates/item/liturgy/tab-json.hbs new file mode 100644 index 00000000..a4db94c6 --- /dev/null +++ b/src/templates/item/liturgy/tab-json.hbs @@ -0,0 +1,8 @@ +
+ +
{{json}}
+ +
+ diff --git a/src/templates/item/specialability/main-sheet.hbs b/src/templates/item/specialability/main-sheet.hbs new file mode 100644 index 00000000..fb0530ff --- /dev/null +++ b/src/templates/item/specialability/main-sheet.hbs @@ -0,0 +1,4 @@ +
+ + Sonderfertigkeiten bitte sei Besonders und Fertig +
\ No newline at end of file diff --git a/src/templates/item/specialability/tab-json.hbs b/src/templates/item/specialability/tab-json.hbs new file mode 100644 index 00000000..d9c5d89c --- /dev/null +++ b/src/templates/item/specialability/tab-json.hbs @@ -0,0 +1,8 @@ +
+ +
{{json}}
+ +
+ -- 2.43.0 From 7ea6b4a2e05a79fdb4ba06b5cf04a23999c794b2 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 20:19:59 +0200 Subject: [PATCH 08/40] Fixes styling of attack-statistics and visibility of different statistics base on the nature of the given skill --- src/module/sheets/skillSheet.mjs | 8 ++++---- src/style/_skill-sheet.scss | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/module/sheets/skillSheet.mjs b/src/module/sheets/skillSheet.mjs index 07654deb..3ea4f5d9 100644 --- a/src/module/sheets/skillSheet.mjs +++ b/src/module/sheets/skillSheet.mjs @@ -69,10 +69,10 @@ export class SkillSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { Handwerk: "Handwerk" } - context.isCombat = skillData.gruppe === "Kampf" - context.isTalent = skillData.gruppe !== "Kampf" - context.isLanguage = skillData.gruppe === "Sprachen" || skillData.gruppe === "Schriften" - context.hasRequirement = skillData.voraussetzung?.talent != null ?? false + context.isCombat = skillData.system.gruppe === "Kampf" + context.isTalent = skillData.system.gruppe !== "Kampf" + context.isLanguage = skillData.system.gruppe === "Sprachen" || skillData.system.gruppe === "Schriften" + context.hasRequirement = skillData.system.voraussetzung?.talent != null ?? false return context; } diff --git a/src/style/_skill-sheet.scss b/src/style/_skill-sheet.scss index 211e3949..f1e621e5 100644 --- a/src/style/_skill-sheet.scss +++ b/src/style/_skill-sheet.scss @@ -42,6 +42,7 @@ grid-area: attack; display: flex; flex-direction: row; + gap: 16px; } } -- 2.43.0 From 626474178d84ba5db94cbcb90dcdae1475093ce8 Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 21:02:56 +0200 Subject: [PATCH 09/40] migrates active effect to DocumentV2 --- src/module/sheets/ActiveEffectSheet.mjs | 93 +++--- src/module/sheets/equipmentSheet.mjs | 34 +- src/style/_active-effect-sheet.scss | 5 + src/style/_liturgy-banner.scss | 294 +++++++++--------- src/style/_player-action.scss | 32 +- src/style/_richtext-editor.scss | 10 +- src/style/_skill-sheet.scss | 2 +- src/style/_tabs.scss | 91 +++--- .../item/activeeffect/main-sheet.hbs | 24 ++ .../item/item-activeeffect-sheet.hbs | 20 -- 10 files changed, 323 insertions(+), 282 deletions(-) create mode 100644 src/templates/item/activeeffect/main-sheet.hbs delete mode 100644 src/templates/item/item-activeeffect-sheet.hbs diff --git a/src/module/sheets/ActiveEffectSheet.mjs b/src/module/sheets/ActiveEffectSheet.mjs index ef2c1d03..9e422c6e 100644 --- a/src/module/sheets/ActiveEffectSheet.mjs +++ b/src/module/sheets/ActiveEffectSheet.mjs @@ -1,44 +1,65 @@ -export class ActiveEffectSheet extends foundry.appv1.sheets.ItemSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'activeeffect'], - width: 520, - height: 480 - }); +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class ActiveEffectSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'activeeffect'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: ActiveEffectSheet.#onSubmitForm + }, + actions: { + openEffect: ActiveEffectSheet.#openEffect, + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/activeeffect/main-sheet.hbs` + }, + } + + static async #openEffect(evt) { + evt.preventDefault() + const {id} = evt.srcElement.dataset + const effect = await this.document.effects.get(id) + effect.sheet.render(true) + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - get template() { - return `systems/DSA_4-1/templates/item/item-activeeffect-sheet.hbs`; - } + async _prepareContext(options) { - /** @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(); - const effects = context.document.getEmbeddedCollection("ActiveEffect").contents; + const context = await super._prepareContext(options) + context.system = context.document.system + + const effects = context.document.getEmbeddedCollection("ActiveEffect").contents if (effects.length > 0) { - context.effectId = effects[0]._id; + context.effectId = effects[0]._id } - return context; + context.name = context.document.name + context.img = context.document.img + context.notes = context.document.system.notes + + return context } - - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - html.on('click', '.editEffects', (evt) => { - const {id} = evt.currentTarget.dataset; - const effect = this.object.effects.get(id); - effect.sheet.render(true); - }) - } - -} +} \ No newline at end of file diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs index 2e12f378..a5c3f878 100644 --- a/src/module/sheets/equipmentSheet.mjs +++ b/src/module/sheets/equipmentSheet.mjs @@ -110,12 +110,12 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } #prepareMetaContext(context) { - const equipmentData = context.document.system; - context.system = equipmentData; - context.quantity = equipmentData.quantity; - context.description = equipmentData.description; - context.name = context.document.name; - context.img = context.document.img; + const equipmentData = context.document.system + context.system = equipmentData + context.quantity = equipmentData.quantity + context.description = equipmentData.description + context.name = context.document.name + context.img = context.document.img context.categoryAndOptions = { options: { @@ -131,8 +131,8 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } #prepareMeleeContext(context) { - const equipmentData = context.document.system; - context.system = equipmentData; + const equipmentData = context.document.system + context.system = equipmentData context.meleeSkillsAndOptions = { options: { "": "", @@ -156,7 +156,7 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } #prepareRangedContext(context) { - const equipmentData = context.document.system; + const equipmentData = context.document.system context.rangedSkillsAndOptions = { options: { "": "", @@ -187,14 +187,14 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) */ _prepareTabs(tabGroup) { - const currentTabs = super._prepareTabs(tabGroup); + const currentTabs = super._prepareTabs(tabGroup) const category = this.document.system.category /** * * @type {[{ApplicationTab}]} */ - let tabs = currentTabs; + let tabs = currentTabs if (category.includes("Nahkampfwaffe")) { tabs.melee = { @@ -223,7 +223,7 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) /** @override */ async _prepareContext(options) { - const context = await super._prepareContext(options); + const context = await super._prepareContext(options) context.price = context.document.system.price context.weight = context.document.system.weight @@ -239,12 +239,12 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) */ _onRender(context, options) { this.element.querySelector('.array-editor select').addEventListener('change', (evt) => { - const addingValue = evt.currentTarget.value; - const fieldToTarget = evt.currentTarget.dataset.targetField; - const newSkills = [...this.document.system[fieldToTarget], addingValue]; + const addingValue = evt.currentTarget.value + const fieldToTarget = evt.currentTarget.dataset.targetField + const newSkills = [...this.document.system[fieldToTarget], addingValue] - this.document.update({system: {[fieldToTarget]: newSkills}}); - evt.currentTarget.value = ""; + this.document.update({system: {[fieldToTarget]: newSkills}}) + evt.currentTarget.value = "" }) } diff --git a/src/style/_active-effect-sheet.scss b/src/style/_active-effect-sheet.scss index dd1dddb0..18c57971 100644 --- a/src/style/_active-effect-sheet.scss +++ b/src/style/_active-effect-sheet.scss @@ -14,6 +14,11 @@ height: 48px; line-height: 48px; } + + button { + height: 48px; + width: 48px; + } } .meta { diff --git a/src/style/_liturgy-banner.scss b/src/style/_liturgy-banner.scss index a6d30efb..c1b3366c 100644 --- a/src/style/_liturgy-banner.scss +++ b/src/style/_liturgy-banner.scss @@ -72,176 +72,180 @@ $deity_colours_tint: ( } } -.tab.liturgies { - table { +.dsa41.sheet { - @include coloring('Praios'); - @include coloring('Rondra'); - @include coloring('Efferd'); - @include coloring('Travia'); - @include coloring('Boron'); - @include coloring('Hesinde'); - @include coloring('Firun'); - @include coloring('Tsa'); - @include coloring('Phex'); - @include coloring('Peraine'); - @include coloring('Ingerimm'); - @include coloring('Rahja'); + .tab.liturgies { + table { - tr { - th.background { + @include coloring('Praios'); + @include coloring('Rondra'); + @include coloring('Efferd'); + @include coloring('Travia'); + @include coloring('Boron'); + @include coloring('Hesinde'); + @include coloring('Firun'); + @include coloring('Tsa'); + @include coloring('Phex'); + @include coloring('Peraine'); + @include coloring('Ingerimm'); + @include coloring('Rahja'); + + tr { + th.background { + + &::before { + position: absolute; + content: ''; + background-image: url("../assets/velvet_strip.png"); + background-repeat: repeat-y; + background-size: cover; + width: 86px; + height: 100%; + + top: 45px; + left: 12px; + } + + &::after { /* for tinting the texture */ + content: ""; + position: absolute; + width: 86px; + height: 100%; + + top: 45px; + left: 12px; + } + } + } + + .banner-top { + position: relative; + + width: 90px; + + img { + position: absolute; + top: 2px; + left: 1px; + width: 90px; + height: 90px; + border: 0; + z-index: 1; + } + + &::after { + z-index: 0; + border-width: 0 4px 0 4px; + //background-color: #64b; + border-style: solid; + position: absolute; + content: ""; + left: -2px; + top: 45px; + bottom: 0; + width: 94px; + } &::before { position: absolute; + border-radius: 45px; + height: 94px; + width: 94px; content: ''; - background-image: url("../assets/velvet_strip.png"); - background-repeat: repeat-y; - background-size: cover; - width: 86px; - height: 100%; - - top: 45px; - left: 12px; - } - - &::after { /* for tinting the texture */ - content: ""; - position: absolute; - width: 86px; - height: 100%; - - top: 45px; - left: 12px; + left: -2px; + right: -2px; + top: 0; + border-width: 4px; + border-style: solid; + z-index: 2; } } - } - .banner-top { - position: relative; - - width: 90px; - - img { - position: absolute; - top: 2px; - left: 1px; - width: 90px; - height: 90px; - border: 0; - z-index: 1; - } - - &::after { - z-index: 0; + .banner-mid { + position: relative; border-width: 0 4px 0 4px; //background-color: #64b; border-style: solid; - position: absolute; - content: ""; - left: -2px; - top: 45px; - bottom: 0; - width: 94px; + width: 90px; + + div { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; + + div.rank-label { + position: absolute; + left: 2px; + right: 2px; + top: 0; + bottom: 0; + border-bottom: 2px solid black; + color: gold; + text-shadow: 2px 2px 1px black; + } + } } - &::before { - position: absolute; - border-radius: 45px; - height: 94px; - width: 94px; - content: ''; - left: -2px; - right: -2px; - top: 0; + .banner-bot { + position: relative; border-width: 4px; border-style: solid; - z-index: 2; + width: 90px; + height: 12px; } } - .banner-mid { - position: relative; - border-width: 0 4px 0 4px; - //background-color: #64b; - border-style: solid; - width: 90px; + .liturgy.rollable { + width: 24px; - div { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - display: flex; - justify-content: center; - align-items: center; + svg { + $color: #e4de61; + width: 24px; + height: 24px; + top: 1px; + z-index: 1; + position: relative; - div.rank-label { - position: absolute; - left: 2px; - right: 2px; - top: 0; - bottom: 0; - border-bottom: 2px solid black; - color: gold; - text-shadow: 2px 2px 1px black; + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; } } } - .banner-bot { - position: relative; - border-width: 4px; - border-style: solid; - width: 90px; - height: 12px; + .clickable:hover { + text-shadow: 0 0 10px rgb(255 0 0); } + } - .liturgy.rollable { - width: 24px; - - svg { - $color: #e4de61; - width: 24px; - height: 24px; - top: 1px; - z-index: 1; - position: relative; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - } - - .clickable:hover { - text-shadow: 0 0 10px rgb(255 0 0); - } - -} +} \ No newline at end of file diff --git a/src/style/_player-action.scss b/src/style/_player-action.scss index a56b7b59..181080bb 100644 --- a/src/style/_player-action.scss +++ b/src/style/_player-action.scss @@ -2,25 +2,27 @@ @use "./_numbers"; @use "sass:color"; -.player-action { +.dsa41.sheet { + .player-action { - display: inline-block; - width: 120px; - height: 80px; - float: left; - margin: 0 8px 8px 0; + display: inline-block; + width: 120px; + height: 80px; + float: left; + margin: 0 8px 8px 0; - border: 1px solid #333; - background-color: color.scale(colours.$default-action, $alpha: 20%); - color: colours.$default-action-color; - border-radius: 4px; - box-shadow: numbers.$pill-box-inset numbers.$pill-box-inset numbers.$pill-box-blur-radius colours.$pill-box-shadow; + border: 1px solid #333; + background-color: color.scale(colours.$default-action, $alpha: 20%); + color: colours.$default-action-color; + border-radius: 4px; + box-shadow: numbers.$pill-box-inset numbers.$pill-box-inset numbers.$pill-box-blur-radius colours.$pill-box-shadow; - &.special-ability { - background-color: color.scale(colours.$special-action, $alpha: 20%); - color: colours.$special-action-color; + &.special-ability { + background-color: color.scale(colours.$special-action, $alpha: 20%); + color: colours.$special-action-color; + + } } - } diff --git a/src/style/_richtext-editor.scss b/src/style/_richtext-editor.scss index 4a2f4c21..1f1e331d 100644 --- a/src/style/_richtext-editor.scss +++ b/src/style/_richtext-editor.scss @@ -1,3 +1,7 @@ -.editor.prosemirror.active, .editor.prosemirror.inactive { - flex: 1; -} +.dsa41.sheet { + + .editor.prosemirror.active, .editor.prosemirror.inactive { + flex: 1; + } + +} \ No newline at end of file diff --git a/src/style/_skill-sheet.scss b/src/style/_skill-sheet.scss index f1e621e5..805d6b62 100644 --- a/src/style/_skill-sheet.scss +++ b/src/style/_skill-sheet.scss @@ -1,4 +1,4 @@ -.sheet.item.skill { +.dsa41.sheet.item.skill { .meta-details { diff --git a/src/style/_tabs.scss b/src/style/_tabs.scss index a0a5676a..5b6a99d5 100644 --- a/src/style/_tabs.scss +++ b/src/style/_tabs.scss @@ -44,61 +44,62 @@ } -} -// Tabs v2 + // Tabs v2 -.sheet-tabs { + .sheet-tabs { - position: relative; - display: flow; - border-top: unset; - border-bottom: unset; - margin-bottom: 0; + position: relative; + display: flow; + border-top: unset; + border-bottom: unset; + margin-bottom: 0; - a[data-action="tab"] { + a[data-action="tab"] { - background-color: colours.$tab-inactive-background-color; - display: inline-block; - height: 32px; - line-height: 32px; - vertical-align: middle; - padding: 0 16px; - - span { - - } - - &.active { - - border-left: numbers.$tab-border-width solid colours.$tab-border-color; - border-top: numbers.$tab-border-width solid colours.$tab-border-color; - border-right: numbers.$tab-border-width solid colours.$tab-border-color; - border-bottom: 0; - top: numbers.$tab-border-width*2; - background: assets.$tab-background; - position: relative; - z-index: 2; + background-color: colours.$tab-inactive-background-color; + display: inline-block; + height: 32px; + line-height: 32px; + vertical-align: middle; + padding: 0 16px; span { } + &.active { + + border-left: numbers.$tab-border-width solid colours.$tab-border-color; + border-top: numbers.$tab-border-width solid colours.$tab-border-color; + border-right: numbers.$tab-border-width solid colours.$tab-border-color; + border-bottom: 0; + top: numbers.$tab-border-width*2; + background: assets.$tab-background; + position: relative; + z-index: 2; + + span { + + } + + } + } - } + + section.tab { + border: numbers.$tab-border-width solid colours.$tab-border-color; + background: assets.$tab-pane-background; + flex: 1; + + & > div { + display: flex; + flex-direction: column; + height: 100%; + gap: 8px; + padding: 8px; + } + } + } - -section.tab { - border: numbers.$tab-border-width solid colours.$tab-border-color; - background: assets.$tab-pane-background; - flex: 1; - - & > div { - display: flex; - flex-direction: column; - height: 100%; - gap: 8px; - padding: 8px; - } -} \ No newline at end of file diff --git a/src/templates/item/activeeffect/main-sheet.hbs b/src/templates/item/activeeffect/main-sheet.hbs new file mode 100644 index 00000000..ce7a83a5 --- /dev/null +++ b/src/templates/item/activeeffect/main-sheet.hbs @@ -0,0 +1,24 @@ +
+ +
+ {{name}} + + + +
+ +
+ + + {{{notes}}} + +
+ +
diff --git a/src/templates/item/item-activeeffect-sheet.hbs b/src/templates/item/item-activeeffect-sheet.hbs deleted file mode 100644 index e7c02a70..00000000 --- a/src/templates/item/item-activeeffect-sheet.hbs +++ /dev/null @@ -1,20 +0,0 @@ -
-
- -
- - - - -
- -
- - {{editor item.system.notes target="system.notes" button=true owner=owner editable=editable}} -
- - -
-
-- 2.43.0 From 6bfd509c2c04128b0d8a75101281feaf7cc976bf Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 21:07:56 +0200 Subject: [PATCH 10/40] modifies structuring of stylesheets to reflect the first semblance of a design pattern --- src/style/{ => atoms}/_assets.scss | 0 src/style/{ => atoms}/_colours.scss | 0 src/style/{ => atoms}/_numbers.scss | 0 src/style/{ => molecules}/_attributes.scss | 6 ++-- src/style/{ => molecules}/_lists.scss | 0 .../{ => molecules}/_liturgy-banner.scss | 6 ++-- src/style/{ => molecules}/_paperdoll.scss | 0 src/style/{ => molecules}/_player-action.scss | 4 +-- .../{ => molecules}/_richtext-editor.scss | 0 src/style/{ => molecules}/_rollable.scss | 4 +-- .../{ => molecules}/_sidebar-elements.scss | 2 +- src/style/{ => molecules}/_tabs.scss | 6 ++-- .../{ => organisms}/_active-effect-sheet.scss | 0 .../{ => organisms}/_advantage-sheet.scss | 0 .../{ => organisms}/_character-sheet.scss | 10 +++--- .../{ => organisms}/_creature-sheet.scss | 4 +-- .../{ => organisms}/_equipment-sheet.scss | 4 +-- src/style/{ => organisms}/_group-sheet.scss | 0 .../{ => organisms}/_modify-liturgy.scss | 0 src/style/{ => organisms}/_skill-sheet.scss | 0 src/style/styles.scss | 34 +++++++++---------- 21 files changed, 40 insertions(+), 40 deletions(-) rename src/style/{ => atoms}/_assets.scss (100%) rename src/style/{ => atoms}/_colours.scss (100%) rename src/style/{ => atoms}/_numbers.scss (100%) rename src/style/{ => molecules}/_attributes.scss (97%) rename src/style/{ => molecules}/_lists.scss (100%) rename src/style/{ => molecules}/_liturgy-banner.scss (97%) rename src/style/{ => molecules}/_paperdoll.scss (100%) rename src/style/{ => molecules}/_player-action.scss (92%) rename src/style/{ => molecules}/_richtext-editor.scss (100%) rename src/style/{ => molecules}/_rollable.scss (98%) rename src/style/{ => molecules}/_sidebar-elements.scss (96%) rename src/style/{ => molecules}/_tabs.scss (96%) rename src/style/{ => organisms}/_active-effect-sheet.scss (100%) rename src/style/{ => organisms}/_advantage-sheet.scss (100%) rename src/style/{ => organisms}/_character-sheet.scss (98%) rename src/style/{ => organisms}/_creature-sheet.scss (98%) rename src/style/{ => organisms}/_equipment-sheet.scss (98%) rename src/style/{ => organisms}/_group-sheet.scss (100%) rename src/style/{ => organisms}/_modify-liturgy.scss (100%) rename src/style/{ => organisms}/_skill-sheet.scss (100%) diff --git a/src/style/_assets.scss b/src/style/atoms/_assets.scss similarity index 100% rename from src/style/_assets.scss rename to src/style/atoms/_assets.scss diff --git a/src/style/_colours.scss b/src/style/atoms/_colours.scss similarity index 100% rename from src/style/_colours.scss rename to src/style/atoms/_colours.scss diff --git a/src/style/_numbers.scss b/src/style/atoms/_numbers.scss similarity index 100% rename from src/style/_numbers.scss rename to src/style/atoms/_numbers.scss diff --git a/src/style/_attributes.scss b/src/style/molecules/_attributes.scss similarity index 97% rename from src/style/_attributes.scss rename to src/style/molecules/_attributes.scss index 1b3fd95a..12830c1f 100644 --- a/src/style/_attributes.scss +++ b/src/style/molecules/_attributes.scss @@ -1,6 +1,6 @@ -@use "./_colours"; -@use "./_numbers"; -@use "./_assets"; +@use "../atoms/colours"; +@use "../atoms/numbers"; +@use "../atoms/assets"; @use "sass:color"; .dsa41.sheet.actor.character { diff --git a/src/style/_lists.scss b/src/style/molecules/_lists.scss similarity index 100% rename from src/style/_lists.scss rename to src/style/molecules/_lists.scss diff --git a/src/style/_liturgy-banner.scss b/src/style/molecules/_liturgy-banner.scss similarity index 97% rename from src/style/_liturgy-banner.scss rename to src/style/molecules/_liturgy-banner.scss index c1b3366c..c2ce6d46 100644 --- a/src/style/_liturgy-banner.scss +++ b/src/style/molecules/_liturgy-banner.scss @@ -1,7 +1,7 @@ @use "sass:map"; @use "sass:color"; -@use "colours" as colour; -@use "numbers"; +@use "../atoms/colours" as colour; +@use "../atoms/numbers"; $deity_colours_border: ( "Praios": orange, @@ -96,7 +96,7 @@ $deity_colours_tint: ( &::before { position: absolute; content: ''; - background-image: url("../assets/velvet_strip.png"); + background-image: url("../../assets/velvet_strip.png"); background-repeat: repeat-y; background-size: cover; width: 86px; diff --git a/src/style/_paperdoll.scss b/src/style/molecules/_paperdoll.scss similarity index 100% rename from src/style/_paperdoll.scss rename to src/style/molecules/_paperdoll.scss diff --git a/src/style/_player-action.scss b/src/style/molecules/_player-action.scss similarity index 92% rename from src/style/_player-action.scss rename to src/style/molecules/_player-action.scss index 181080bb..dddba46e 100644 --- a/src/style/_player-action.scss +++ b/src/style/molecules/_player-action.scss @@ -1,5 +1,5 @@ -@use "./_colours"; -@use "./_numbers"; +@use "../atoms/colours"; +@use "../atoms/numbers"; @use "sass:color"; .dsa41.sheet { diff --git a/src/style/_richtext-editor.scss b/src/style/molecules/_richtext-editor.scss similarity index 100% rename from src/style/_richtext-editor.scss rename to src/style/molecules/_richtext-editor.scss diff --git a/src/style/_rollable.scss b/src/style/molecules/_rollable.scss similarity index 98% rename from src/style/_rollable.scss rename to src/style/molecules/_rollable.scss index 5a294533..de8f7ac2 100644 --- a/src/style/_rollable.scss +++ b/src/style/molecules/_rollable.scss @@ -1,7 +1,7 @@ @use 'sass:color'; @use 'sass:map'; -@use "_colours" as colour; -@use "_numbers" as numbers; +@use "../atoms/colours" as colour; +@use "../atoms/numbers" as numbers; $rollable_colours: ( "nachteil": colour.$nachteil-color, diff --git a/src/style/_sidebar-elements.scss b/src/style/molecules/_sidebar-elements.scss similarity index 96% rename from src/style/_sidebar-elements.scss rename to src/style/molecules/_sidebar-elements.scss index f774031b..c75bf25c 100644 --- a/src/style/_sidebar-elements.scss +++ b/src/style/molecules/_sidebar-elements.scss @@ -60,7 +60,7 @@ left: 0; top: 0; bottom: 0; - background: url('../assets/gradient.png'); + background: url('../../assets/gradient.png'); background-size: 32px 100%; &::after { diff --git a/src/style/_tabs.scss b/src/style/molecules/_tabs.scss similarity index 96% rename from src/style/_tabs.scss rename to src/style/molecules/_tabs.scss index 5b6a99d5..cfc7b9ec 100644 --- a/src/style/_tabs.scss +++ b/src/style/molecules/_tabs.scss @@ -1,6 +1,6 @@ -@use "./numbers"; -@use "./colours"; -@use "./assets"; +@use "../atoms/numbers"; +@use "../atoms/colours"; +@use "../atoms/assets"; .dsa41.sheet { diff --git a/src/style/_active-effect-sheet.scss b/src/style/organisms/_active-effect-sheet.scss similarity index 100% rename from src/style/_active-effect-sheet.scss rename to src/style/organisms/_active-effect-sheet.scss diff --git a/src/style/_advantage-sheet.scss b/src/style/organisms/_advantage-sheet.scss similarity index 100% rename from src/style/_advantage-sheet.scss rename to src/style/organisms/_advantage-sheet.scss diff --git a/src/style/_character-sheet.scss b/src/style/organisms/_character-sheet.scss similarity index 98% rename from src/style/_character-sheet.scss rename to src/style/organisms/_character-sheet.scss index 6c88c78b..6750bdde 100644 --- a/src/style/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -1,6 +1,6 @@ @use "sass:color"; -@use "_numbers"; -@use "_colours" as colour; +@use "../atoms/numbers"; +@use "../atoms/colours" as colour; .dsa41.sheet.actor.character { @@ -192,7 +192,7 @@ padding: 0 8px; margin-left: 0; margin-bottom: 4px; - background-image: url("../assets/velvet_button.png"); + background-image: url("../../assets/velvet_button.png"); background-repeat: repeat-y; background-size: cover; @@ -320,7 +320,7 @@ .filled-segment { border: 1px solid black; - background-image: url('../assets/gradient.png'); + background-image: url('../../assets/gradient.png'); background-size: 24px 100%; position: relative; flex: 1; @@ -336,7 +336,7 @@ .empty-segment { border: 1px solid black; - background-image: url('../assets/gradient.png'); + background-image: url('../../assets/gradient.png'); background-size: 32px 100%; position: relative; flex: 1; diff --git a/src/style/_creature-sheet.scss b/src/style/organisms/_creature-sheet.scss similarity index 98% rename from src/style/_creature-sheet.scss rename to src/style/organisms/_creature-sheet.scss index 6c222a63..2ea8acd1 100644 --- a/src/style/_creature-sheet.scss +++ b/src/style/organisms/_creature-sheet.scss @@ -1,6 +1,6 @@ -@use "_colours" as colour; +@use "../atoms/colours" as colour; @use 'sass:color'; -@use "_numbers"; +@use "../atoms/numbers"; .dsa41.sheet.actor.creature { diff --git a/src/style/_equipment-sheet.scss b/src/style/organisms/_equipment-sheet.scss similarity index 98% rename from src/style/_equipment-sheet.scss rename to src/style/organisms/_equipment-sheet.scss index 859793e5..a565df70 100644 --- a/src/style/_equipment-sheet.scss +++ b/src/style/organisms/_equipment-sheet.scss @@ -1,5 +1,5 @@ -@use "./_colours"; -@use "./_numbers"; +@use "../atoms/colours"; +@use "../atoms/numbers"; .application.sheet.dsa41.item.equipment { diff --git a/src/style/_group-sheet.scss b/src/style/organisms/_group-sheet.scss similarity index 100% rename from src/style/_group-sheet.scss rename to src/style/organisms/_group-sheet.scss diff --git a/src/style/_modify-liturgy.scss b/src/style/organisms/_modify-liturgy.scss similarity index 100% rename from src/style/_modify-liturgy.scss rename to src/style/organisms/_modify-liturgy.scss diff --git a/src/style/_skill-sheet.scss b/src/style/organisms/_skill-sheet.scss similarity index 100% rename from src/style/_skill-sheet.scss rename to src/style/organisms/_skill-sheet.scss diff --git a/src/style/styles.scss b/src/style/styles.scss index ea91cf78..8cd4c662 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -1,17 +1,17 @@ -@use "_rollable"; -@use "_lists"; -@use "_attributes"; -@use "_sidebar-elements"; -@use "_character-sheet"; -@use "_group-sheet"; -@use "_tabs"; -@use "_equipment-sheet"; -@use "_paperdoll"; -@use "_creature-sheet"; -@use "_player-action"; -@use "_modify-liturgy"; -@use "_liturgy-banner"; -@use "_skill-sheet"; -@use "_active-effect-sheet"; -@use "_advantage-sheet"; -@use "_richtext-editor"; \ No newline at end of file +@use "molecules/rollable"; +@use "molecules/lists"; +@use "molecules/attributes"; +@use "molecules/sidebar-elements"; +@use "organisms/character-sheet"; +@use "organisms/group-sheet"; +@use "molecules/tabs"; +@use "organisms/equipment-sheet"; +@use "molecules/paperdoll"; +@use "organisms/creature-sheet"; +@use "molecules/player-action"; +@use "organisms/modify-liturgy"; +@use "molecules/liturgy-banner"; +@use "organisms/skill-sheet"; +@use "organisms/active-effect-sheet"; +@use "organisms/advantage-sheet"; +@use "molecules/richtext-editor"; \ No newline at end of file -- 2.43.0 From 9984db4ca65d71fe468cf6977b1c25e408e98eab Mon Sep 17 00:00:00 2001 From: macniel Date: Wed, 15 Oct 2025 22:29:48 +0200 Subject: [PATCH 11/40] migrates CreatureSheet to ActorSheetV2 --- src/module/sheets/creatureSheet.mjs | 166 ++++++---- src/style/atoms/_svg.scss | 3 + src/style/organisms/_creature-sheet.scss | 300 +++++++++--------- src/style/styles.scss | 1 + src/templates/actor/actor-creature-sheet.hbs | 137 -------- src/templates/actor/creature/main-sheet.hbs | 22 ++ src/templates/actor/creature/tab-attacks.hbs | 83 +++++ .../actor/creature/tab-description.hbs | 12 + src/templates/actor/creature/tab-meta.hbs | 33 ++ 9 files changed, 401 insertions(+), 356 deletions(-) create mode 100644 src/style/atoms/_svg.scss delete mode 100644 src/templates/actor/actor-creature-sheet.hbs create mode 100644 src/templates/actor/creature/main-sheet.hbs create mode 100644 src/templates/actor/creature/tab-attacks.hbs create mode 100644 src/templates/actor/creature/tab-description.hbs create mode 100644 src/templates/actor/creature/tab-meta.hbs diff --git a/src/module/sheets/creatureSheet.mjs b/src/module/sheets/creatureSheet.mjs index 2c28134d..93d21402 100644 --- a/src/module/sheets/creatureSheet.mjs +++ b/src/module/sheets/creatureSheet.mjs @@ -1,32 +1,114 @@ -export class CreatureSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'creature'], - width: 520, - height: 480, +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets + +export class CreatureSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'actor', 'creature'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CreatureSheet.#onSubmitForm + }, + actions: { + removeAttack: CreatureSheet.#removeAttack, + addAttack: CreatureSheet.#addAttack, + roll: CreatureSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'meta', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'attacks', group: 'sheet', label: 'Attacken'}, + {id: 'description', group: 'sheet', label: 'Beschreibung'}, ], + initial: 'meta' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/creature/main-sheet.hbs` + }, + meta: { + template: `systems/DSA_4-1/templates/actor/creature/tab-meta.hbs` + }, + attacks: { + template: `systems/DSA_4-1/templates/actor/creature/tab-attacks.hbs` + }, + description: { + template: `systems/DSA_4-1/templates/actor/creature/tab-description.hbs` + } + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + static async #removeAttack(evt) { + const {index} = evt.srcElement.dataset; + let sans = Array.from(this.document.system.attacks); + sans.splice(index, 1); + await this.document.update({'system.attacks': sans}) + } + + static async #dieRoll(evt) { + const {rollType, rollName, roll} = evt.srcElement.dataset; + let r = new Roll(roll, this.document.getRollData()); + const label = `${rollType} (${rollName})` + await r.toMessage({ + speaker: ChatMessage.getSpeaker({actor: this.document}), + flavor: label, + rollMode: game.settings.get('core', 'rollMode'), }); } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/actor-creature-sheet.hbs`; + static async #addAttack() { + const name = this.element.querySelector('#attack_name').value + const at = this.element.querySelector('#attack_at').value + const pa = this.element.querySelector('#attack_pa').value + const tp = this.element.querySelector('#attack_tp').value + + const newAttack = { + name, + at, + pa, + tp + } + + await this.document.update({'system.attacks': [...this.document.system.attacks, newAttack]}) + + this.element.querySelector('#attack_name').value = "" + this.element.querySelector('#attack_at').value = "" + this.element.querySelector('#attack_pa').value = "" + this.element.querySelector('#attack_tp').value = "" } /** @override */ - getData() { + async _prepareContext(options) { - const context = super.getData(); - const actorData = context.data; + const context = await super._prepareContext(options); + const actorData = context.document; context.attacks = []; + context.actor = actorData; actorData.system.attacks.forEach((attack, index) => { context.attacks.push({ @@ -43,55 +125,7 @@ export class CreatureSheet extends foundry.appv1.sheets.ActorSheet { }) }) - return context; } - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - html.on('click', '.remove-attack', async (evt) => { - const {index} = evt.target.dataset; - let sans = Array.from(this.object.system.attacks); - sans.splice(index, 1); - await this.object.update({'system.attacks': sans}) - }) - - html.on('click', '.attacks-die.die', async (evt) => { - const {rollType, rollName, roll} = evt.currentTarget.dataset; - let r = new Roll(roll, this.actor.getRollData()); - const label = `${rollType} (${rollName})` - await r.toMessage({ - speaker: ChatMessage.getSpeaker({actor: this.object}), - flavor: label, - rollMode: game.settings.get('core', 'rollMode'), - }); - }) - - html.on('click', '.editor .add-attack', async (evt) => { - const name = html[0].querySelector('#attack_name').value - const at = html[0].querySelector('#attack_at').value - const pa = html[0].querySelector('#attack_pa').value - const tp = html[0].querySelector('#attack_tp').value - - const newAttack = { - name, - at, - pa, - tp - } - - await this.object.update({'system.attacks': [...this.object.system.attacks, newAttack]}) - - evt.target.parentElement.querySelector('#attack_name').value = "" - evt.target.parentElement.querySelector('#attack_at').value = "" - evt.target.parentElement.querySelector('#attack_pa').value = "" - evt.target.parentElement.querySelector('#attack_tp').value = "" - }) - - } - } diff --git a/src/style/atoms/_svg.scss b/src/style/atoms/_svg.scss new file mode 100644 index 00000000..2092062b --- /dev/null +++ b/src/style/atoms/_svg.scss @@ -0,0 +1,3 @@ +svg { + pointer-events: none; +} \ No newline at end of file diff --git a/src/style/organisms/_creature-sheet.scss b/src/style/organisms/_creature-sheet.scss index 2ea8acd1..707971cd 100644 --- a/src/style/organisms/_creature-sheet.scss +++ b/src/style/organisms/_creature-sheet.scss @@ -6,169 +6,163 @@ .window-content { - form { + .sheet-header { + height: 64px; display: grid; - grid-template-columns: 1fr; - grid-template-rows: 74px 30px 1fr; - - .sheet-header { + grid-template-columns: 64px 1fr; + grid-template-rows: 1fr; + gap: 0 8px; + margin-bottom: 8px; + img { + width: 64px; height: 64px; - display: grid; - grid-template-columns: 64px max-content; - grid-template-rows: 1fr; - gap: 0 8px; - - img { - width: 64px; - height: 64px; - } - - input { - line-height: 64px; - height: 64px; - font-size: 2rem; - - } - } - .sheet-body { - .tab { - margin: 8px; + input { + line-height: 64px; + height: 64px; + font-size: 2rem; - height: 100%; - - div.input { - - height: 32px; - display: grid; - grid-template-columns: 120px 1fr; - - &.compound { - - grid-template-columns: 120px 140px 1fr; - - span { - width: 120px; - } - - - input { - width: 100px; - } - - } - - label { - height: 32px; - width: 100%; - - span { - width: 120px; - text-align: left; - line-height: 32px; - vertical-align: middle; - display: inline-block; - } - - input { - text-align: right; - line-height: 32px; - vertical-align: middle; - padding-left: 120px; - display: inline-block; - } - - } - - } - - table.attacks-table { - - td { - padding: 2px 4px; - } - } - - .rollable.tablecell { - position: relative; - - - .attacks-die { - width: 24px; - height: 24px; - position: absolute; - left: 4px; - top: 4px; - bottom: 2px; - z-index: 1; - - - svg { - stroke-width: 0.5; - - $color: #f30; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - - - } - - input { - position: absolute; - left: 16px; - top: 4px; - bottom: 2px; - right: 4px; - width: unset; - text-indent: 12px; - } - } - - .button-inline { - border: unset; - background: unset; - } - - .editor { - height: 100%; - } - - } } } - } + div.input { + + height: 32px; + display: grid; + grid-template-columns: 120px 1fr; + + &.compound { + + grid-template-columns: 120px 140px 1fr; + + span { + width: 120px; + } + + + input { + width: 100px; + } + + } + + label { + height: 32px; + width: 100%; + + span { + width: 120px; + text-align: left; + line-height: 32px; + vertical-align: middle; + display: inline-block; + } + + input { + text-align: right; + line-height: 32px; + vertical-align: middle; + padding-left: 120px; + display: inline-block; + } + + } + + } + + table.attacks-table { + + margin: 0; + + td { + padding: 2px 4px; + } + } + + .rollable.tablecell { + position: relative; + + + .attacks-die { + width: 24px; + height: 24px; + position: absolute; + left: 4px; + top: 4px; + bottom: 2px; + z-index: 1; + + + svg { + stroke-width: 0.5; + + $color: #f30; + + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; + } + } + + + } + + input { + position: absolute; + left: 16px; + top: 4px; + bottom: 2px; + right: 4px; + width: unset; + text-indent: 12px; + } + } + + .button-inline { + border: unset; + background: unset; + } + + .editor { + height: 100%; + } + + .tab.active { + padding: 8px; + } + + .tab.attacks.active { + padding: 16px; + } + + } } diff --git a/src/style/styles.scss b/src/style/styles.scss index 8cd4c662..eb843ead 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -1,3 +1,4 @@ +@use "atoms/svg"; @use "molecules/rollable"; @use "molecules/lists"; @use "molecules/attributes"; diff --git a/src/templates/actor/actor-creature-sheet.hbs b/src/templates/actor/actor-creature-sheet.hbs deleted file mode 100644 index 221b9a79..00000000 --- a/src/templates/actor/actor-creature-sheet.hbs +++ /dev/null @@ -1,137 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- {{!-- Header stuff goes here --}} - - - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
- -
-
-
- - -
-
- - -
-
- - - -
-
- -
- - w6 + -
- - -
-
-
-
- - - - - - - - - - - - - {{#each this.attacks}} - - - - - - - - {{/each}} - - - - - - - - - - - - - - - - -
NameAttackeParadeSchaden
- - -
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} -
- -
- -
Attacke hinzufügen
- - - - - - - - - - -
- -
-
- {{editor system.description target="system.description" button=true owner=owner editable=editable}} - -
-
-
diff --git a/src/templates/actor/creature/main-sheet.hbs b/src/templates/actor/creature/main-sheet.hbs new file mode 100644 index 00000000..a59c040d --- /dev/null +++ b/src/templates/actor/creature/main-sheet.hbs @@ -0,0 +1,22 @@ +
+
+ {{!-- Header stuff goes here --}} + + {{actor.name}} + + +
+ + +
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-attacks.hbs b/src/templates/actor/creature/tab-attacks.hbs new file mode 100644 index 00000000..b1020e5a --- /dev/null +++ b/src/templates/actor/creature/tab-attacks.hbs @@ -0,0 +1,83 @@ +
+ + + + + + + + + + + + {{#each this.attacks}} + + + + + + + + {{/each}} + + + + + + + + + + + + + + + + +
NameAttackeParadeSchaden
+ + +
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} +
+ +
+ +
Attacke hinzufügen
+ + + + + + + + + + +
+
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-description.hbs b/src/templates/actor/creature/tab-description.hbs new file mode 100644 index 00000000..7d97f68c --- /dev/null +++ b/src/templates/actor/creature/tab-description.hbs @@ -0,0 +1,12 @@ +
+ + {{{system.description}}} + +
\ No newline at end of file diff --git a/src/templates/actor/creature/tab-meta.hbs b/src/templates/actor/creature/tab-meta.hbs new file mode 100644 index 00000000..8434981b --- /dev/null +++ b/src/templates/actor/creature/tab-meta.hbs @@ -0,0 +1,33 @@ +
+
+
+ + +
+
+ + +
+
+ + + +
+
+ +
+ + w6 + +
+ + +
+
+
\ No newline at end of file -- 2.43.0 From 5e41285b1c08eb502c4ccc82b9281e731203f9a0 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 00:06:50 +0200 Subject: [PATCH 12/40] WIP group sheet --- src/module/data/group.mjs | 10 + src/module/data/skill.mjs | 9 +- src/module/sheets/groupSheet.mjs | 229 +++++++++----------- src/templates/actor/group-sheet.hbs | 121 ----------- src/templates/actor/group/main-sheet.hbs | 20 ++ src/templates/actor/group/tab-inventory.hbs | 28 +++ src/templates/actor/group/tab-members.hbs | 89 ++++++++ 7 files changed, 252 insertions(+), 254 deletions(-) delete mode 100644 src/templates/actor/group-sheet.hbs create mode 100644 src/templates/actor/group/main-sheet.hbs create mode 100644 src/templates/actor/group/tab-inventory.hbs create mode 100644 src/templates/actor/group/tab-members.hbs diff --git a/src/module/data/group.mjs b/src/module/data/group.mjs index 9786dd34..f6ef784b 100644 --- a/src/module/data/group.mjs +++ b/src/module/data/group.mjs @@ -18,6 +18,7 @@ export class GroupDataModel extends foundry.abstract.TypeDataModel { quantity: new NumberField(), item: new DocumentIdField(Item) }), + groupId: new DocumentIdField(Actor), characters: new ArrayField( new DocumentIdField(Actor) ), @@ -25,4 +26,13 @@ export class GroupDataModel extends foundry.abstract.TypeDataModel { } } + _onCreate(data, options, userId) { + super._onCreate(data, options, userId); + Folder.implementation.createDocuments([{name: data.name, type: "Actor"}]).then(( + folder + ) => { + this.parent.update({"system.groupId": folder[0]._id}); + }) + } + } diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index 14c84a4c..90d2a4f1 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -45,10 +45,11 @@ export class SkillDataModel extends BaseItem { /** * Handle clickable rolls. - * @param {Event} event The originating click event + * @param {RollMode} rollMode * @private */ - async roll() { + async roll(rollMode = null) { + rollMode = rollMode ?? game.settings.get('core', 'rollMode'); const owner = this.parent.parent let roll1 = new Roll("3d20", owner.getRollData()); @@ -63,13 +64,13 @@ export class SkillDataModel extends BaseItem { evaluated1.toMessage({ speaker: ChatMessage.getSpeaker({actor: owner}), flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, - rollMode: game.settings.get('core', 'rollMode'), + rollMode, }) } else { // misserfolg evaluated1.toMessage({ speaker: ChatMessage.getSpeaker({actor: owner}), flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, - rollMode: game.settings.get('core', 'rollMode'), + rollMode, }) } } diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 3edff152..7db70ed3 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -1,20 +1,52 @@ -export class GroupSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'group'], - width: 520, - height: 480, - tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, - ], - }); +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets + +export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'actor', 'group'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: GroupSheet.#onSubmitForm + }, + actions: { + roll: GroupSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + openEmbeddedDocument: GroupSheet.#openEmbeddedDocument, + openActorDocument: GroupSheet.#openActorDocument, + removeFromParty: GroupSheet.#removeFromParty, + } } + static TABS = { + sheet: { + tabs: [ + {id: 'members', group: 'sheet', label: 'Gruppenmitglieder'}, + {id: 'inventory', group: 'sheet', label: 'Gruppeninventar'}, + // settings is only added on context + ], + initial: 'members' + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/group/main-sheet.hbs` + }, + members: { + template: `systems/DSA_4-1/templates/actor/group/tab-members.hbs` + }, + inventory: { + template: `systems/DSA_4-1/templates/actor/group/tab-inventory.hbs` + }, + } + + static async onDroppedData(group, sheet, data) { if (data.type === "Actor") { const uuid = await foundry.utils.parseUuid(data.uuid); @@ -63,17 +95,52 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { return s } - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/group-sheet.hbs`; + static async #openEmbeddedDocument(evt) { + const {documentId} = evt.srcElement.dataset + this.document.items.get(documentId).sheet.render(true) + } + + static async #openActorDocument(evt) { + const {id} = evt.srcElement.dataset + evt.stopPropagation() + game.actors.get(id).sheet.render(true) + } + + static async #dieRoll(evt) { + console.log(evt) + } + + static async #removeFromParty(evt) { + const dataset = evt.srcElement.dataset; + const group = this.document; + const charactersWithoutMember = group.system.characters.filter(id => id !== dataset.id) + group.update({ + system: { + characters: charactersWithoutMember + } + }) + + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object } /** @override */ - async getData() { - const context = super.getData(); + async _prepareContext(options) { + const context = await super._prepareContext(options) // Use a safe clone of the actor data for further operations. - const groupData = context.data; + const groupData = context.document; // Add the actor's data to context.data for easier access, as well as flags. context.system = groupData.system; @@ -101,8 +168,11 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { } } - for (const characterId of groupData.system.characters) { - const character = await game.actors.get(characterId) + // TODO hook on changes in the given folder + const characters = await game.folders.get(groupData.system.groupId).contents + console.log(characters) + + for (const character of characters) { character.items.filter((i) => i.type === "Advantage").filter((i) => hiddenFields.includes(this.#stringToKeyFieldName(i.name))).map((advantage) => { const n = this.#stringToKeyFieldName(advantage.name) @@ -154,7 +224,7 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { } context.equipments = []; - const actorData = context.data; + const actorData = context.document; Object.values(actorData.items).forEach((item, index) => { if (item.type === "Equipment") { context.equipments.push({ @@ -173,110 +243,8 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { return await context; } - openEmbeddedDocument(documentId) { - this.object.items.get(documentId).sheet.render(true) - } - - - _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, - } - } - - async _onTalentRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; - const actor = await game.actors.get(dataset.actorId); - console.log(dataset, actor) - if (dataset.rolleigenschaft1) { - let roll1 = new Roll("3d20", 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: actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Meisterlich geschafft' : 'Geschafft'} mit ${dsaDieRollEvaluated.tap} Punkten übrig`, - }, {rollMode: "gmroll"}) - } else { // misserfolg - evaluated1.toMessage({ - speaker: ChatMessage.getSpeaker({actor: actor}), - flavor: ` ${dsaDieRollEvaluated.meisterlich ? 'Gepatzt' : ''} mit ${Math.abs(dsaDieRollEvaluated.tap)} Punkten daneben`, - }, {rollMode: "gmroll"}) - } - } - } - - activateListeners(html) { - super.activateListeners(html); - - html.on('click', '.owneroption.clickable', async (evt) => { - const dataset = evt.target.dataset; - const group = this.object; - switch (dataset.operation) { - case "removeFromParty": - const charactersWithoutMember = group.system.characters.filter(id => id !== dataset.id) - await group.update({ - system: { - characters: charactersWithoutMember - } - }) - } - }); - html.on('click', '.header.clickable', async (evt) => { - const {id, operation} = evt.currentTarget.dataset; - if (operation === "openActorSheet") { - evt.stopPropagation(); - (await game.actors.get(id)).sheet.render(true); - } - }) - - - html.on('click', '.equipment', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - html.on('click', ".rollable", (evt) => { - this._onTalentRoll(evt) - evt.stopPropagation() - }) - - new ContextMenu(html, '.equipment', [ + _onRender(context, options) { + new ContextMenu(this.element, ".equipment", [ { name: "Aus dem Gruppeninventar entfernen", icon: '', @@ -285,6 +253,9 @@ export class GroupSheet extends foundry.appv1.sheets.ActorSheet { }, condition: () => true } - ]); + ], { + jQuery: false + }); } + } diff --git a/src/templates/actor/group-sheet.hbs b/src/templates/actor/group-sheet.hbs deleted file mode 100644 index 776e34e7..00000000 --- a/src/templates/actor/group-sheet.hbs +++ /dev/null @@ -1,121 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
- {{#unless isGM}} -
- {{#each characters}} - {{#if this.isVisible}} -
-
- {{this.name}} - {{this.name}} -
-
- {{/if}} - {{/each}} -
- {{else}} -
- - - - - {{#each this.fields.head}} - - {{/each}} - - - - {{#each this.fields}} - {{#unless (eq @key "head")}} - - - - {{#each this}} - - {{/each}} - - - {{/unless}} - {{/each}} - -
-
-
- {{this.name}} - {{this.name}} -
- {{#if this.isLimited}} -
- {{#each this.attributes}} -
- {{this.value}} - {{this.name}} -
- {{/each}} -
- {{/if}} -
-
- {{ @key}} - - {{#if (eq this "-")}} - - {{else}} - {{#if this.taw}} -
- {{this.taw}} ({{this.eigenschaft1}}, {{this.eigenschaft2}} - , {{this.eigenschaft3}}) -
- {{else}} - Ja - {{/if}} - {{/if}} -
-
- {{/unless}} -
-
- {{> 'systems/DSA_4-1/templates/ui/partial-equipment-group-button.hbs' equipments}} -
- {{#if owner}} -
- {{#each settings}} -
- -
- {{/each}} -
- {{/if}} - -
- -
diff --git a/src/templates/actor/group/main-sheet.hbs b/src/templates/actor/group/main-sheet.hbs new file mode 100644 index 00000000..3ac4260f --- /dev/null +++ b/src/templates/actor/group/main-sheet.hbs @@ -0,0 +1,20 @@ +
+
+ + + +
+ + {{!-- Sheet Tab Navigation --}} + +
\ No newline at end of file diff --git a/src/templates/actor/group/tab-inventory.hbs b/src/templates/actor/group/tab-inventory.hbs new file mode 100644 index 00000000..f6107c7e --- /dev/null +++ b/src/templates/actor/group/tab-inventory.hbs @@ -0,0 +1,28 @@ +
+ + + + + + + + + + + + + {{#each inventoryItems}} + + + + + + + {{/each}} + +
AnzahlGewicht
{{this.name}}{{this.quantity}}{{this.weight}}
+ + +
diff --git a/src/templates/actor/group/tab-members.hbs b/src/templates/actor/group/tab-members.hbs new file mode 100644 index 00000000..7adc3411 --- /dev/null +++ b/src/templates/actor/group/tab-members.hbs @@ -0,0 +1,89 @@ +
+ {{#unless isGM}} +
+ {{#each this.characters}} + {{#if this.isVisible}} +
+
+ {{this.name}} + {{this.name}} +
+
+ {{/if}} + {{/each}} +
+ {{else}} +
+ + + + + {{#each this.fields.head}} + + {{/each}} + + + + {{#each this.fields}} + {{#unless (eq @key "head")}} + + + + {{#each this}} + + {{/each}} + + + {{/unless}} + {{/each}} + +
+
+
+ {{this.name}} + {{this.name}} +
+ {{#if this.isLimited}} +
+ {{#each this.attributes}} +
+ {{this.value}} + {{this.name}} +
+ {{/each}} +
+ {{/if}} +
+
+ {{ @key}} + + {{#if (eq this "-")}} + + {{else}} + {{#if this.taw}} +
+ {{this.taw}} ({{this.eigenschaft1}}, {{this.eigenschaft2}} + , {{this.eigenschaft3}}) +
+ {{else}} + Ja + {{/if}} + {{/if}} +
+
+ {{/unless}} +
\ No newline at end of file -- 2.43.0 From e14e4e71081a64c338abd0b31f8f70ee17a5602c Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 00:06:54 +0200 Subject: [PATCH 13/40] WIP group sheet --- .../ui/partial-equipment-group-button.hbs | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/templates/ui/partial-equipment-group-button.hbs diff --git a/src/templates/ui/partial-equipment-group-button.hbs b/src/templates/ui/partial-equipment-group-button.hbs deleted file mode 100644 index 37e310b6..00000000 --- a/src/templates/ui/partial-equipment-group-button.hbs +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - {{#each this}} - - - - - - - {{/each}} - -
AnzahlGewicht
{{this.name}}{{this.quantity}}{{this.weight}}
-- 2.43.0 From 6f1bad0b6767db1363c7e0b90b15f9a0ec25b397 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 16:24:36 +0200 Subject: [PATCH 14/40] partial migration of groupsheet --- src/module/sheets/groupSheet.mjs | 187 ++++++++++-------- src/style/organisms/_group-sheet.scss | 40 +--- src/templates/actor/group/main-sheet.hbs | 2 + src/templates/actor/group/tab-members.hbs | 13 +- src/templates/actor/group/tab-settings.hbs | 12 ++ src/templates/ui/partial-equipment-button.hbs | 2 +- 6 files changed, 134 insertions(+), 122 deletions(-) create mode 100644 src/templates/actor/group/tab-settings.hbs diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 7db70ed3..3126e411 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -1,5 +1,6 @@ const {HandlebarsApplicationMixin} = foundry.applications.api const {ActorSheetV2} = foundry.applications.sheets +const {ContextMenu} = foundry.applications.ux export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { @@ -8,17 +9,22 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { position: {width: 520, height: 480}, classes: ['dsa41', 'sheet', 'actor', 'group'], tag: 'form', + dragDrop: [{ + dropSelector: '.tab.inventory.active' + }], form: { submitOnChange: true, closeOnSubmit: false, handler: GroupSheet.#onSubmitForm }, + window: { + resizable: true, + }, actions: { roll: GroupSheet.#dieRoll, editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, openEmbeddedDocument: GroupSheet.#openEmbeddedDocument, openActorDocument: GroupSheet.#openActorDocument, - removeFromParty: GroupSheet.#removeFromParty, } } @@ -27,7 +33,6 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { tabs: [ {id: 'members', group: 'sheet', label: 'Gruppenmitglieder'}, {id: 'inventory', group: 'sheet', label: 'Gruppeninventar'}, - // settings is only added on context ], initial: 'members' } @@ -44,51 +49,45 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { inventory: { template: `systems/DSA_4-1/templates/actor/group/tab-inventory.hbs` }, + settings: { + template: `systems/DSA_4-1/templates/actor/group/tab-settings.hbs` + } } + constructor(options = {}) { + super(options); + } - static async onDroppedData(group, sheet, data) { - if (data.type === "Actor") { - const uuid = await foundry.utils.parseUuid(data.uuid); - const character = await (game.actors.get(uuid.id)) + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() - // check if character already is part of the group - if (group.system.characters.includes(character._id)) { - ui.notifications.warn(`${character.name} befindet sich bereits in der Heldengruppe ${group.name}`) - return false; + if (formData.object.name) { + await (game.folders.get(this.document.system.groupId)).update({name: formData.object.name}) + } + + await this.document.update(formData.object) // Note: formData.object + } + + #createDragDropHandlers() { + return this.options.dragDrop.map((d) => { + d.permissions = { + dragstart: this._canDragStart.bind(this), + drop: this._canDragDrop.bind(this) } - - - // update group - let settings = {...group.system.settings} - character.items.filter((i) => i.type === "Advantage").forEach((advantage) => { - if (!settings[sheet.#stringToKeyFieldName(advantage.name)]) { - settings[sheet.#stringToKeyFieldName(advantage.name)] = false - } - }) - character.items.filter((i) => i.type === "Skill").forEach((skill) => { - if (!settings[sheet.#stringToKeyFieldName(skill.name)]) { - settings[sheet.#stringToKeyFieldName(skill.name)] = false - } - }) - - await group.update({ - system: { - characters: [ - ...group.system.characters, - character._id - ], - settings: settings - } - }) - ui.notifications.info(`${character.name} ist der Heldengruppe ${group.name} beigetreten`) - } - if (data.type === "Equipment") { - const uuid = await foundry.utils.parseUuid(data.uuid); - const equipment = await (game.actors.get(uuid.id)) - ui.notifications.info(`${equipment.name} befindet sich nun im Inventar der Heldengruppe ${group.name}`) - return true; - } + d.callbacks = { + dragstart: this._onDragStart.bind(this), + dragover: this._onDragOver.bind(this), + drop: this._onDrop.bind(this) + } + return new DragDrop(d) + }) } #stringToKeyFieldName(s) { @@ -110,43 +109,47 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { console.log(evt) } - static async #removeFromParty(evt) { - const dataset = evt.srcElement.dataset; - const group = this.document; - const charactersWithoutMember = group.system.characters.filter(id => id !== dataset.id) - group.update({ - system: { - characters: charactersWithoutMember - } - }) + async #onUpdateCharacterSettings(data) { + if (data.type === "character") { + // update group + let settings = {...this.document.system.settings} + data.items.filter((i) => i.type === "Advantage").forEach((advantage) => { + if (!settings[this.#stringToKeyFieldName(advantage.name)]) { + settings[this.#stringToKeyFieldName(advantage.name)] = false + } + }) + data.items.filter((i) => i.type === "Skill").forEach((skill) => { + if (!settings[this.#stringToKeyFieldName(skill.name)]) { + settings[this.#stringToKeyFieldName(skill.name)] = false + } + }) + + await this.document.update({"system.settings": settings}) + } } - /** - * Handle form submission - * @this {AdvantageSheet} - * @param {SubmitEvent} event - * @param {HTMLFormElement} form - * @param {FormDataExtended} formData - */ - static async #onSubmitForm(event, form, formData) { - event.preventDefault() + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) - await this.document.update(formData.object) // Note: formData.object + // Modify tabs based on document properties + if (game.user.isGM) { + tabs.tabs.push({id: "settings", group: "sheet", label: "Einstellungen"}) + } + + return tabs } /** @override */ async _prepareContext(options) { const context = await super._prepareContext(options) - - // Use a safe clone of the actor data for further operations. - const groupData = context.document; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = groupData.system; - context.flags = groupData.flags; + const groupData = context.document + context.system = groupData.system + context.flags = groupData.flags context.characters = [] - context.isGM = game.user.isGM; + context.isGM = game.user.isGM + context.name = groupData.name + context.img = groupData.img context.fields = []; @@ -187,15 +190,8 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { if (!context.fields[n]) { context.fields[n] = {} } - const eigenschaften = Object.values(skill.system.probe); context.fields[n][character.name] = { - taw: skill.system.taw, - eigenschaft1: eigenschaften[0], - eigenschaft2: eigenschaften[1], - eigenschaft3: eigenschaften[2], - rollEigenschaft1: character.system.attribute[eigenschaften[0].toLowerCase()].aktuell, - rollEigenschaft2: character.system.attribute[eigenschaften[1].toLowerCase()].aktuell, - rollEigenschaft3: character.system.attribute[eigenschaften[2].toLowerCase()].aktuell, + taw: skill.system.taw ?? "0", name: skill.name, actor: character._id, } @@ -244,7 +240,7 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } _onRender(context, options) { - new ContextMenu(this.element, ".equipment", [ + /*ContextMenu.implementation.create(this, this.element, ".equipment", [ { name: "Aus dem Gruppeninventar entfernen", icon: '', @@ -255,7 +251,42 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } ], { jQuery: false + });*/ + + // Drag-drop + new foundry.applications.ux.DragDrop.implementation({ + dropSelector: ".inventory-table", + permissions: { + dragstart: this._canDragStart.bind(this), + drop: this._canDragDrop.bind(this) + }, + callbacks: { + dragstart: this._onDragStart.bind(this), + drop: this._onDrop.bind(this) + } + }).bind(this.element); + + // Update Group Members when either an Actor was moved into the linked Folder or removed from the linked Folder + Hooks.on('updateActor', (data) => { + if (data._id !== this.document._id) { // dont update yourself when you update yourself... baka! + if (data.type === "character" && data.folder?._id === this.document.system.groupId) { + this.#onUpdateCharacterSettings(data) + this.render() + } else if (data.type === "character") { + this.render() + } + } }); + } + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 + _onDrop(event) { + const data = event.dataTransfer.getData("application/json") + if (!data) return false + console.log(data) + + } + + } diff --git a/src/style/organisms/_group-sheet.scss b/src/style/organisms/_group-sheet.scss index 0f61f602..e246ff98 100644 --- a/src/style/organisms/_group-sheet.scss +++ b/src/style/organisms/_group-sheet.scss @@ -1,40 +1,14 @@ -.dsa41.sheet.actor.group { - - - .window-content { - display: unset; - position: relative; - } +.application.sheet.dsa41.actor.group { .sheet-header { - .sheet-name { - font-size: 24pt; - height: 48px; - } - } + display: grid; + grid-template-columns: 32px 1fr; + gap: 8px; - .sheet-tabs { - position: absolute; - left: 0; - right: 0; - top: 76px; - height: 32px; - padding: 0 16px; - } - - .sheet-body { - position: absolute; - top: 98px; - left: 0; - bottom: 0; - right: 0; - padding: 8px; - margin: 8px; - - div.tab { - height: 100%; - position: relative; + img { + height: 32px; + width: 32px; } } diff --git a/src/templates/actor/group/main-sheet.hbs b/src/templates/actor/group/main-sheet.hbs index 3ac4260f..38ccb4bf 100644 --- a/src/templates/actor/group/main-sheet.hbs +++ b/src/templates/actor/group/main-sheet.hbs @@ -1,6 +1,8 @@
+ {{name}}
diff --git a/src/templates/actor/group/tab-members.hbs b/src/templates/actor/group/tab-members.hbs index 7adc3411..60da70cd 100644 --- a/src/templates/actor/group/tab-members.hbs +++ b/src/templates/actor/group/tab-members.hbs @@ -59,18 +59,11 @@ {{#if (eq this "-")}} {{else}} - {{#if this.taw}} + {{#if (lt this.taw 0)}}
- {{this.taw}} ({{this.eigenschaft1}}, {{this.eigenschaft2}} - , {{this.eigenschaft3}}) + data-name="{{this.name}}"> + {{this.taw}}
{{else}} Ja diff --git a/src/templates/actor/group/tab-settings.hbs b/src/templates/actor/group/tab-settings.hbs new file mode 100644 index 00000000..d87adfa5 --- /dev/null +++ b/src/templates/actor/group/tab-settings.hbs @@ -0,0 +1,12 @@ +
+ +
    + {{#each system.settings}} +
    + +
    + {{/each}} +
+
\ No newline at end of file diff --git a/src/templates/ui/partial-equipment-button.hbs b/src/templates/ui/partial-equipment-button.hbs index f6503019..68121064 100644 --- a/src/templates/ui/partial-equipment-button.hbs +++ b/src/templates/ui/partial-equipment-button.hbs @@ -11,7 +11,7 @@ {{#each this}} - + {{this.name}} {{this.quantity}} -- 2.43.0 From f74bb38f3a8a5b46fecf6ac32436aab2e79e19f5 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 18:22:09 +0200 Subject: [PATCH 15/40] fixes groupsheet dragging and dropping --- src/module/sheets/characterSheet.mjs | 46 ++++++++--------- src/module/sheets/groupSheet.mjs | 57 ++++++++++++++++++--- src/templates/actor/group/tab-inventory.hbs | 2 +- 3 files changed, 73 insertions(+), 32 deletions(-) diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index af8fdb09..bb6f9d84 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -901,33 +901,33 @@ export class CharacterSheet extends foundry.appv1.sheets.ActorSheet { evt.stopPropagation(); } }) - - html.on('dragstart', '.equipment', (evt) => { - evt.originalEvent.dataTransfer.setData("application/json", JSON.stringify({ - documentId: evt.currentTarget.dataset.id - })); - }) - - html.on('drop', '.equipped', async (evt) => { - const {actor, target, setId} = evt.currentTarget.dataset; - try { - const {documentId} = JSON.parse(evt.originalEvent.dataTransfer.getData("application/json")); + /* + html.on('dragstart', '.equipment', (evt) => { + evt.originalEvent.dataTransfer.setData("application/json", JSON.stringify({ + documentId: evt.currentTarget.dataset.id + })); + })*/ + /* + html.on('drop', '.equipped', async (evt) => { + const {actor, target, setId} = evt.currentTarget.dataset; + try { + const {documentId} = JSON.parse(evt.originalEvent.dataTransfer.getData("application/json")); - if (actor === this.object._id && documentId) { // managing equipped items - //const slot = this.#isWorn(documentId, setId) - //const updateObject = await this.#getEquipmentset(Number(setId)) - const updateObject = this.#mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = documentId; - console.log(updateObject); + if (actor === this.object._id && documentId) { // managing equipped items + //const slot = this.#isWorn(documentId, setId) + //const updateObject = await this.#getEquipmentset(Number(setId)) + const updateObject = this.#mapAllSets() + updateObject[`system.heldenausruestung.${setId}.${target}`] = documentId; + console.log(updateObject); - await this.object.update(updateObject); - } + await this.object.update(updateObject); + } - evt.stopPropagation(); - } catch (e) { - } - }) + evt.stopPropagation(); + } catch (e) { + } + })*/ new foundry.applications.ux.ContextMenu(html[0], '.talent.rollable', [ { diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 3126e411..58ba836a 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -219,11 +219,11 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } } - context.equipments = []; + context.inventoryItems = []; const actorData = context.document; - Object.values(actorData.items).forEach((item, index) => { + actorData.items.forEach((item, index) => { if (item.type === "Equipment") { - context.equipments.push({ + context.inventoryItems.push({ index: index, id: item._id, quantity: item.system.quantity, @@ -255,6 +255,7 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { // Drag-drop new foundry.applications.ux.DragDrop.implementation({ + dragSelector: ".inventory-table .equipment", dropSelector: ".inventory-table", permissions: { dragstart: this._canDragStart.bind(this), @@ -280,13 +281,53 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } - // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 - _onDrop(event) { - const data = event.dataTransfer.getData("application/json") - if (!data) return false - console.log(data) + /** + * An event that occurs when a drag workflow begins for a draggable item on the sheet. + * @param {DragEvent} event The initiating drag start event + * @returns {Promise} + * @protected + */ + async _onDragStart(event) { + const target = event.currentTarget; + if ("link" in event.target.dataset) return; + let dragData; + // Owned Items + if (target.dataset.itemId) { + const item = this.actor.items.get(target.dataset.itemId); + dragData = item.toDragData(); + } + + // Active Effect + if (target.dataset.effectId) { + const effect = this.actor.effects.get(target.dataset.effectId); + dragData = effect.toDragData(); + } + + // Set data transfer + if (!dragData) return; + event.dataTransfer.setData("text/plain", JSON.stringify(dragData)); } + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + const actor = this.actor; + const allowed = Hooks.call("dropActorSheetData", actor, this, data); + if (allowed === false) return; + + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + const document = await documentClass.fromDropData(data); + await this._onDropDocument(event, document); + + // No duplication by moving items from one actor to another + if (document.parent) { + document.parent.items.get(document._id).delete() + } + await this._onDropDocument(event, document); + } + } } diff --git a/src/templates/actor/group/tab-inventory.hbs b/src/templates/actor/group/tab-inventory.hbs index f6107c7e..d238d631 100644 --- a/src/templates/actor/group/tab-inventory.hbs +++ b/src/templates/actor/group/tab-inventory.hbs @@ -14,7 +14,7 @@ {{#each inventoryItems}} - + {{this.name}} {{this.quantity}} -- 2.43.0 From 561e34d0ff9e9b86dac7b2c53e687a0a3e927e82 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 21:16:57 +0200 Subject: [PATCH 16/40] first push of charactersheet --- src/main.mjs | 2 +- src/module/sheets/character/attributes.mjs | 127 ++ src/module/sheets/character/combat.mjs | 112 ++ src/module/sheets/character/effects.mjs | 53 + src/module/sheets/character/equipment.mjs | 200 +++ src/module/sheets/character/liturgies.mjs | 109 ++ src/module/sheets/character/meta.mjs | 18 + src/module/sheets/character/skills.mjs | 81 + src/module/sheets/character/spells.mjs | 50 + src/module/sheets/characterSheet.mjs | 1406 ++++------------- src/module/sheets/groupSheet.mjs | 15 - src/templates/actor/actor-character-sheet.hbs | 814 ---------- src/templates/actor/character/main-sheet.hbs | 91 ++ .../actor/character/tab-attributes.hbs | 161 ++ src/templates/actor/character/tab-combat.hbs | 100 ++ src/templates/actor/character/tab-effects.hbs | 27 + .../actor/character/tab-equipment.hbs | 85 + .../actor/character/tab-liturgies.hbs | 202 +++ src/templates/actor/character/tab-meta.hbs | 49 + src/templates/actor/character/tab-skills.hbs | 85 + src/templates/actor/character/tab-spells.hbs | 49 + 21 files changed, 1947 insertions(+), 1889 deletions(-) create mode 100644 src/module/sheets/character/attributes.mjs create mode 100644 src/module/sheets/character/combat.mjs create mode 100644 src/module/sheets/character/effects.mjs create mode 100644 src/module/sheets/character/equipment.mjs create mode 100644 src/module/sheets/character/liturgies.mjs create mode 100644 src/module/sheets/character/meta.mjs create mode 100644 src/module/sheets/character/skills.mjs create mode 100644 src/module/sheets/character/spells.mjs delete mode 100644 src/templates/actor/actor-character-sheet.hbs create mode 100644 src/templates/actor/character/main-sheet.hbs create mode 100644 src/templates/actor/character/tab-attributes.hbs create mode 100644 src/templates/actor/character/tab-combat.hbs create mode 100644 src/templates/actor/character/tab-effects.hbs create mode 100644 src/templates/actor/character/tab-equipment.hbs create mode 100644 src/templates/actor/character/tab-liturgies.hbs create mode 100644 src/templates/actor/character/tab-meta.hbs create mode 100644 src/templates/actor/character/tab-skills.hbs create mode 100644 src/templates/actor/character/tab-spells.hbs diff --git a/src/main.mjs b/src/main.mjs index 21a59bc2..89239448 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -5,7 +5,7 @@ import {SkillDataModel} from "./module/data/skill.mjs"; import {SpellDataModel} from "./module/data/spell.mjs"; import {VornachteileDataModel} from "./module/data/vornachteile.mjs"; import {Character} from "./module/documents/character.mjs"; -import {CharacterSheet} from "./module/sheets/characterSheet.mjs"; +import CharacterSheet from "./module/sheets/characterSheet.mjs"; import {AdvantageSheet} from "./module/sheets/advantageSheet.mjs"; import {GroupDataModel} from "./module/data/group.mjs"; import {GroupSheet} from "./module/sheets/groupSheet.mjs"; diff --git a/src/module/sheets/character/attributes.mjs b/src/module/sheets/character/attributes.mjs new file mode 100644 index 00000000..230caa62 --- /dev/null +++ b/src/module/sheets/character/attributes.mjs @@ -0,0 +1,127 @@ +export default { + _prepareContext: async (context, options, object) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + context.advantages = [] + + const getModsOfAttribute = async (keyPath, object) => { + let returnValue = []; + Array.from(object.appliedEffects).forEach( + (e) => + e.changes.filter(c => c.key === keyPath).forEach(change => { + returnValue.push({ + name: e.name, + value: change.value > 0 ? "+" + change.value : "" + change.value, + icon: e.icon, + }) + })) + return returnValue; + } + + context.mods = { + "mu": await getModsOfAttribute('system.attribute.mu.mod', actorData), + "kl": await getModsOfAttribute('system.attribute.kl.mod', actorData), + "in": await getModsOfAttribute('system.attribute.in.mod', actorData), + "ch": await getModsOfAttribute('system.attribute.ch.mod', actorData), + "ff": await getModsOfAttribute('system.attribute.ff.mod', actorData), + "ge": await getModsOfAttribute('system.attribute.ge.mod', actorData), + "ko": await getModsOfAttribute('system.attribute.ko.mod', actorData), + "kk": await getModsOfAttribute('system.attribute.kk.mod', actorData), + "at": await getModsOfAttribute('system.at.mod', actorData), + "pa": await getModsOfAttribute('system.pa.mod', actorData), + "fk": await getModsOfAttribute('system.fk.mod', actorData), + + } + context.attributes = [ + { + eigenschaft: "mu", + name: "MU", + tooltip: "Mut", + wert: context.derived.attribute.mu.aktuell ?? 0, + }, + { + eigenschaft: "kl", + name: "KL", + tooltip: "Klugheit", + wert: context.derived.attribute.kl.aktuell ?? 0, + }, + { + eigenschaft: "in", + name: "IN", + tooltip: "Intuition", + wert: context.derived.attribute.in.aktuell ?? 0, + }, + { + eigenschaft: "ch", + name: "CH", + tooltip: "Charisma", + wert: context.derived.attribute.ch.aktuell ?? 0, + }, + { + eigenschaft: "ff", + name: "FF", + tooltip: "Fingerfertigkeit", + wert: context.derived.attribute.ff.aktuell ?? 0, + }, + { + eigenschaft: "ge", + name: "GE", + tooltip: "Geschicklichkeit", + wert: context.derived.attribute.ge.aktuell ?? 0, + }, + { + eigenschaft: "ko", + name: "KO", + tooltip: "Konstitution", + wert: context.derived.attribute.ko.aktuell ?? 0, + }, + { + eigenschaft: "kk", + name: "KK", + tooltip: "Körperkraft", + wert: context.derived.attribute.kk.aktuell ?? 0, + }, + + ] + + Object.values(actorData.items).forEach((item) => { + if (item.type === "Advantage") { + context.advantages.push({ + id: item._id, + name: item.name, + value: item.system.value, + options: item.system.auswahl, + description: item.system.description, + isAdvantage: !item.system.nachteil, + isDisadvantage: item.system.nachteil, + isBadAttribute: item.system.schlechteEigenschaft + }); + } + } + ); + + context.specialAbilities = []; + Object.values(actorData.items).forEach((item) => { + if (item.type === "SpecialAbility") { + context.specialAbilities.push({ + id: item._id, + name: item.name, + }); + } + } + ); + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "attributes", group: "sheet", label: "Eigenschaften"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-attributes.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/combat.mjs b/src/module/sheets/character/combat.mjs new file mode 100644 index 00000000..ab4d9b48 --- /dev/null +++ b/src/module/sheets/character/combat.mjs @@ -0,0 +1,112 @@ +import {ActionManager} from "../actions/action-manager.mjs"; + +export default { + _prepareContext: async (context, object) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const findEquipmentOnSlot = (slot, setNumber, object) => { + return object.items.get(object.system.heldenausruestung[setNumber]?.[slot]) + } + + const am = new ActionManager(actorData) + context.actions = am.evaluate() + + + context.inidice = actorData.system.ini.wuerfel + context.inivalue = actorData.system.ini.aktuell + context.inimod = actorData.system.ini.mod + + context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100) + context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100) + context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100) + context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100) + context.lepcurrent = actorData.system.lep.aktuell ?? 0 + + context.aupcurrent = actorData.system.aup.aktuell ?? 0 + + const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) + const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) + const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) + context.attacks = []; + + if (fernkampf) { + const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion)) + fkitems.forEach(async skill => { + const obj = await skill + context.attacks.push({ + name: obj.name, + using: fernkampf.name, + atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`, + at: `${object.system.fk.aktuell + obj.system.at}`, + tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod + tp: `${fernkampf.system.rangedAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + }) + }) + } + if (links) { + const meitems = [] + links.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: links.name, + atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, + tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${links.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + }) + }) + } + if (rechts) { + const meitems = [] + rechts.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: rechts.name, + atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, + tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${rechts.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + }) + }) + } + + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "combat", group: "sheet", label: "Kampf"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-combat.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/effects.mjs b/src/module/sheets/character/effects.mjs new file mode 100644 index 00000000..6c817e7d --- /dev/null +++ b/src/module/sheets/character/effects.mjs @@ -0,0 +1,53 @@ +export default { + _prepareContext: (context, object) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + context.isGM = game.user.isGM + context.effects = [] + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "ActiveEffect") { + const effect = item.effects[0]; + const conditions = [] + + if (effect) { + effect.changes.forEach(change => { + if (change.key.indexOf("wunden") === -1) { + const key = change.key + .replace(/system\./g, "") + .replace(/\.mod/g, "") + .replace(/attribute./g, "") + .replace(/.links/g, "(Links)") + .replace(/.rechts/g, "(Rechts)") + const value = Number(change.value) > 0 ? "+" + change.value : change.value + conditions.push( + `${key}${value}` + ) + } + }) + } + + context.effects.push({ + name: item.name, + conditions: conditions.join(" "), + id: item._id, + actor: actorData._id + }); + } + }) + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "effects", group: "sheet", label: "Effekte"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-effects.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs new file mode 100644 index 00000000..680a0538 --- /dev/null +++ b/src/module/sheets/character/equipment.mjs @@ -0,0 +1,200 @@ +import {PlayerCharacterDataModel} from "../../data/character.mjs"; + +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const isWorn = (itemId, object) => { + + const slots = PlayerCharacterDataModel.getSlots() + const set = object.system.heldenausruestung[object.system.setEquipped] + if (set) { + for (const slot of slots) { + const equipmentSlotId = set[slot] + if (equipmentSlotId === itemId) { + return slot + } + } + } + + return false + } + + context.equipments = [] + context.carryingweight = 0 + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Equipment") { + + // worn items are halved weight + + let effectiveWeight = item.system.weight ?? 0 + if (isWorn(item._id, object)) { + effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 + } + + context.equipments.push({ + index: index, + id: item._id, + quantity: item.system.quantity, + name: item.name, + icon: item.img ?? "", + weight: item.system.weight, + worn: isWorn(item._id, object) + }) + context.carryingweight += item.system.quantity * effectiveWeight; + } + }) + context.maxcarryingcapacity = actorData.system.attribute.kk.aktuell + context.carryingpercentage = Math.min((context.carryingweight / context.maxcarryingcapacity) * 100, 100); + + const maxSets = 3 + const romanNumerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] + context.sets = [] + for (let setIndex = 0; setIndex < maxSets; setIndex++) { + + context.sets.push({ + tab: "set" + (setIndex + 1), + name: romanNumerals[setIndex], + index: setIndex, + slots: [ + { + target: "links", + id: actorData.system.heldenausruestung[setIndex]?.links, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.img + }, + { + target: "rechts", + id: actorData.system.heldenausruestung[setIndex]?.rechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.img + }, + { + target: "brust", + id: actorData.system.heldenausruestung[setIndex]?.brust, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.img + }, + { + target: "ruecken", + id: actorData.system.heldenausruestung[setIndex]?.ruecken, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.img + }, + { + target: "kopf", + id: actorData.system.heldenausruestung[setIndex]?.kopf, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.img + }, + { + target: "fernkampf", + id: actorData.system.heldenausruestung[setIndex]?.fernkampf, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.img + }, + { + target: "munition", + id: actorData.system.heldenausruestung[setIndex]?.munition, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.img + }, + { + target: "armlinks", + id: actorData.system.heldenausruestung[setIndex]?.armlinks, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.img + }, + { + target: "armrechts", + id: actorData.system.heldenausruestung[setIndex]?.armrechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.img + }, + { + target: "bauch", + id: actorData.system.heldenausruestung[setIndex]?.bauch, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.img + }, + { + target: "beinlinks", + id: actorData.system.heldenausruestung[setIndex]?.beinlinks, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.img + }, + { + target: "beinrechts", + id: actorData.system.heldenausruestung[setIndex]?.beinrechts, + name: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.name, + icon: actorData.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.img + } + ] + }) + } + }, + _onRender: (context, options, element) => { + const mapAllSets = () => { + const updateObject = {} + Array.from(context.document.system.heldenausruestung).forEach((equipmentSet, index) => { + updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; + updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; + updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; + updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; + updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; + updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; + updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; + updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; + updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; + updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; + updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; + updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; + + }) + return updateObject; + } + + new foundry.applications.ux.ContextMenu(element, '.equipped', [ + { + name: "Gegenstand vom Set entfernen", + callback: (event) => { + const {setId, target, actor} = event[0].dataset + + const updateObject = mapAllSets() + updateObject[`system.heldenausruestung.${setId}.${target}`] = null; + + object.update(updateObject); + }, + condition: () => true + } + ], { + jQuery: false + }); + + new foundry.applications.ux.ContextMenu(element, '.equipment', [ + { + name: "Aus dem Inventar entfernen", + icon: '', + callback: (event) => { + // TODO find id on heldenausruestung to remove the worn items as well + object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) + }, + condition: () => true + } + ], { + jQuery: false + }); + }, + _getTabConfig: (group) => { + group.tabs.push({id: "equipment", group: "sheet", label: "Ausrüstung"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-equipment.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/liturgies.mjs b/src/module/sheets/character/liturgies.mjs new file mode 100644 index 00000000..196ac767 --- /dev/null +++ b/src/module/sheets/character/liturgies.mjs @@ -0,0 +1,109 @@ +import {LiturgyData} from "../../data/miracle/liturgydata.mjs"; + +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + + context.effects = actorData.effects ?? [] + context.liturgies = []; + context.blessings = []; + + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Blessing") { + context.blessings.push({ + deity: item.system.gottheit, + value: item.system.wert + }) + } + }) + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Liturgy") { + + context.blessings.forEach(({deity, value}) => { + let insertObject = context.liturgies.find(p => p.deity === deity); + if (!insertObject) { + insertObject = { + deity: deity, + lkp: value, + O: [], + I: [], + II: [], + III: [], + IV: [], + V: [], + VI: [], + VII: [], + VIII: [], + "NA": [], + countO: 1, + countI: 1, + countII: 1, + countIII: 1, + countIV: 1, + countV: 1, + countVI: 1, + countVII: 1, + countVIII: 1, + countNA: 0, + total: 3, + + } + context.liturgies.push(insertObject); + } + + // sort by rank + const rankData = LiturgyData.getRankOfLiturgy(item.system, deity) + if (rankData) { + let {index, name, lkp, mod, costKaP} = rankData; + + insertObject["count" + name] = insertObject["count" + name] + 1; + + insertObject[name].push({ + id: item._id, + name: item.name, + lkpReq: lkp, + lkpMod: mod, + costKaP, + rank: index, // get effective liturgy rank based on deity + liturgiekenntnis: deity, + }) + insertObject.total = insertObject.total + 2; + + } + }) + } + }) + + + // clean up counter + Object.values(context.liturgies).forEach((litObject) => { + + if (litObject.I.length === 0) litObject.countI = false; + if (litObject.II.length === 0) litObject.countII = false; + if (litObject.III.length === 0) litObject.countIII = false; + if (litObject.IV.length === 0) litObject.countIV = false; + if (litObject.V.length === 0) litObject.countV = false; + if (litObject.VI.length === 0) litObject.countVI = false; + if (litObject.VII.length === 0) litObject.countVII = false; + if (litObject.VIII.length === 0) litObject.countVIII = false; + if (litObject.NA.length === 0) litObject.countNA = false; + + + }) + + context.hasLiturgies = context.blessings.length > 0; + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "liturgies", group: "sheet", label: "Liturgien"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-liturgies.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/meta.mjs b/src/module/sheets/character/meta.mjs new file mode 100644 index 00000000..75ed6f50 --- /dev/null +++ b/src/module/sheets/character/meta.mjs @@ -0,0 +1,18 @@ +export default { + _prepareContext: (context, object) => { + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "meta", group: "sheet", label: "Meta"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-meta.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs new file mode 100644 index 00000000..78e6b307 --- /dev/null +++ b/src/module/sheets/character/skills.mjs @@ -0,0 +1,81 @@ +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const prepareEigenschaftRoll = (actorData, name) => { + if (name && name !== "*") { + return actorData.system.attribute[name.toLowerCase()].aktuell + } else { + return 0 + } + } + + + context.skills = {}; + context.flatSkills = []; + + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Skill") { + + const talentGruppe = item.system.gruppe; + const eigenschaften = Object.values(item.system.probe); + const werte = [ + {name: eigenschaften[0], value: prepareEigenschaftRoll(actorData, eigenschaften[0])}, + {name: eigenschaften[1], value: prepareEigenschaftRoll(actorData, eigenschaften[1])}, + {name: eigenschaften[2], value: prepareEigenschaftRoll(actorData, eigenschaften[2])} + ] + if (context.skills[talentGruppe] == null) { + context.skills[talentGruppe] = []; + } + const obj = { + type: "talent", + gruppe: talentGruppe, + name: item.name, + taw: "" + item.system.taw, + tawPath: `system.items.${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("/")})`, + id: item._id, + at: item.system.at, + pa: item.system.pa, + komplexität: item.system.komplexität + }; + + if (talentGruppe === "Kampf") { + + if (item.system.pa != null) { // has no parry value so it must be ranged talent (TODO: but it isnt as there can be combatstatistics which has no pa value assigned to) + obj.at = item.system.at + context.derived.at.aktuell + obj.pa = item.system.pa + context.derived.pa.aktuell + } else { + obj.at = item.system.at + context.derived.fk.aktuell + } + } + + context.skills[talentGruppe].push(obj); + context.flatSkills.push(obj); + } + } + ); + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "skills", group: "sheet", label: "Talente"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-skills.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/spells.mjs b/src/module/sheets/character/spells.mjs new file mode 100644 index 00000000..9c33ad0d --- /dev/null +++ b/src/module/sheets/character/spells.mjs @@ -0,0 +1,50 @@ +export default { + _prepareContext: (context) => { + + const actorData = context.document + context.spells = [] + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + const cleanUpMerkmal = (merkmale) => { + return merkmale.split(",").map((merkmal) => merkmal.trim()) + } + + + Object.values(actorData.items).forEach((item, index) => { + if (item.type === "Spell") { + const eigenschaften = item.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])} + ] + context.spells.push({ + id: item._id, + name: item.name, + zfw: item.system.zfw, + hauszauber: item.system.hauszauber, + merkmal: cleanUpMerkmal(item.system.merkmal), + rollEigenschaft1: werte[0].value, + rollEigenschaft2: werte[1].value, + rollEigenschaft3: werte[2].value, + eigenschaft1: werte[0].name, + eigenschaft2: werte[1].name, + eigenschaft3: werte[2].name, + }) + } + }) + context.hasSpells = context.spells.length > 0; + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "spells", group: "sheet", label: "Zauber"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-spells.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index bb6f9d84..69716a1b 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -1,145 +1,163 @@ -import {PlayerCharacterDataModel} from "../data/character.mjs"; -import {ActionManager} from "./actions/action-manager.mjs"; -import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {ModifyLiturgy} from "../dialog/modify-liturgy.mjs"; +import Meta from "./character/meta.mjs" +import Attributes from "./character/attributes.mjs" +import Combat from "./character/combat.mjs" +import Equipment from "./character/equipment.mjs" +import Skills from "./character/skills.mjs" +import Spells from "./character/spells.mjs" +import Liturgies from "./character/liturgies.mjs" +import Effects from "./character/effects.mjs" -export class CharacterSheet extends foundry.appv1.sheets.ActorSheet { - /**@override */ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ['dsa41', 'sheet', 'actor', 'character'], - width: 1100, - height: 480, +const {HandlebarsApplicationMixin} = foundry.applications.api +const {ActorSheetV2} = foundry.applications.sheets +const {ContextMenu} = foundry.applications.ux + + +class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 1100, height: 640}, + classes: ['dsa41', 'sheet', 'actor', 'character'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CharacterSheet.#onSubmitForm + }, + window: { + resizable: true, + }, + actions: { + roll: CharacterSheet.#dieRoll, + editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, + openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument, + } + } + + static TABS = { + sheet: { tabs: [ - { - navSelector: '.sheet-tabs', - contentSelector: '.sheet-body', - initial: 'description', - }, + {id: 'meta', group: 'sheet', label: 'Meta'}, ], - }); - } - - /** @override */ - get template() { - return `systems/DSA_4-1/templates/actor/actor-character-sheet.hbs`; - } - - static onDroppedData(actor, characterSheet, data) { - 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": - return characterSheet.#handleDroppedSkill(actor, document); // on false cancel this whole operation - case "Advantage": - return characterSheet.#handleDroppedAdvantage(actor, document); - case "ActiveEffect": - return characterSheet.#handleDroppedActiveEffect(actor, document); - case "Equipment": - return characterSheet.#handleDroppedEquipment(actor, document); - case "Liturgy": - return characterSheet.#handleDroppedLiturgy(actor, document); - case "SpecialAbility": - return characterSheet.#handleDroppedSpecialAbility(actor, document); - default: - return false; - } - - } - - static getElementByName(collection, id) { - const array = Array.from(collection); - for (const element of array) { - if (element._id === id) { - return element; - } + initial: 'meta' } } - #addSkillsToContext(context) { - const actorData = context.data; - context.skills = {}; - context.flatSkills = []; - - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Skill") { - - 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])}, - {name: eigenschaften[2], value: this.prepareEigenschaftRoll(actorData, eigenschaften[2])} - ] - if (context.skills[talentGruppe] == null) { - context.skills[talentGruppe] = []; - } - const obj = { - type: "talent", - gruppe: talentGruppe, - name: item.name, - taw: "" + item.system.taw, - tawPath: `system.items.${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("/")})`, - id: item._id, - at: item.system.at, - pa: item.system.pa, - komplexität: item.system.komplexität - }; - - if (talentGruppe === "Kampf") { - - if (item.system.pa != null) { // has no parry value so it must be ranged talent (TODO: but it isnt as there can be combatstatistics which has no pa value assigned to) - obj.at = item.system.at + context.derived.at.aktuell - obj.pa = item.system.pa + context.derived.pa.aktuell - } else { - obj.at = item.system.at + context.derived.fk.aktuell - } - } - - context.skills[talentGruppe].push(obj); - context.flatSkills.push(obj); - } - } - ); + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/actor/character/main-sheet.hbs` + }, + meta: { + template: Meta.template + }, + attributes: { + template: Attributes.template + }, + combat: { + template: Combat.template + }, + equipment: { + template: Equipment.template + }, + skills: { + template: Skills.template + }, + liturgies: { + template: Liturgies.template + }, + effects: { + template: Effects.template + } } - #cleanUpMerkmal(merkmale) { - return merkmale.split(",").map((merkmal) => merkmal.trim()) + static #dieRoll(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 + } + } + + static #openEmbeddedDocument(documentId) { + this.object.items.get(documentId).sheet.render(true) + } + + /** + * Handle form submission + * @this {AdvantageSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + Attributes._getTabConfig(tabs) + Combat._getTabConfig(tabs) + Equipment._getTabConfig(tabs) + Skills._getTabConfig(tabs) + Spells._getTabConfig(tabs) + Liturgies._getTabConfig(tabs) + Effects._getTabConfig(tabs) + return tabs + } + + async _preparePartContext(partId, context) { + switch (partId) { + case "meta": + Meta._prepareContext(context, this.object) + break + case "attributes": + await Attributes._prepareContext(context, this.object) + break + case "combat": + await Combat._prepareContext(context, this.object) + break + case "equipment": + Equipment._prepareContext(context, this.object) + break + case "skills": + Skills._prepareContext(context, this.object) + break + case "spells": + Spells._prepareContext(context, this.object) + break + case "liturgies": + Liturgies._prepareContext(context, this.object) + break + case "effects": + Effects._prepareContext(context, this.object) + break + } } /** @override */ - async getData() { - const context = super.getData(); + async _prepareContext(options) { + const context = await super._prepareContext(options) + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] - - // Use a safe clone of the actor data for further operations. - const actorData = context.data; - - // Add the actor's data to context.data for easier access, as well as flags. - context.system = actorData.system; - context.flags = actorData.flags; - context.derived = context.document.system; - context.originalName = actorData.name; - context.name = context.derived.name ?? actorData.name; - context.effects = actorData.effects ?? []; - - context.maxWounds = actorData.system.wunden.max ?? 3; - context.wounds = actorData.system.wunden.aktuell ?? 0; - context.woundsFilled = []; + context.maxWounds = actorData.system.wunden.max ?? 3 + context.wounds = actorData.system.wunden.aktuell ?? 0 + context.woundsFilled = [] for (let i = 1; i <= context.maxWounds; i++) { context.woundsFilled[i] = i <= context.wounds } @@ -148,950 +166,220 @@ export class CharacterSheet extends foundry.appv1.sheets.ActorSheet { context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") - - this.#addEffectsToContext(context) - this.#addSkillsToContext(context) - this.#addAdvantagesToContext(context) - this.#addSpecialAbilitiesToContext(context) - await this.#addAttributesToContext(context) - this.#addEquipmentsToContext(context) - await this.#addCombatStatistics(context) - this.#addActionsToContext(context) - this.#addSpellsToContext(context) - this.#addLiturgiesToContext(context) return context; } - #addEffectsToContext(context) { - const actorData = context.data; + _onRender(context, options) { + Meta._onRender(context, options, this.element) + Attributes._onRender(context, options, this.element) + Combat._onRender(context, options, this.element) + Effects._onRender(context, options, this.element) + Equipment._onRender(context, options, this.element) + Liturgies._onRender(context, options, this.element) + Skills._onRender(context, options, this.element) + Spells._onRender(context, options, this.element) + } - context.isGM = game.user.isGM - context.effects = []; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "ActiveEffect") { - const effect = item.effects[0]; - const conditions = [] + /* showAdjustAttributeDialog(attributeName, attributeField, previousValue) { + const thisActor = this; + const myContent = ` + Value: + + `; - if (effect) { - effect.changes.forEach(change => { - if (change.key.indexOf("wunden") === -1) { - const key = change.key - .replace(/system\./g, "") - .replace(/\.mod/g, "") - .replace(/attribute./g, "") - .replace(/.links/g, "(Links)") - .replace(/.rechts/g, "(Rechts)") - const value = Number(change.value) > 0 ? "+" + change.value : change.value; - conditions.push( - `${key}${value}` - ) - } - }) + function updateAttribute(html) { + const value = html.find("input#attributeValue").val(); + const attribute = {} + attribute[attributeField.toLowerCase()] = { + aktuell: value } - - context.effects.push({ - name: item.name, - conditions: conditions.join(" "), - id: item._id, - actor: actorData._id - }); + thisActor.object.update({system: {attribute}}) } - }) - } - #addSpellsToContext(context) { - const actorData = context.data; - context.spells = []; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Spell") { - const eigenschaften = item.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])} - ] - context.spells.push({ - id: item._id, - name: item.name, - zfw: item.system.zfw, - hauszauber: item.system.hauszauber, - merkmal: this.#cleanUpMerkmal(item.system.merkmal), - rollEigenschaft1: werte[0].value, - rollEigenschaft2: werte[1].value, - rollEigenschaft3: werte[2].value, - eigenschaft1: werte[0].name, - eigenschaft2: werte[1].name, - eigenschaft3: werte[2].name, - }) - } - }) - context.hasSpells = context.spells.length > 0; - } - - async #getModsOfAttribute(keyPath) { - let returnValue = []; - Array.from(this.object.appliedEffects).forEach( - (e) => - e.changes.filter(c => c.key === keyPath).forEach(change => { - returnValue.push({ - name: e.name, - value: change.value > 0 ? "+" + change.value : "" + change.value, - icon: e.icon, - }) - })) - return returnValue; - } - - async #addAttributesToContext(context) { - context.mods = { - "mu": await this.#getModsOfAttribute('system.attribute.mu.mod'), - "kl": await this.#getModsOfAttribute('system.attribute.kl.mod'), - "in": await this.#getModsOfAttribute('system.attribute.in.mod'), - "ch": await this.#getModsOfAttribute('system.attribute.ch.mod'), - "ff": await this.#getModsOfAttribute('system.attribute.ff.mod'), - "ge": await this.#getModsOfAttribute('system.attribute.ge.mod'), - "ko": await this.#getModsOfAttribute('system.attribute.ko.mod'), - "kk": await this.#getModsOfAttribute('system.attribute.kk.mod'), - "at": await this.#getModsOfAttribute('system.at.mod'), - "pa": await this.#getModsOfAttribute('system.pa.mod'), - "fk": await this.#getModsOfAttribute('system.fk.mod'), - - } - context.attributes = [ - { - eigenschaft: "mu", - name: "MU", - tooltip: "Mut", - wert: context.derived.attribute.mu.aktuell ?? 0, - }, - { - eigenschaft: "kl", - name: "KL", - tooltip: "Klugheit", - wert: context.derived.attribute.kl.aktuell ?? 0, - }, - { - eigenschaft: "in", - name: "IN", - tooltip: "Intuition", - wert: context.derived.attribute.in.aktuell ?? 0, - }, - { - eigenschaft: "ch", - name: "CH", - tooltip: "Charisma", - wert: context.derived.attribute.ch.aktuell ?? 0, - }, - { - eigenschaft: "ff", - name: "FF", - tooltip: "Fingerfertigkeit", - wert: context.derived.attribute.ff.aktuell ?? 0, - }, - { - eigenschaft: "ge", - name: "GE", - tooltip: "Geschicklichkeit", - wert: context.derived.attribute.ge.aktuell ?? 0, - }, - { - eigenschaft: "ko", - name: "KO", - tooltip: "Konstitution", - wert: context.derived.attribute.ko.aktuell ?? 0, - }, - { - eigenschaft: "kk", - name: "KK", - tooltip: "Körperkraft", - wert: context.derived.attribute.kk.aktuell ?? 0, - }, - - ]; - - } - - #addAdvantagesToContext(context) { - context.advantages = []; - const actorData = context.data; - Object.values(actorData.items).forEach((item) => { - if (item.type === "Advantage") { - context.advantages.push({ - id: item._id, - name: item.name, - value: item.system.value, - options: item.system.auswahl, - description: item.system.description, - isAdvantage: !item.system.nachteil, - isDisadvantage: item.system.nachteil, - isBadAttribute: item.system.schlechteEigenschaft - }); - } - } - ); - } - - #addSpecialAbilitiesToContext(context) { - context.specialAbilities = []; - const actorData = context.data; - Object.values(actorData.items).forEach((item) => { - if (item.type === "SpecialAbility") { - context.specialAbilities.push({ - id: item._id, - name: item.name, - }); - } - } - ); - } - - #findEquipmentOnSlot(slot, setNumber) { - return this.object.items.get(this.object.system.heldenausruestung[setNumber]?.[slot]) - } - - #addActionsToContext(context) { - const am = new ActionManager(this.object) - context.actions = am.evaluate() - } - - #isWorn(itemId) { - - const slots = PlayerCharacterDataModel.getSlots() - const set = this.object.system.heldenausruestung[this.object.system.setEquipped] - if (set) { - for (const slot of slots) { - const equipmentSlotId = set[slot] - if (equipmentSlotId === itemId) { - return slot - } - } - } - - return false - } - - async #addCombatStatistics(context) { - const actorData = context.data; - - context.inidice = actorData.system.ini.wuerfel; - context.inivalue = actorData.system.ini.aktuell; - context.inimod = actorData.system.ini.mod; - - context.aupper = Math.min((context.actor.system.aup.aktuell / context.actor.system.aup.max) * 100, 100); - context.lepper = Math.min((context.actor.system.lep.aktuell / context.actor.system.lep.max) * 100, 100); - context.keper = Math.min((context.actor.system.kap.aktuell / context.actor.system.kap.max) * 100, 100); - context.aspper = Math.min((context.actor.system.asp.aktuell / context.actor.system.asp.max) * 100, 100); - context.lepcurrent = context.actor.system.lep.aktuell ?? 0 - - context.aupcurrent = context.actor.system.aup.aktuell ?? 0 - - const fernkampf = this.#findEquipmentOnSlot("fernkampf", context.actor.system.setEquipped) - const links = this.#findEquipmentOnSlot("links", context.actor.system.setEquipped) - const rechts = this.#findEquipmentOnSlot("rechts", context.actor.system.setEquipped) - context.attacks = []; - - if (fernkampf) { - const fkitems = fernkampf.system.rangedSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - fkitems.forEach(async skill => { - const obj = await skill - context.attacks.push({ - name: obj.name, - using: fernkampf.name, - atroll: `1d20cs<${this.object.system.fk.aktuell + obj.system.at}`, - at: `${this.object.system.fk.aktuell + obj.system.at}`, - tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod - tp: `${fernkampf.system.rangedAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, - }) - }) - } - if (links) { - const meitems = links.system.meleeSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - meitems.forEach(async skill => { - const obj = await skill - context.attacks.push({ - name: obj.name, - using: links.name, - atroll: `1d20cs<${this.object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M - at: `${this.object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, - paroll: `1d20cs<${this.object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M - pa: `${this.object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, - tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod - tp: `${links.system.meleeAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, - }) - }) - } - if (rechts) { - const meitems = rechts.system.meleeSkills.map(async (skillInQuestion) => await this.object.items.getName(skillInQuestion)) - meitems.forEach(async skill => { - const obj = await skill - console.log(this.object.system.at) - context.attacks.push({ - name: obj.name, - using: rechts.name, - atroll: `1d20cs<${this.object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M - at: `${this.object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, - paroll: `1d20cs<${this.object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M - pa: `${this.object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, - tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod - tp: `${rechts.system.meleeAttackDamage}`, - iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, - ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, - }) - }) - } - - // add weapons to sidebar - } - - prepareEigenschaftRoll(actorData, name) { - if (name && name !== "*") { - return actorData.system.attribute[name.toLowerCase()].aktuell - } else { - return 0 - } - } - - #addEquipmentsToContext(context) { - context.equipments = []; - const actorData = context.data; - context.carryingweight = 0; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Equipment") { - - // worn items are halved weight - - let effectiveWeight = item.system.weight ?? 0 - if (this.#isWorn(item._id)) { - effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 - } - - context.equipments.push({ - index: index, - id: item._id, - quantity: item.system.quantity, - name: item.name, - icon: item.img ?? "", - weight: item.system.weight, - worn: this.#isWorn(item._id) - }) - context.carryingweight += item.system.quantity * effectiveWeight; - } - }) - context.maxcarryingcapacity = actorData.system.attribute.kk.aktuell - context.carryingpercentage = Math.min((context.carryingweight / context.maxcarryingcapacity) * 100, 100); - - const maxSets = 3 - const romanNumerals = ["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"] - context.sets = [] - for (let setIndex = 0; setIndex < maxSets; setIndex++) { - - context.sets.push({ - tab: "set" + (setIndex + 1), - name: romanNumerals[setIndex], - index: setIndex, - slots: [ - { - target: "links", - id: this.object.system.heldenausruestung[setIndex]?.links, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.links)?.img - }, - { - target: "rechts", - id: this.object.system.heldenausruestung[setIndex]?.rechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.rechts)?.img - }, - { - target: "brust", - id: this.object.system.heldenausruestung[setIndex]?.brust, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.brust)?.img - }, - { - target: "ruecken", - id: this.object.system.heldenausruestung[setIndex]?.ruecken, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.ruecken)?.img - }, - { - target: "kopf", - id: this.object.system.heldenausruestung[setIndex]?.kopf, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.kopf)?.img - }, - { - target: "fernkampf", - id: this.object.system.heldenausruestung[setIndex]?.fernkampf, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.fernkampf)?.img - }, - { - target: "munition", - id: this.object.system.heldenausruestung[setIndex]?.munition, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.munition)?.img - }, - { - target: "armlinks", - id: this.object.system.heldenausruestung[setIndex]?.armlinks, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armlinks)?.img - }, - { - target: "armrechts", - id: this.object.system.heldenausruestung[setIndex]?.armrechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.armrechts)?.img - }, - { - target: "bauch", - id: this.object.system.heldenausruestung[setIndex]?.bauch, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.bauch)?.img - }, - { - target: "beinlinks", - id: this.object.system.heldenausruestung[setIndex]?.beinlinks, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinlinks)?.img - }, - { - target: "beinrechts", - id: this.object.system.heldenausruestung[setIndex]?.beinrechts, - name: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.name, - icon: this.object.items.get(actorData.system.heldenausruestung[setIndex]?.beinrechts)?.img - } - ] - }) - } - } - - 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; - } - } - - openEmbeddedDocument(documentId) { - this.object.items.get(documentId).sheet.render(true) - } - - _onRoll(event) { - event.preventDefault(); - const dataset = event.currentTarget.dataset; - if (dataset.roll) { - let label = dataset.label ? `${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; - } - } - - #mapAllSets() { - const updateObject = {} - Array.from(this.object.system.heldenausruestung).forEach((equipmentSet, index) => { - updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; - updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; - updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; - updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; - updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; - updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; - updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; - updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; - updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; - updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; - updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; - updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; - - }) - return updateObject; - } - - 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); - - } - - #addLiturgiesToContext(context) { - const actorData = context.data; - context.liturgies = []; - context.blessings = []; - - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Blessing") { - context.blessings.push({ - deity: item.system.gottheit, - value: item.system.wert - }) - } - }) - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Liturgy") { - - context.blessings.forEach(({deity, value}) => { - let insertObject = context.liturgies.find(p => p.deity === deity); - if (!insertObject) { - insertObject = { - deity: deity, - lkp: value, - O: [], - I: [], - II: [], - III: [], - IV: [], - V: [], - VI: [], - VII: [], - VIII: [], - "NA": [], - countO: 1, - countI: 1, - countII: 1, - countIII: 1, - countIV: 1, - countV: 1, - countVI: 1, - countVII: 1, - countVIII: 1, - countNA: 0, - total: 3, - - } - context.liturgies.push(insertObject); - } - - // sort by rank - const rankData = LiturgyData.getRankOfLiturgy(item.system, deity) - if (rankData) { - let {index, name, lkp, mod, costKaP} = rankData; - - insertObject["count" + name] = insertObject["count" + name] + 1; - - insertObject[name].push({ - id: item._id, - name: item.name, - lkpReq: lkp, - lkpMod: mod, - costKaP, - rank: index, // get effective liturgy rank based on deity - liturgiekenntnis: deity, - }) - insertObject.total = insertObject.total + 2; - - } - }) - } - }) - - - // clean up counter - Object.values(context.liturgies).forEach((litObject) => { - - if (litObject.I.length === 0) litObject.countI = false; - if (litObject.II.length === 0) litObject.countII = false; - if (litObject.III.length === 0) litObject.countIII = false; - if (litObject.IV.length === 0) litObject.countIV = false; - if (litObject.V.length === 0) litObject.countV = false; - if (litObject.VI.length === 0) litObject.countVI = false; - if (litObject.VII.length === 0) litObject.countVII = false; - if (litObject.VIII.length === 0) litObject.countVIII = false; - if (litObject.NA.length === 0) litObject.countNA = false; - - - }) - - context.hasLiturgies = context.blessings.length > 0; - } - - #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; - } - } - } - - async #handleDroppedActiveEffect(actor, activeEffect) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === activeEffect.name) { - // replace active effect if its unique - - return true; - } - } - } - - #handleDroppedAdvantage(actor, advantage) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === advantage.name) { // TODO: adjust for uniqueness - return false; - } - } - } - - activateListeners(html) { - super.activateListeners(html); - - const tabs = new foundry.applications.ux.Tabs({ - navSelector: ".paperdoll-tabs.tabs", - contentSelector: ".sheet-body.paperdoll-sets", - initial: "set" + (this.object.system.setEquipped + 1) - }); - tabs.bind(html[0]); - - html.on('click', '.attribute.rollable', (evt) => { - this._onAttributeRoll(evt); - }); - - html.on('click', '[data-operation="switchSet"]', (evt) => { - const {id} = evt.currentTarget.dataset; - console.log(id); - this.object.update({"system.setEquipped": id}) - }) - - html.on('click', '[data-operation="removeEffect"]', (evt) => { - const {actorId, effectId} = evt.currentTarget.dataset; - if (game.user.isGM) { - this.object.items.get(effectId).delete(); - } - }) - - html.on('click', '.talent.rollable', (evt) => { - this._onTalentRoll(evt); - }); - - html.on('click', '.sidebar-element.rollable', (evt) => { - this._onRoll(evt); - }); - - // TODO: merge into click.clickable handler - html.on('click', '.talent .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.advantage .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.equipment', (evt) => { - this.openEmbeddedDocument(evt.target.parentElement.dataset.id); - evt.stopPropagation(); - }) - - html.on('click', '.clickable', async (evt) => { - const {id, operation} = evt.currentTarget.dataset; - if (operation === "openActorSheet") { - this.openEmbeddedDocument(id); - evt.stopPropagation(); - } - }) - /* - html.on('dragstart', '.equipment', (evt) => { - evt.originalEvent.dataTransfer.setData("application/json", JSON.stringify({ - documentId: evt.currentTarget.dataset.id - })); - })*/ - /* - html.on('drop', '.equipped', async (evt) => { - const {actor, target, setId} = evt.currentTarget.dataset; - try { - const {documentId} = JSON.parse(evt.originalEvent.dataTransfer.getData("application/json")); - - - if (actor === this.object._id && documentId) { // managing equipped items - //const slot = this.#isWorn(documentId, setId) - //const updateObject = await this.#getEquipmentset(Number(setId)) - const updateObject = this.#mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = documentId; - console.log(updateObject); - - await this.object.update(updateObject); - } - - evt.stopPropagation(); - } catch (e) { - } - })*/ - - new foundry.applications.ux.ContextMenu(html[0], '.talent.rollable', [ - { - name: "Entfernen", - icon: '', - callback: (event) => { - this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); - - - new foundry.applications.ux.ContextMenu(html[0], '.attribute.rollable', [ - { - name: "Anpassen", - icon: '', - callback: (event) => { - this.showAdjustAttributeDialog(event[0].dataset.name, event[0].dataset.label, event[0].dataset.value) - }, - condition: () => true - } - ], { - jQuery: false - }); - - let handler = evt => { - const talentId = evt.target.dataset.id - evt.dataTransfer.setData("application/json", JSON.stringify({ - talentId - })); - this._onDragStart(evt) - - } - - // 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); - }); - - new foundry.applications.ux.ContextMenu(html[0], '.equipment', [ - { - name: "Aus dem Inventar entfernen", - icon: '', - callback: (event) => { - // TODO find id on heldenausruestung to remove the worn items as well - this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); - - new foundry.applications.ux.ContextMenu(html[0], '.equipped', [ - { - name: "Gegenstand vom Set entfernen", - callback: (event) => { - const {setId, target, actor} = event[0].dataset - - const updateObject = this.#mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = null; - - this.object.update(updateObject); - }, - condition: () => true - } - ], { - jQuery: false - }); - - html.on('click', '[data-operation="addWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '[data-operation="reduceWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '.liturgy.rollable', async (evt) => { - - evt.stopPropagation(); - - const {id, rank, lkp, deity} = evt.currentTarget.dataset; - const document = await this.object.items.get(id) - - const data = {}; - - data.rank = rank; - data.lkp = lkp; - data.deity = deity; - data.variations = []; - const ranks = LiturgyData.ranks - ranks.forEach(rank => { - if (document.system.auswirkung[rank]) { - data.variations.push({ - rank, - effect: document.system.auswirkung[rank] - }) - } - }) - data.mods = []; - - const htmlContent = await renderTemplate('systems/DSA_4-1/templates/dialog/modify-liturgy.hbs', data); - - const dialogData = { - title: document.name, - content: htmlContent, - data: {}, + new Dialog({ + title: `${attributeName} ändern auf`, + content: myContent, buttons: { - submit: { - label: "Wirken", - icon: '', + button1: { + label: "Ändern", callback: (html) => { + updateAttribute(html) + }, + icon: `` + } + } + }).render(true); + + }*/ + + /* + activateListeners(html) { + super.activateListeners(html); + + const tabs = new foundry.applications.ux.Tabs({ + navSelector: ".paperdoll-tabs.tabs", + contentSelector: ".sheet-body.paperdoll-sets", + initial: "set" + (this.object.system.setEquipped + 1) + }); + tabs.bind(html[0]); + + html.on('click', '.attribute.rollable', (evt) => { + this._onAttributeRoll(evt); + }); + + html.on('click', '[data-operation="switchSet"]', (evt) => { + const {id} = evt.currentTarget.dataset; + console.log(id); + this.object.update({"system.setEquipped": id}) + }) + + html.on('click', '[data-operation="removeEffect"]', (evt) => { + const {actorId, effectId} = evt.currentTarget.dataset; + if (game.user.isGM) { + this.object.items.get(effectId).delete(); + } + }) + + html.on('click', '.talent.rollable', (evt) => { + this._onTalentRoll(evt); + }); + + html.on('click', '.sidebar-element.rollable', (evt) => { + this._onRoll(evt); + }); + + // TODO: merge into click.clickable handler + html.on('click', '.talent .name', (evt) => { + this.openEmbeddedDocument(evt.target.dataset.id); + evt.stopPropagation(); + }) + + // TODO: merge into click.clickable handler + html.on('click', '.advantage .name', (evt) => { + this.openEmbeddedDocument(evt.target.dataset.id); + evt.stopPropagation(); + }) + + // TODO: merge into click.clickable handler + html.on('click', '.equipment', (evt) => { + this.openEmbeddedDocument(evt.target.parentElement.dataset.id); + evt.stopPropagation(); + }) + + html.on('click', '.clickable', async (evt) => { + const {id, operation} = evt.currentTarget.dataset; + if (operation === "openActorSheet") { + this.openEmbeddedDocument(id); + evt.stopPropagation(); + } + }) + + new foundry.applications.ux.ContextMenu(html[0], '.talent.rollable', [ + { + name: "Entfernen", + icon: '', + callback: (event) => { + this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) + }, + condition: () => true + } + ], { + jQuery: false + }); + + + new foundry.applications.ux.ContextMenu(html[0], '.attribute.rollable', [ + { + name: "Anpassen", + icon: '', + callback: (event) => { + this.showAdjustAttributeDialog(event[0].dataset.name, event[0].dataset.label, event[0].dataset.value) + }, + condition: () => true + } + ], { + jQuery: false + }); + + let handler = evt => { + const talentId = evt.target.dataset.id + evt.dataTransfer.setData("application/json", JSON.stringify({ + talentId + })); + this._onDragStart(evt) + } + + // 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); + }); + + html.on('click', '[data-operation="addWounds"]', async (evt) => { + const {value} = evt.currentTarget.dataset + this.object.update({"system.wunden.aktuell": value}) + }) + + html.on('click', '[data-operation="reduceWounds"]', async (evt) => { + const {value} = evt.currentTarget.dataset + this.object.update({"system.wunden.aktuell": value}) + }) + + html.on('click', '.liturgy.rollable', async (evt) => { + + evt.stopPropagation(); + + const {id, rank, lkp, deity} = evt.currentTarget.dataset; + const document = await this.object.items.get(id) + + const data = {}; + + data.rank = rank; + data.lkp = lkp; + data.deity = deity; + data.variations = []; + const ranks = LiturgyData.ranks + ranks.forEach(rank => { + if (document.system.auswirkung[rank]) { + data.variations.push({ + rank, + effect: document.system.auswirkung[rank] + }) + } + }) + data.mods = []; + + const htmlContent = await renderTemplate('systems/DSA_4-1/templates/dialog/modify-liturgy.hbs', data); + + const dialogData = { + title: document.name, + content: htmlContent, + data: {}, + buttons: { + submit: { + label: "Wirken", + icon: '', + callback: (html) => { + }, }, }, - }, - } - dialogData.render = new ModifyLiturgy(data).handleRender + } + dialogData.render = new ModifyLiturgy(data).handleRender - const dialog = new Dialog(dialogData, { - classes: ['dsa41', 'dialog', 'liturgy'], - height: 480 + const dialog = new Dialog(dialogData, { + classes: ['dsa41', 'dialog', 'liturgy'], + height: 480 + }) + + dialog.render(true); + + return false; }) - dialog.render(true); - return false; - }) - - - } - - #handleDroppedEquipment(actor, equipment) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === equipment.name) { // TODO: adjust item quantity if item is the same - return false; - } } - } - - #handleDroppedLiturgy(actor, liturgy) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === liturgy.name) { // TODO: allow multiple miracles with the same name - return false; - } - } - } - - #handleDroppedSpecialAbility(actor, specialAbility) { - const array = Array.from(actor.items); - for (let i = 0; i < array.length; i++) { - if (array[i].name === specialAbility.name) { // TODO: allow multiple miracles with the same name - return false; - } - } - } - + */ } + +export default CharacterSheet diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 58ba836a..b3ed1427 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -75,21 +75,6 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { await this.document.update(formData.object) // Note: formData.object } - #createDragDropHandlers() { - return this.options.dragDrop.map((d) => { - d.permissions = { - dragstart: this._canDragStart.bind(this), - drop: this._canDragDrop.bind(this) - } - d.callbacks = { - dragstart: this._onDragStart.bind(this), - dragover: this._onDragOver.bind(this), - drop: this._onDrop.bind(this) - } - return new DragDrop(d) - }) - } - #stringToKeyFieldName(s) { return s } diff --git a/src/templates/actor/actor-character-sheet.hbs b/src/templates/actor/actor-character-sheet.hbs deleted file mode 100644 index f499c11b..00000000 --- a/src/templates/actor/actor-character-sheet.hbs +++ /dev/null @@ -1,814 +0,0 @@ -
- - {{!-- Sheet Header --}} -
- {{!-- Header stuff goes here --}} -
-
- {{#each attributes}} - {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} - {{/each}} -
-
-
- -
-

- - - - - - {{#if ausdauer}} - - {{/if}} - - {{#if this.hasLiturgies}} - - {{/if}} - - {{#if this.hasSpells}} - - {{/if}} - - {{#each attacks}} -
-

{{this.using}} ({{this.name}})

-
- {{#if this.at}} - - {{/if}} - {{#if this.pa}} - - {{/if}} -
- {{#if this.at}} - - {{/if}} - {{#if this.ini}} - - {{/if}} -
- {{/each}} - - - -
- - {{!-- Sheet Tab Navigation --}} - - - {{!-- Sheet Body --}} -
-
- - - - -
-
-
-
- - -
- {{#each this.mods.mu}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.kl}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.in}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ch}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ff}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ge}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ko}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.kk}} - {{this.value}} - {{/each}} -
- -
-
- - -
-
- - -
- {{#each this.mods.at}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.pa}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.fk}} - {{this.value}} - {{/each}} -
-
-
-
-
- - - -
- {{#if ausdauer}} -
- - - -
- {{/if}} - {{#if hasSpells}} -
- - - -
- {{/if}} - {{#if hasLiturgies}} -
- - - -
- {{/if}} -
-
-

Vor- und Nachteile

-
    - {{#each this.advantages}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • - {{/each}} -
-
-
-

Sonderfertigkeiten

-
    - {{#each this.specialAbilities}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • - {{/each}} -
-
-
- -
- -
- -
- - - w6 - -
-
- - - von - -
- {{#if ausdauer}} -
- - - von - -
- {{/if}} - {{#if (not zonenruestung)}} -
- - {{derived.rs}} -
- {{/if}} -
- - {{derived.be}} -
- - -
- {{#if (not trefferzonen)}} -
- - {{#each this.woundsFilled}} - {{#if this}} -
{{@index}}
- {{else}} -
{{@index}}
- {{/if}} - {{/each}} -
- {{/if}} - - -
-

Aktionen im Kampf

- {{#each this.actions}} - {{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}} - {{/each}} -
- - {{#if (or trefferzonen zonenruestung)}} -
-

{{#if (and trefferzonen zonenruestung)}}Trefferzonen{{/if}}{{#if - (and trefferzonen (not zonenruestung))}}Wunden{{/if}}{{#if - (and (not trefferzonen) zonenruestung)}}Rüstung{{/if}}

-
- - - - {{#if trefferzonen}} - {{derived.wunden.kopf}} - {{derived.wunden.brust}} - {{derived.wunden.armlinks}} - {{derived.wunden.armrechts}} - {{derived.wunden.bauch}} - {{derived.wunden.beinlinks}} - {{derived.wunden.beinrechts}} - {{/if}} - {{#if zonenruestung}} - {{derived.rs.kopf}} - {{derived.rs.brust}} - {{derived.rs.armlinks}} - {{derived.rs.armrechts}} - {{derived.rs.bauch}} - {{derived.rs.beinlinks}} - {{derived.rs.beinrechts}} - {{/if}} -
-
- {{/if}} - -
-
-
-

Kampftalente

-
    - {{#each skills.Kampf}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Körperliche Talente

-
    -
  • - {{#each skills.Körperlich}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Gesellschaftliche Talente

-
    -
  • - {{#each skills.Gesellschaft}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Natur Talente

-
    -
  • - {{#each skills.Natur}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Wissenstalente

-
    -
  • - {{#each skills.Wissen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Schriften & Sprachen

-
    -
  • - {{#each skills.Schriften}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} - {{#each skills.Sprachen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Handwerkliche Talente

-
    -
  • - {{#each skills.Handwerk}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
- -
-
- -
- -
- -
-
- - -
-

Inventar

- - {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}} - -
- -
-

Ausrüstung

- {{!-- Set Tab Navigation --}} - - {{!-- Set Body --}} -
- {{#each this.sets}} -
- -
- - - - - {{#each this.slots}} -
- {{/each}} - {{#if (eq ../actor.system.setEquipped @index)}} - - {{else}} - - {{/if}} - -
-
- {{/each}} - -
-
- -
- {{#if this.hasSpells}} -
- -
- -
- - - von - -
-
- - -
-
- - - - - - - - - - - - - {{#each this.spells}} - - - - - - - - - - {{/each}} - -
ZaubernameProbeZfWMerkmale
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}{{this.eigenschaft1}}{{this.eigenschaft2}}{{this.eigenschaft3}}{{this.zfw}} -
    {{#each this.merkmal}} -
  • {{this}}
  • {{/each}}
-
- -
- {{/if}} - {{#if this.hasLiturgies}} -
- -
- -
- - - von - -
-
- - {{#each this.liturgies}} - - - - - - - - - - {{#if this.countO}} - - - - - {{#each this.O}} - - - - - - {{/each}} - {{/if}} - {{#if this.countI}} - - - - {{#each this.I}} - - - - - - {{/each}} - {{/if}} - {{#if this.countII}} - - - - {{#each this.II}} - - - - - {{/each}} - {{/if}} - {{#if this.countIII}} - - - - {{#each this.III}} - - - - - {{/each}} - {{/if}} - {{#if this.countIV}} - - - - {{#each this.IV}} - - - - - {{/each}}{{/if}} - {{#if this.countV}} - - - - {{#each this.V}} - - - - - {{/each}} - {{/if}} - {{#if this.countVI}} - - - - {{#each this.VI}} - - - - - {{/each}} - {{/if}}{{#if this.countVII}} - - - - {{#each this.VII}} - - - - - {{/each}} - {{/if}}{{#if this.countVIII}} - - - - {{#each this.VIII}} - - - - - {{/each}} - {{/if}} - -
Liturgiekenntnis: {{this.lkp}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{this.name}}
- {{/each}} - -
- {{/if}} - -
- - - - - - - - {{#each this.effects}} - - - - - - {{/each}} - -
EffektVeränderungen
- {{this.name}} - {{this.conditions}}{{#if ../isGM}} - {{/if}}
-
- -
-
diff --git a/src/templates/actor/character/main-sheet.hbs b/src/templates/actor/character/main-sheet.hbs new file mode 100644 index 00000000..d034f3a8 --- /dev/null +++ b/src/templates/actor/character/main-sheet.hbs @@ -0,0 +1,91 @@ +
+ + {{!-- Sheet Header --}} +
+ {{!-- Header stuff goes here --}} +
+
+ {{#each attributes}} + {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} + {{/each}} +
+
+
+ +
+

+ + + + + + {{#if ausdauer}} + + {{/if}} + + {{#if this.hasLiturgies}} + + {{/if}} + + {{#if this.hasSpells}} + + {{/if}} + + {{#each attacks}} +
+

{{this.using}} ({{this.name}})

+
+ {{#if this.at}} + + {{/if}} + {{#if this.pa}} + + {{/if}} +
+ {{#if this.at}} + + {{/if}} + {{#if this.ini}} + + {{/if}} +
+ {{/each}} + + + +
+ + {{!-- Sheet Tab Navigation --}} + + +
diff --git a/src/templates/actor/character/tab-attributes.hbs b/src/templates/actor/character/tab-attributes.hbs new file mode 100644 index 00000000..842f2973 --- /dev/null +++ b/src/templates/actor/character/tab-attributes.hbs @@ -0,0 +1,161 @@ +
+ +
+
+ + +
+ {{#each this.mods.mu}} + {{this.value}} + {{/each}} +
+
+
+ + +
+ {{#each this.mods.kl}} + {{this.value}} + {{/each}} +
+
+
+ + +
+ {{#each this.mods.in}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+ {{#each this.mods.ch}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+ {{#each this.mods.ff}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+ {{#each this.mods.ge}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+ {{#each this.mods.ko}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+ {{#each this.mods.kk}} + {{this.value}} + {{/each}} +
+ +
+
+ + +
+
+ + +
+ {{#each this.mods.at}} + {{this.value}} + {{/each}} +
+
+
+ + +
+ {{#each this.mods.pa}} + {{this.value}} + {{/each}} +
+
+
+ + +
+ {{#each this.mods.fk}} + {{this.value}} + {{/each}} +
+
+
+
+
+ + + +
+ {{#if ausdauer}} +
+ + + +
+ {{/if}} + {{#if hasSpells}} +
+ + + +
+ {{/if}} + {{#if hasLiturgies}} +
+ + + +
+ {{/if}} +
+
+

Vor- und Nachteile

+
    + {{#each this.advantages}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • + {{/each}} +
+
+
+

Sonderfertigkeiten

+
    + {{#each this.specialAbilities}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • + {{/each}} +
+
+ +
diff --git a/src/templates/actor/character/tab-combat.hbs b/src/templates/actor/character/tab-combat.hbs new file mode 100644 index 00000000..9992c484 --- /dev/null +++ b/src/templates/actor/character/tab-combat.hbs @@ -0,0 +1,100 @@ +
+ +
+ +
+ + + w6 + +
+
+ + + von + +
+ {{#if ausdauer}} +
+ + + von + +
+ {{/if}} + {{#if (not zonenruestung)}} +
+ + {{derived.rs}} +
+ {{/if}} +
+ + {{derived.be}} +
+ + +
+ {{#if (not trefferzonen)}} +
+ + {{#each this.woundsFilled}} + {{#if this}} +
{{@index}}
+ {{else}} +
{{@index}}
+ {{/if}} + {{/each}} +
+ {{/if}} + + +
+

Aktionen im Kampf

+ {{#each this.actions}} + {{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}} + {{/each}} +
+ + {{#if (or trefferzonen zonenruestung)}} +
+

{{#if (and trefferzonen zonenruestung)}}Trefferzonen{{/if}}{{#if + (and trefferzonen (not zonenruestung))}}Wunden{{/if}}{{#if + (and (not trefferzonen) zonenruestung)}}Rüstung{{/if}}

+
+ + + + {{#if trefferzonen}} + {{derived.wunden.kopf}} + {{derived.wunden.brust}} + {{derived.wunden.armlinks}} + {{derived.wunden.armrechts}} + {{derived.wunden.bauch}} + {{derived.wunden.beinlinks}} + {{derived.wunden.beinrechts}} + {{/if}} + {{#if zonenruestung}} + {{derived.rs.kopf}} + {{derived.rs.brust}} + {{derived.rs.armlinks}} + {{derived.rs.armrechts}} + {{derived.rs.bauch}} + {{derived.rs.beinlinks}} + {{derived.rs.beinrechts}} + {{/if}} +
+
+ {{/if}} + +
+ + diff --git a/src/templates/actor/character/tab-effects.hbs b/src/templates/actor/character/tab-effects.hbs new file mode 100644 index 00000000..ca174837 --- /dev/null +++ b/src/templates/actor/character/tab-effects.hbs @@ -0,0 +1,27 @@ +
+ + + + + + + + + + + {{#each this.effects}} + + + + + + {{/each}} + +
EffektVeränderungen
+ {{this.name}} + {{this.conditions}}{{#if ../isGM}} + {{/if}}
+
\ No newline at end of file diff --git a/src/templates/actor/character/tab-equipment.hbs b/src/templates/actor/character/tab-equipment.hbs new file mode 100644 index 00000000..526254f3 --- /dev/null +++ b/src/templates/actor/character/tab-equipment.hbs @@ -0,0 +1,85 @@ +
+
+

Kampftalente

+
    + {{#each skills.Kampf}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Körperliche Talente

+
    +
  • + {{#each skills.Körperlich}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Gesellschaftliche Talente

+
    +
  • + {{#each skills.Gesellschaft}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Natur Talente

+
    +
  • + {{#each skills.Natur}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Wissenstalente

+
    +
  • + {{#each skills.Wissen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Schriften & Sprachen

+
    +
  • + {{#each skills.Schriften}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} + {{#each skills.Sprachen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Handwerkliche Talente

+
    +
  • + {{#each skills.Handwerk}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
\ No newline at end of file diff --git a/src/templates/actor/character/tab-liturgies.hbs b/src/templates/actor/character/tab-liturgies.hbs new file mode 100644 index 00000000..886f41bd --- /dev/null +++ b/src/templates/actor/character/tab-liturgies.hbs @@ -0,0 +1,202 @@ +
+ +
+ +
+ + + von + +
+
+ + {{#each this.liturgies}} + + + + + + + + + + {{#if this.countO}} + + + + + {{#each this.O}} + + + + + + {{/each}} + {{/if}} + {{#if this.countI}} + + + + {{#each this.I}} + + + + + + {{/each}} + {{/if}} + {{#if this.countII}} + + + + {{#each this.II}} + + + + + {{/each}} + {{/if}} + {{#if this.countIII}} + + + + {{#each this.III}} + + + + + {{/each}} + {{/if}} + {{#if this.countIV}} + + + + {{#each this.IV}} + + + + + {{/each}}{{/if}} + {{#if this.countV}} + + + + {{#each this.V}} + + + + + {{/each}} + {{/if}} + {{#if this.countVI}} + + + + {{#each this.VI}} + + + + + {{/each}} + {{/if}}{{#if this.countVII}} + + + + {{#each this.VII}} + + + + + {{/each}} + {{/if}}{{#if this.countVIII}} + + + + {{#each this.VIII}} + + + + + {{/each}} + {{/if}} + +
Liturgiekenntnis: {{this.lkp}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + {{this.name}}
+ {{/each}} + + +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-meta.hbs b/src/templates/actor/character/tab-meta.hbs new file mode 100644 index 00000000..324470dc --- /dev/null +++ b/src/templates/actor/character/tab-meta.hbs @@ -0,0 +1,49 @@ +
+ + + +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-skills.hbs b/src/templates/actor/character/tab-skills.hbs new file mode 100644 index 00000000..526254f3 --- /dev/null +++ b/src/templates/actor/character/tab-skills.hbs @@ -0,0 +1,85 @@ +
+
+

Kampftalente

+
    + {{#each skills.Kampf}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Körperliche Talente

+
    +
  • + {{#each skills.Körperlich}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Gesellschaftliche Talente

+
    +
  • + {{#each skills.Gesellschaft}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Natur Talente

+
    +
  • + {{#each skills.Natur}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Wissenstalente

+
    +
  • + {{#each skills.Wissen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Schriften & Sprachen

+
    +
  • + {{#each skills.Schriften}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} + {{#each skills.Sprachen}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} +
  • + {{/each}} +
+
+
+

Handwerkliche Talente

+
    +
  • + {{#each skills.Handwerk}} +
  • + {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} +
  • + {{/each}} +
+
+
\ No newline at end of file diff --git a/src/templates/actor/character/tab-spells.hbs b/src/templates/actor/character/tab-spells.hbs new file mode 100644 index 00000000..ed6cda06 --- /dev/null +++ b/src/templates/actor/character/tab-spells.hbs @@ -0,0 +1,49 @@ +
+ +
+ +
+ + + von + +
+
+ + +
+
+ + + + + + + + + + + + + {{#each this.spells}} + + + + + + + + + + {{/each}} + +
ZaubernameProbeZfWMerkmale
+ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} + + {{this.name}}{{this.eigenschaft1}}{{this.eigenschaft2}}{{this.eigenschaft3}}{{this.zfw}} +
    {{#each this.merkmal}} +
  • {{this}}
  • {{/each}}
+
+
\ No newline at end of file -- 2.43.0 From 96d7b1874242aae37cd00d5c9c0dc9e569d211a1 Mon Sep 17 00:00:00 2001 From: macniel Date: Thu, 16 Oct 2025 21:46:35 +0200 Subject: [PATCH 17/40] requires retargeting of styling --- src/module/sheets/character/attributes.mjs | 13 ++-- src/module/sheets/character/combat.mjs | 2 + src/module/sheets/character/effects.mjs | 2 + src/module/sheets/character/equipment.mjs | 2 + src/module/sheets/character/liturgies.mjs | 2 + src/module/sheets/character/meta.mjs | 2 + src/module/sheets/character/skills.mjs | 4 +- src/module/sheets/character/spells.mjs | 4 +- src/module/sheets/characterSheet.mjs | 78 ++++++++++--------- src/style/organisms/_character-sheet.scss | 5 +- src/templates/actor/character/tab-combat.hbs | 2 - src/templates/actor/character/tab-effects.hbs | 1 + 12 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/module/sheets/character/attributes.mjs b/src/module/sheets/character/attributes.mjs index 230caa62..b01333eb 100644 --- a/src/module/sheets/character/attributes.mjs +++ b/src/module/sheets/character/attributes.mjs @@ -21,7 +21,7 @@ export default { icon: e.icon, }) })) - return returnValue; + return returnValue } context.mods = { @@ -36,8 +36,8 @@ export default { "at": await getModsOfAttribute('system.at.mod', actorData), "pa": await getModsOfAttribute('system.pa.mod', actorData), "fk": await getModsOfAttribute('system.fk.mod', actorData), - } + context.attributes = [ { eigenschaft: "mu", @@ -87,7 +87,6 @@ export default { tooltip: "Körperkraft", wert: context.derived.attribute.kk.aktuell ?? 0, }, - ] Object.values(actorData.items).forEach((item) => { @@ -101,12 +100,12 @@ export default { isAdvantage: !item.system.nachteil, isDisadvantage: item.system.nachteil, isBadAttribute: item.system.schlechteEigenschaft - }); + }) } } - ); + ) - context.specialAbilities = []; + context.specialAbilities = [] Object.values(actorData.items).forEach((item) => { if (item.type === "SpecialAbility") { context.specialAbilities.push({ @@ -116,6 +115,8 @@ export default { } } ); + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/combat.mjs b/src/module/sheets/character/combat.mjs index ab4d9b48..883cc92a 100644 --- a/src/module/sheets/character/combat.mjs +++ b/src/module/sheets/character/combat.mjs @@ -101,6 +101,8 @@ export default { }) } + return context + }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/effects.mjs b/src/module/sheets/character/effects.mjs index 6c817e7d..e59e080d 100644 --- a/src/module/sheets/character/effects.mjs +++ b/src/module/sheets/character/effects.mjs @@ -42,6 +42,8 @@ export default { }); } }) + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 680a0538..4739a516 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -140,6 +140,8 @@ export default { ] }) } + + return context }, _onRender: (context, options, element) => { const mapAllSets = () => { diff --git a/src/module/sheets/character/liturgies.mjs b/src/module/sheets/character/liturgies.mjs index 196ac767..1b8c5af2 100644 --- a/src/module/sheets/character/liturgies.mjs +++ b/src/module/sheets/character/liturgies.mjs @@ -98,6 +98,8 @@ export default { }) context.hasLiturgies = context.blessings.length > 0; + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/meta.mjs b/src/module/sheets/character/meta.mjs index 75ed6f50..de5d56fe 100644 --- a/src/module/sheets/character/meta.mjs +++ b/src/module/sheets/character/meta.mjs @@ -7,6 +7,8 @@ export default { context.originalName = actorData.name context.name = context.derived.name ?? actorData.name context.effects = actorData.effects ?? [] + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs index 78e6b307..b8c271c0 100644 --- a/src/module/sheets/character/skills.mjs +++ b/src/module/sheets/character/skills.mjs @@ -69,7 +69,9 @@ export default { context.flatSkills.push(obj); } } - ); + ) + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/character/spells.mjs b/src/module/sheets/character/spells.mjs index 9c33ad0d..8bc0a3af 100644 --- a/src/module/sheets/character/spells.mjs +++ b/src/module/sheets/character/spells.mjs @@ -38,7 +38,9 @@ export default { }) } }) - context.hasSpells = context.spells.length > 0; + context.hasSpells = context.spells.length > 0 + + return context }, _onRender: (context, options) => { diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 69716a1b..464663ab 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -38,6 +38,13 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { sheet: { tabs: [ {id: 'meta', group: 'sheet', label: 'Meta'}, + {id: 'attributes', group: 'sheet', label: 'Eigenschaften'}, + {id: 'combat', group: 'sheet', label: 'Kampf'}, + {id: 'equipment', group: 'sheet', label: 'Inventar'}, + {id: 'skills', group: 'sheet', label: 'Talente'}, + {id: 'spells', group: 'sheet', label: 'Zauber'}, + {id: 'liturgies', group: 'sheet', label: 'Liturgien'}, + ], initial: 'meta' } @@ -103,20 +110,41 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { await this.document.update(formData.object) // Note: formData.object } - _getTabsConfig(group) { - const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) - Attributes._getTabConfig(tabs) - Combat._getTabConfig(tabs) - Equipment._getTabConfig(tabs) - Skills._getTabConfig(tabs) - Spells._getTabConfig(tabs) - Liturgies._getTabConfig(tabs) - Effects._getTabConfig(tabs) - return tabs - } - + /* + _getTabsConfig(group) { + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + Attributes._getTabConfig(tabs) + Combat._getTabConfig(tabs) + Equipment._getTabConfig(tabs) + Skills._getTabConfig(tabs) + Spells._getTabConfig(tabs) + Liturgies._getTabConfig(tabs) + Effects._getTabConfig(tabs) + return tabs + } + */ async _preparePartContext(partId, context) { switch (partId) { + case "form": + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + context.maxWounds = actorData.system.wunden.max ?? 3 + context.wounds = actorData.system.wunden.aktuell ?? 0 + context.woundsFilled = [] + for (let i = 1; i <= context.maxWounds; i++) { + context.woundsFilled[i] = i <= context.wounds + } + + context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen") + context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") + context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") + break; case "meta": Meta._prepareContext(context, this.object) break @@ -142,31 +170,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { Effects._prepareContext(context, this.object) break } - } - - /** @override */ - async _prepareContext(options) { - const context = await super._prepareContext(options) - const actorData = context.document - context.system = actorData.system - context.flags = actorData.flags - context.derived = context.document.system - context.originalName = actorData.name - context.name = context.derived.name ?? actorData.name - context.effects = actorData.effects ?? [] - - context.maxWounds = actorData.system.wunden.max ?? 3 - context.wounds = actorData.system.wunden.aktuell ?? 0 - context.woundsFilled = [] - for (let i = 1; i <= context.maxWounds; i++) { - context.woundsFilled[i] = i <= context.wounds - } - - context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen") - context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") - context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") - - return context; + return context } _onRender(context, options) { diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index 6750bdde..14ae4631 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -3,10 +3,7 @@ @use "../atoms/colours" as colour; -.dsa41.sheet.actor.character { - - .window-header.flexrow.draggable.resizable { - } +.application.sheet.dsa41.actor.character { $sidebar-width: 224px; $attribute-height: 60px; diff --git a/src/templates/actor/character/tab-combat.hbs b/src/templates/actor/character/tab-combat.hbs index 9992c484..ab59267e 100644 --- a/src/templates/actor/character/tab-combat.hbs +++ b/src/templates/actor/character/tab-combat.hbs @@ -95,6 +95,4 @@ {{/if}} - - diff --git a/src/templates/actor/character/tab-effects.hbs b/src/templates/actor/character/tab-effects.hbs index ca174837..b131f219 100644 --- a/src/templates/actor/character/tab-effects.hbs +++ b/src/templates/actor/character/tab-effects.hbs @@ -24,4 +24,5 @@ {{/each}} + \ No newline at end of file -- 2.43.0 From 74e91d206f23cf6623a2b8696ecc541bc61e9c4f Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 00:10:24 +0200 Subject: [PATCH 18/40] adds optional styling according to Paramanthus --- src/main.mjs | 13 ++ src/module/sheets/characterSheet.mjs | 53 +++++++ src/style/atoms/_colours.scss | 23 +++ src/style/molecules/_attributes.scss | 138 +++++++++++++----- src/style/organisms/_character-sheet.scss | 4 +- src/templates/actor/character/main-sheet.hbs | 2 +- src/templates/ui/partial-attribute-button.hbs | 3 +- src/templates/ui/partial-die.hbs | 47 +----- 8 files changed, 203 insertions(+), 80 deletions(-) diff --git a/src/main.mjs b/src/main.mjs index 89239448..ddfa2dd7 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -133,6 +133,19 @@ Hooks.once("init", () => { label: 'DSA41.ActiveEffectLabels.ActiveEffect' }) + game.settings.register('DSA_4-1', 'optional_colorfuldice', { + name: "Optional: Farbige Würfel nach Paramanthus", + hint: "Färbt die Würfel je nach Attribut ein", + scope: "client", + config: true, + type: Boolean, + default: false, + onChange: value => { + }, + requiresReload: false + }) + + game.settings.register('DSA_4-1', 'optional_trefferzonen', { name: "Optional: Trefferzonen", hint: "Ersetzt das Wundensystem aus dem BRW durch das Trefferzonensystem aus WdH", diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 464663ab..c322ade3 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -144,6 +144,59 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.zonenruestung = game.settings.get("DSA_4-1", "optional_ruestungzonen") context.trefferzonen = game.settings.get("DSA_4-1", "optional_trefferzonen") context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") + context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice') + + context.attributes = [ + { + eigenschaft: "mu", + name: "MU", + tooltip: "Mut", + wert: context.derived.attribute.mu.aktuell ?? 0, + }, + { + eigenschaft: "kl", + name: "KL", + tooltip: "Klugheit", + wert: context.derived.attribute.kl.aktuell ?? 0, + }, + { + eigenschaft: "in", + name: "IN", + tooltip: "Intuition", + wert: context.derived.attribute.in.aktuell ?? 0, + }, + { + eigenschaft: "ch", + name: "CH", + tooltip: "Charisma", + wert: context.derived.attribute.ch.aktuell ?? 0, + }, + { + eigenschaft: "ff", + name: "FF", + tooltip: "Fingerfertigkeit", + wert: context.derived.attribute.ff.aktuell ?? 0, + }, + { + eigenschaft: "ge", + name: "GE", + tooltip: "Geschicklichkeit", + wert: context.derived.attribute.ge.aktuell ?? 0, + }, + { + eigenschaft: "ko", + name: "KO", + tooltip: "Konstitution", + wert: context.derived.attribute.ko.aktuell ?? 0, + }, + { + eigenschaft: "kk", + name: "KK", + tooltip: "Körperkraft", + wert: context.derived.attribute.kk.aktuell ?? 0, + }, + ] + break; case "meta": Meta._prepareContext(context, this.object) diff --git a/src/style/atoms/_colours.scss b/src/style/atoms/_colours.scss index 4fc2e42f..a352d9b1 100644 --- a/src/style/atoms/_colours.scss +++ b/src/style/atoms/_colours.scss @@ -35,8 +35,31 @@ $dice-box-shadow: rgba(0, 0, 0, 0.25); $pill-box-shadow: rgba(0, 0, 0, 0.3); $attribute-die-border-color: #000; + $attribute-die-color: #F00; $attribute-die-label-color: #FFF; + +$attribute-die-co-color: #b3241a; +$attribute-die-sm-color: #8259a3; +$attribute-die-in-color: #388834; +$attribute-die-ch-color: #0d0d0d; + +$attribute-die-dx-color: #688ec4; +$attribute-die-ag-color: #d5b467; +$attribute-die-bd-color: #a3a3a3; +$attribute-die-st-color: #d6a878; + +$attribute-die-co-text-color: #fff; +$attribute-die-sm-text-color: #fff; +$attribute-die-in-text-color: #fff; +$attribute-die-ch-text-color: #fff; + +$attribute-die-dx-text-color: #000; +$attribute-die-ag-text-color: #000; +$attribute-die-bd-text-color: #000; +$attribute-die-st-text-color: #000; + + $attribute-label-color: #FFF; $attribute-label-background-color: #0008; diff --git a/src/style/molecules/_attributes.scss b/src/style/molecules/_attributes.scss index 12830c1f..5bcbd8ed 100644 --- a/src/style/molecules/_attributes.scss +++ b/src/style/molecules/_attributes.scss @@ -29,49 +29,24 @@ svg { position: absolute; - left: 4px; - top: 4px; - bottom: 4px; - right: 4px; - } + left: -6px; + top: -6px; + bottom: -6px; + right: -6px; - .border { - fill: rgba(0, 0, 0, 0); - stroke: colours.$attribute-die-border-color; - } - - .center { - fill: colours.$attribute-die-color; - stroke: colours.$attribute-die-border-color; - } - - .topleft { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$lighter_factor); - stroke: colours.$attribute-die-border-color; - } - - .bottomleft { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$lightest_factor); - stroke: colours.$attribute-die-border-color; - } - - .topright { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$darken_factor); - stroke: colours.$attribute-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust(colours.$attribute-die-color, $lightness: numbers.$darkest_factor); - stroke: colours.$attribute-die-border-color; + path { + fill: colours.$attribute-die-color; + } } } .wert { font-weight: bold; position: absolute; - left: 0; + left: -2px; width: 48px; - top: 0; + top: -2px; + font-size: smaller; line-height: 48px; vertical-align: middle; text-align: center; @@ -90,6 +65,99 @@ background-color: colours.$attribute-label-background-color; } } + + &.colorfulDice { + + &.Mut { + + .die svg path { + fill: colours.$attribute-die-co-color; + } + + .wert { + color: colours.$attribute-die-co-text-color; + } + } + + .Klugheit { + + .die svg path { + fill: colours.$attribute-die-sm-color; + } + + .wert { + color: colours.$attribute-die-sm-text-color; + } + } + + .Intuition { + + .die svg path { + fill: colours.$attribute-die-in-color; + } + + .wert { + color: colours.$attribute-die-in-text-color; + } + } + + .Charisma { + + .die svg path { + fill: colours.$attribute-die-ch-color; + } + + .wert { + color: colours.$attribute-die-ch-text-color; + } + } + + .Geschicklichkeit { + + .die svg path { + fill: colours.$attribute-die-dx-color; + } + + .wert { + color: colours.$attribute-die-dx-text-color; + } + } + + .Fingerfertigkeit { + + .die svg path { + fill: colours.$attribute-die-ag-color; + } + + .wert { + color: colours.$attribute-die-ag-text-color; + } + } + + .Konstitution { + + .die svg path { + fill: colours.$attribute-die-bd-color; + } + + .wert { + color: colours.$attribute-die-bd-text-color; + } + } + + .Körperkraft { + + .die svg path { + fill: colours.$attribute-die-st-color; + } + + .wert { + color: colours.$attribute-die-st-text-color; + } + } + + } + } } } diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index 14ae4631..60f938fb 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -14,7 +14,7 @@ display: unset; /* we are on our own */ position: relative; - header.sheet-header { + .header-fields { position: absolute; top: 0; left: 0; @@ -44,7 +44,7 @@ height: $tabs-height; } - section.sheet-body { + section.tab { position: absolute; top: $attribute-height+$tabs-height+$tabs-spacing+4px; left: $sidebar-width; diff --git a/src/templates/actor/character/main-sheet.hbs b/src/templates/actor/character/main-sheet.hbs index d034f3a8..089a3ae1 100644 --- a/src/templates/actor/character/main-sheet.hbs +++ b/src/templates/actor/character/main-sheet.hbs @@ -4,7 +4,7 @@
{{!-- Header stuff goes here --}}
-
+
{{#each attributes}} {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} {{/each}} diff --git a/src/templates/ui/partial-attribute-button.hbs b/src/templates/ui/partial-attribute-button.hbs index ae542d07..2fce6caa 100644 --- a/src/templates/ui/partial-attribute-button.hbs +++ b/src/templates/ui/partial-attribute-button.hbs @@ -1,4 +1,5 @@ -
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} diff --git a/src/templates/ui/partial-die.hbs b/src/templates/ui/partial-die.hbs index dfb408fc..8b86f709 100644 --- a/src/templates/ui/partial-die.hbs +++ b/src/templates/ui/partial-die.hbs @@ -1,43 +1,8 @@ - - + + + - - - - - - + fill="#000000" + d="m 379.93,375.668 c -0.57,0.019 -1.226,0.228 -1.585,0.731 l -80.673,96.527 c -1.342,1.681 -1.433,2.056 0.366,2.073 l 161.59,-0.427 c 2.221,-0.182 2.23,-0.07 0.792,-1.951 l -79.27,-96.527 c -0.164,-0.254 -0.649,-0.44 -1.22,-0.426 z m 15.489,8.598 72.746,88.478 c 0.974,1.182 1.212,1.249 2.927,0.427 l 38.354,-17.562 c 2.513,-1.134 2.165,-1.366 0.487,-2.5 z m -33.965,3.232 c -0.034,-0.072 -0.625,0.37 -1.952,1.281 l -105.612,69.513 33.05,15.001 c 1.724,0.568 2.239,0.599 3.354,-0.793 l 69.698,-83.234 c 0.981,-1.137 1.495,-1.696 1.462,-1.768 z m 153.602,72.258 c -0.328,0.023 -0.846,0.212 -1.646,0.548 l -39.392,17.989 c -1.398,0.635 -1.311,1.49 -0.792,2.561 l 45.793,116.162 -3.292,-135.309 c -0.101,-1.479 -0.123,-1.99 -0.671,-1.951 z m -264.154,3.598 -4.208,131.651 38.782,-113.907 c 0.573,-1.682 0.559,-1.767 -0.61,-2.317 z m 210.859,17.073 -165.249,0.427 c -2.361,-0.035 -2.264,-0.033 -1.098,1.89 l 83.905,141.529 c 1.417,2.159 1.265,2.092 2.744,-0.121 L 462.675,482.38 c 0.708,-1.127 1.212,-1.914 -0.914,-1.953 z m 6.586,3.72 c -0.152,0.064 -0.318,0.639 -0.793,1.524 l -81.16,142.809 c -0.887,1.508 -1.097,2.048 1.036,1.708 l 128.845,-17.744 c 2.044,-0.467 1.982,-1.197 1.281,-3.232 l -48.6,-123.479 c -0.321,-1.183 -0.456,-1.65 -0.609,-1.586 z m -178.176,1.342 c -0.158,0.113 -0.3,0.715 -0.609,1.585 l -41.16,121.162 c -0.701,2.573 -0.78,3.541 1.829,4.024 l 123.113,17.805 c 2.328,0.351 2.03,-0.822 1.463,-1.951 L 291.024,486.769 c -0.526,-1.067 -0.695,-1.394 -0.853,-1.28 z m -32.013,133.845 120.796,68.538 c 1.564,0.949 1.929,0.604 1.707,-1.036 l -2.561,-48.05 c -0.07,-1.551 -0.28,-2.183 -1.89,-2.439 z m 249.764,0.121 -122.625,16.952 c -1.618,0.238 -1.326,1.032 -1.342,2.195 l 2.622,48.903 c 0.135,1.483 0.091,2.017 1.89,1.098 z"/> - + \ No newline at end of file -- 2.43.0 From 34a5028e30643cb6e3f8a4ee7069e4db17ea509a Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 18:10:22 +0200 Subject: [PATCH 19/40] removes labeling and adds custom fonts --- src/style/atoms/_colours.scss | 3 +++ src/style/atoms/_fonts.scss | 21 ++++++++++++++++++++ src/style/atoms/_numbers.scss | 8 ++++++++ src/style/atoms/_typography.scss | 16 +++++++++++++++ src/style/molecules/_tabs.scss | 6 +++++- src/style/styles.scss | 2 ++ src/templates/item/skill/tab-description.hbs | 2 -- 7 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 src/style/atoms/_fonts.scss create mode 100644 src/style/atoms/_typography.scss diff --git a/src/style/atoms/_colours.scss b/src/style/atoms/_colours.scss index a352d9b1..25c572ee 100644 --- a/src/style/atoms/_colours.scss +++ b/src/style/atoms/_colours.scss @@ -34,6 +34,9 @@ $tab-background-color: #fff8; $dice-box-shadow: rgba(0, 0, 0, 0.25); $pill-box-shadow: rgba(0, 0, 0, 0.3); +$tab-shadow: rgba(0, 0, 0, 0.3); +$tab-pane-shadow: rgba(0, 0, 0, 0.3); + $attribute-die-border-color: #000; $attribute-die-color: #F00; diff --git a/src/style/atoms/_fonts.scss b/src/style/atoms/_fonts.scss new file mode 100644 index 00000000..832342a1 --- /dev/null +++ b/src/style/atoms/_fonts.scss @@ -0,0 +1,21 @@ +@font-face { + font-family: "Andalus"; + src: url("../../assets/fonts/andlso.ttf"); +} + +@font-face { + font-family: "Gentium"; + src: url("../../assets/fonts/GenBasR.ttf"); +} + +@font-face { + font-family: "Gentium"; + src: url("../../assets/fonts/GenBasI.ttf"); + font-style: italic; +} + +@font-face { + font-family: "Gentium"; + src: url("../../assets/fonts/GenBasB.ttf"); + font-weight: bold; +} \ No newline at end of file diff --git a/src/style/atoms/_numbers.scss b/src/style/atoms/_numbers.scss index e79d87d1..7b8faefa 100644 --- a/src/style/atoms/_numbers.scss +++ b/src/style/atoms/_numbers.scss @@ -16,6 +16,14 @@ $dice-box-inset: 4px; $dice-box-blur-radius: 4px; $dice-box-border-width: 1px; +$tab-shadow-right: 1px; +$tab-shadow-bottom: 0; +$tab-shadow-blur-radius: 0; + +$tab-pane-shadow-right: 1px; +$tab-pane-shadow-bottom: 1px; +$tab-pane-shadow-blur-radius: 0; + $pill-box-inset: 2px; $pill-box-blur-radius: 4px; diff --git a/src/style/atoms/_typography.scss b/src/style/atoms/_typography.scss new file mode 100644 index 00000000..550bf4cf --- /dev/null +++ b/src/style/atoms/_typography.scss @@ -0,0 +1,16 @@ +.application.sheet.dsa41 { + + --font-body: Gentium, sans-serif; + + label, + .sheet-tabs.tabs a { + font-family: Gentium, sans-serif; + font-weight: bold; + } + + .editor.prosemirror.active, .editor.prosemirror.inactive { + font-family: Gentium, sans-serif; + } + +} + diff --git a/src/style/molecules/_tabs.scss b/src/style/molecules/_tabs.scss index cfc7b9ec..9a42f929 100644 --- a/src/style/molecules/_tabs.scss +++ b/src/style/molecules/_tabs.scss @@ -74,11 +74,13 @@ border-top: numbers.$tab-border-width solid colours.$tab-border-color; border-right: numbers.$tab-border-width solid colours.$tab-border-color; border-bottom: 0; - top: numbers.$tab-border-width*2; + top: numbers.$tab-border-width; background: assets.$tab-background; position: relative; z-index: 2; + box-shadow: numbers.$tab-shadow-right numbers.$tab-shadow-bottom numbers.$tab-shadow-blur-radius colours.$tab-shadow; + span { } @@ -91,6 +93,8 @@ section.tab { border: numbers.$tab-border-width solid colours.$tab-border-color; background: assets.$tab-pane-background; + box-shadow: numbers.$tab-pane-shadow-right numbers.$tab-pane-shadow-bottom numbers.$tab-pane-shadow-blur-radius colours.$tab-pane-shadow; + flex: 1; & > div { diff --git a/src/style/styles.scss b/src/style/styles.scss index eb843ead..b34105ce 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -1,3 +1,5 @@ +@use "atoms/fonts"; +@use "atoms/typography"; @use "atoms/svg"; @use "molecules/rollable"; @use "molecules/lists"; diff --git a/src/templates/item/skill/tab-description.hbs b/src/templates/item/skill/tab-description.hbs index 960cc9a0..321866d1 100644 --- a/src/templates/item/skill/tab-description.hbs +++ b/src/templates/item/skill/tab-description.hbs @@ -4,8 +4,6 @@ data-group="{{tabs.description.group}}"> {{!-- Tab content here --}}
- - Date: Fri, 17 Oct 2025 18:24:58 +0200 Subject: [PATCH 20/40] restores hiding of unimportant sheets --- src/module/sheets/character/liturgies.mjs | 7 +++-- src/module/sheets/character/spells.mjs | 7 +++-- src/module/sheets/characterSheet.mjs | 31 +++++++++++------------ 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/module/sheets/character/liturgies.mjs b/src/module/sheets/character/liturgies.mjs index 1b8c5af2..062d5966 100644 --- a/src/module/sheets/character/liturgies.mjs +++ b/src/module/sheets/character/liturgies.mjs @@ -104,8 +104,11 @@ export default { _onRender: (context, options) => { }, - _getTabConfig: (group) => { - group.tabs.push({id: "liturgies", group: "sheet", label: "Liturgien"}) + _getTabConfig: (group, thisObject) => { + const hasLiturgies = thisObject.document.items.filter(p => p.type === "Liturgy").length > 0 ?? false + if (hasLiturgies) { + group.tabs.push({id: "liturgies", group: "sheet", label: "Liturgien"}) + } }, template: `systems/DSA_4-1/templates/actor/character/tab-liturgies.hbs` } \ No newline at end of file diff --git a/src/module/sheets/character/spells.mjs b/src/module/sheets/character/spells.mjs index 8bc0a3af..920283c7 100644 --- a/src/module/sheets/character/spells.mjs +++ b/src/module/sheets/character/spells.mjs @@ -45,8 +45,11 @@ export default { _onRender: (context, options) => { }, - _getTabConfig: (group) => { - group.tabs.push({id: "spells", group: "sheet", label: "Zauber"}) + _getTabConfig: (group, thisObject) => { + const hasSpells = thisObject.document.items.filter(p => p.type === "Spell").length > 0 ?? false + if (hasSpells) { + group.tabs.push({id: "spells", group: "sheet", label: "Zauber"}) + } }, template: `systems/DSA_4-1/templates/actor/character/tab-spells.hbs` } \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index c322ade3..12fe6951 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -38,13 +38,12 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { sheet: { tabs: [ {id: 'meta', group: 'sheet', label: 'Meta'}, - {id: 'attributes', group: 'sheet', label: 'Eigenschaften'}, - {id: 'combat', group: 'sheet', label: 'Kampf'}, - {id: 'equipment', group: 'sheet', label: 'Inventar'}, - {id: 'skills', group: 'sheet', label: 'Talente'}, - {id: 'spells', group: 'sheet', label: 'Zauber'}, - {id: 'liturgies', group: 'sheet', label: 'Liturgien'}, - + // {id: 'attributes', group: 'sheet', label: 'Eigenschaften'}, + // {id: 'combat', group: 'sheet', label: 'Kampf'}, + // {id: 'equipment', group: 'sheet', label: 'Inventar'}, + // {id: 'skills', group: 'sheet', label: 'Talente'}, + // {id: 'spells', group: 'sheet', label: 'Zauber'}, + // {id: 'liturgies', group: 'sheet', label: 'Liturgien'}, ], initial: 'meta' } @@ -110,19 +109,19 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { await this.document.update(formData.object) // Note: formData.object } - /* + _getTabsConfig(group) { const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) - Attributes._getTabConfig(tabs) - Combat._getTabConfig(tabs) - Equipment._getTabConfig(tabs) - Skills._getTabConfig(tabs) - Spells._getTabConfig(tabs) - Liturgies._getTabConfig(tabs) - Effects._getTabConfig(tabs) + Attributes._getTabConfig(tabs, this) + Combat._getTabConfig(tabs, this) + Equipment._getTabConfig(tabs, this) + Skills._getTabConfig(tabs, this) + Spells._getTabConfig(tabs, this) + Liturgies._getTabConfig(tabs, this) + Effects._getTabConfig(tabs, this) return tabs } - */ + async _preparePartContext(partId, context) { switch (partId) { case "form": -- 2.43.0 From d0c2d747210ab694bddf296fefaba627a2f36ba7 Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 18:29:08 +0200 Subject: [PATCH 21/40] fixes pathing --- src/style/atoms/_fonts.scss | 8 ++++---- src/style/molecules/_sidebar-elements.scss | 2 +- src/style/organisms/_character-sheet.scss | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/style/atoms/_fonts.scss b/src/style/atoms/_fonts.scss index 832342a1..05608815 100644 --- a/src/style/atoms/_fonts.scss +++ b/src/style/atoms/_fonts.scss @@ -1,21 +1,21 @@ @font-face { font-family: "Andalus"; - src: url("../../assets/fonts/andlso.ttf"); + src: url("/systems/DSA_4-1/assets/fonts/andlso.ttf"); } @font-face { font-family: "Gentium"; - src: url("../../assets/fonts/GenBasR.ttf"); + src: url("/systems/DSA_4-1/assets/fonts/GenBasR.ttf"); } @font-face { font-family: "Gentium"; - src: url("../../assets/fonts/GenBasI.ttf"); + src: url("/systems/DSA_4-1/assets/fonts/GenBasI.ttf"); font-style: italic; } @font-face { font-family: "Gentium"; - src: url("../../assets/fonts/GenBasB.ttf"); + src: url("/systems/DSA_4-1/assets/fonts/GenBasB.ttf"); font-weight: bold; } \ No newline at end of file diff --git a/src/style/molecules/_sidebar-elements.scss b/src/style/molecules/_sidebar-elements.scss index c75bf25c..2e69c5e3 100644 --- a/src/style/molecules/_sidebar-elements.scss +++ b/src/style/molecules/_sidebar-elements.scss @@ -60,7 +60,7 @@ left: 0; top: 0; bottom: 0; - background: url('../../assets/gradient.png'); + background: url('/systems/DSA_4-1/assets/gradient.png'); background-size: 32px 100%; &::after { diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index 60f938fb..e0180656 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -317,7 +317,7 @@ .filled-segment { border: 1px solid black; - background-image: url('../../assets/gradient.png'); + background-image: url('/systems/DSA_4-1/assets/gradient.png'); background-size: 24px 100%; position: relative; flex: 1; @@ -333,7 +333,7 @@ .empty-segment { border: 1px solid black; - background-image: url('../../assets/gradient.png'); + background-image: url('/systems/DSA_4-1/assets/gradient.png'); background-size: 32px 100%; position: relative; flex: 1; -- 2.43.0 From 355f55e2bd426143b4b1b0670096d0981d820f3b Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 21:52:40 +0200 Subject: [PATCH 22/40] finally fixes the stubborn tab error --- src/main.mjs | 3 +- src/module/data/character.mjs | 2 + src/module/data/profession.mjs | 14 + src/module/documents/profession.mjs | 9 + src/module/sheets/character/social.mjs | 20 + src/module/sheets/characterSheet.mjs | 152 ++++- src/module/xml-import/xml-import.mjs | 35 +- src/style/atoms/_typography.scss | 5 + src/style/molecules/_attributes.scss | 4 - src/style/molecules/_pill.scss | 19 + src/style/molecules/_richtext-editor.scss | 10 +- src/style/organisms/_character-sheet.scss | 625 ++---------------- .../organisms/character-tabs/_attributes.scss | 121 ++++ .../organisms/character-tabs/_combat.scss | 190 ++++++ .../organisms/character-tabs/_inventory.scss | 42 ++ .../organisms/character-tabs/_liturgies.scss | 63 ++ src/style/organisms/character-tabs/_meta.scss | 64 ++ .../organisms/character-tabs/_social.scss | 38 ++ .../organisms/character-tabs/_spells.scss | 108 +++ src/style/styles.scss | 12 +- src/system.json | 8 + src/templates/actor/character/main-sheet.hbs | 20 +- .../actor/character/tab-equipment.hbs | 88 +-- src/templates/actor/character/tab-meta.hbs | 60 +- src/templates/actor/character/tab-social.hbs | 40 ++ 25 files changed, 1004 insertions(+), 748 deletions(-) create mode 100644 src/module/data/profession.mjs create mode 100644 src/module/documents/profession.mjs create mode 100644 src/module/sheets/character/social.mjs create mode 100644 src/style/molecules/_pill.scss create mode 100644 src/style/organisms/character-tabs/_attributes.scss create mode 100644 src/style/organisms/character-tabs/_combat.scss create mode 100644 src/style/organisms/character-tabs/_inventory.scss create mode 100644 src/style/organisms/character-tabs/_liturgies.scss create mode 100644 src/style/organisms/character-tabs/_meta.scss create mode 100644 src/style/organisms/character-tabs/_social.scss create mode 100644 src/style/organisms/character-tabs/_spells.scss create mode 100644 src/templates/actor/character/tab-social.hbs diff --git a/src/main.mjs b/src/main.mjs index ddfa2dd7..ec48819c 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -21,6 +21,7 @@ import {SpecialAbilitySheet} from "./module/sheets/specialAbilitySheet.mjs"; import {ActiveEffectSheet} from "./module/sheets/ActiveEffectSheet.mjs"; import {ActiveEffectDataModel} from "./module/data/activeeffect.mjs"; import {Trefferzone, Wunde, Zonenruestung, Zonenwunde} from "./module/data/Trefferzone.js"; +import {ProfessionDataModel} from "./module/data/profession.mjs"; async function preloadHandlebarsTemplates() { return foundry.applications.handlebars.loadTemplates([ @@ -70,6 +71,7 @@ Hooks.once("init", () => { Blessing: BlessingDataModel, SpecialAbility: SpecialAbilityDataModel, ActiveEffect: ActiveEffectDataModel, + Profession: ProfessionDataModel, } CONFIG.Combat.initiative = { @@ -126,7 +128,6 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.SpecialAbilityLabels.Item' }) - foundry.documents.collections.Items.registerSheet('dsa41.activeEffect', ActiveEffectSheet, { types: ['ActiveEffect'], makeDefault: true, diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index b6e5eb4b..433c8865 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -29,6 +29,8 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { familie: new HTMLField(), titel: new StringField(), stand: new StringField(), + verbindungen: new HTMLField(), + notizen: new HTMLField(), }), setEquipped: new NumberField({required: true, initial: 0, max: 3, integer: true}), ini: new SchemaField({ diff --git a/src/module/data/profession.mjs b/src/module/data/profession.mjs new file mode 100644 index 00000000..9b7b1cfe --- /dev/null +++ b/src/module/data/profession.mjs @@ -0,0 +1,14 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, StringField, HTMLField} = foundry.data.fields; + +export class ProfessionDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + revealed: new BooleanField(), + alias: new StringField(), + } + } +} \ No newline at end of file diff --git a/src/module/documents/profession.mjs b/src/module/documents/profession.mjs new file mode 100644 index 00000000..2dfb3529 --- /dev/null +++ b/src/module/documents/profession.mjs @@ -0,0 +1,9 @@ +export class Profession extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/sheets/character/social.mjs b/src/module/sheets/character/social.mjs new file mode 100644 index 00000000..c97eb622 --- /dev/null +++ b/src/module/sheets/character/social.mjs @@ -0,0 +1,20 @@ +export default { + _prepareContext: (context, object) => { + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "social", group: "sheet", label: "Soziales"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-social.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 12fe6951..d79341f9 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -1,11 +1,12 @@ -import Meta from "./character/meta.mjs" import Attributes from "./character/attributes.mjs" import Combat from "./character/combat.mjs" -import Equipment from "./character/equipment.mjs" -import Skills from "./character/skills.mjs" -import Spells from "./character/spells.mjs" -import Liturgies from "./character/liturgies.mjs" import Effects from "./character/effects.mjs" +import Equipment from "./character/equipment.mjs" +import Liturgies from "./character/liturgies.mjs" +import Meta from "./character/meta.mjs" +import Skills from "./character/skills.mjs" +import Social from "./character/social.mjs"; +import Spells from "./character/spells.mjs" const {HandlebarsApplicationMixin} = foundry.applications.api const {ActorSheetV2} = foundry.applications.sheets @@ -36,15 +37,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { static TABS = { sheet: { - tabs: [ - {id: 'meta', group: 'sheet', label: 'Meta'}, - // {id: 'attributes', group: 'sheet', label: 'Eigenschaften'}, - // {id: 'combat', group: 'sheet', label: 'Kampf'}, - // {id: 'equipment', group: 'sheet', label: 'Inventar'}, - // {id: 'skills', group: 'sheet', label: 'Talente'}, - // {id: 'spells', group: 'sheet', label: 'Zauber'}, - // {id: 'liturgies', group: 'sheet', label: 'Liturgien'}, - ], + tabs: [], initial: 'meta' } } @@ -57,6 +50,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { meta: { template: Meta.template }, + social: { + template: Social.template + }, attributes: { template: Attributes.template }, @@ -69,6 +65,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { skills: { template: Skills.template }, + spells: { + template: Spells.template + }, liturgies: { template: Liturgies.template }, @@ -112,6 +111,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { _getTabsConfig(group) { const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) + Meta._getTabConfig(tabs, this); + Social._getTabConfig(tabs, this); Attributes._getTabConfig(tabs, this) Combat._getTabConfig(tabs, this) Equipment._getTabConfig(tabs, this) @@ -125,12 +126,36 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { async _preparePartContext(partId, context) { switch (partId) { case "form": + + const findEquipmentOnSlot = (slot, setNumber, object) => { + return object.items.get(object.system.heldenausruestung[setNumber]?.[slot]) + } + const actorData = context.document context.system = actorData.system + context.isOwner = actorData.isOwner context.flags = actorData.flags context.derived = context.document.system + context.professions = actorData.items.filter(p => p.type === 'Profession').map(p => { + // is tarnidentitaet revealed? + if (p.system.revealed) { + return { + id: p.id, + name: p.name, + alias: p.system.alias, + } + } else { + return { + id: p.id, + name: p.system.alias ?? p.name, + alias: p.name, + } + } + }) + context.originalName = actorData.name context.name = context.derived.name ?? actorData.name + context.img = actorData.img context.effects = actorData.effects ?? [] context.maxWounds = actorData.system.wunden.max ?? 3 @@ -145,6 +170,89 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.ausdauer = game.settings.get("DSA_4-1", "optional_ausdauer") context.colorfulDice = game.settings.get('DSA_4-1', 'optional_colorfuldice') + + context.inidice = actorData.system.ini.wuerfel + context.inivalue = actorData.system.ini.aktuell + context.inimod = actorData.system.ini.mod + + context.aupper = Math.min((actorData.system.aup.aktuell / actorData.system.aup.max) * 100, 100) + context.lepper = Math.min((actorData.system.lep.aktuell / actorData.system.lep.max) * 100, 100) + context.keper = Math.min((actorData.system.kap.aktuell / actorData.system.kap.max) * 100, 100) + context.aspper = Math.min((actorData.system.asp.aktuell / actorData.system.asp.max) * 100, 100) + context.lepcurrent = actorData.system.lep.aktuell ?? 0 + + context.aupcurrent = actorData.system.aup.aktuell ?? 0 + + const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) + const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) + const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) + context.attacks = []; + + if (fernkampf) { + const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion)) + fkitems.forEach(async skill => { + const obj = await skill + context.attacks.push({ + name: obj.name, + using: fernkampf.name, + atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`, + at: `${object.system.fk.aktuell + obj.system.at}`, + tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod + tp: `${fernkampf.system.rangedAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, + }) + }) + } + if (links) { + const meitems = [] + links.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: links.name, + atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, + tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${links.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`, + }) + }) + } + if (rechts) { + const meitems = [] + rechts.system.meleeSkills.forEach((skillInQuestion) => { + const item = actorData.items.find(p => p.name === skillInQuestion) + if (item) { + meitems.push(item) + } + }) + meitems.forEach(skill => { + const obj = skill + context.attacks.push({ + name: obj.name, + using: rechts.name, + atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M + at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, + paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M + pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, + tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod + tp: `${rechts.system.meleeAttackDamage}`, + iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, + }) + }) + } + context.attributes = [ { eigenschaft: "mu", @@ -198,7 +306,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { break; case "meta": - Meta._prepareContext(context, this.object) + await Meta._prepareContext(context, this.object) + break + case "social": + await Social._prepareContext(context, this.object) break case "attributes": await Attributes._prepareContext(context, this.object) @@ -207,19 +318,19 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { await Combat._prepareContext(context, this.object) break case "equipment": - Equipment._prepareContext(context, this.object) + await Equipment._prepareContext(context, this.object) break case "skills": - Skills._prepareContext(context, this.object) + await Skills._prepareContext(context, this.object) break case "spells": - Spells._prepareContext(context, this.object) + await Spells._prepareContext(context, this.object) break case "liturgies": - Liturgies._prepareContext(context, this.object) + await Liturgies._prepareContext(context, this.object) break case "effects": - Effects._prepareContext(context, this.object) + await Effects._prepareContext(context, this.object) break } return context @@ -227,6 +338,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { _onRender(context, options) { Meta._onRender(context, options, this.element) + Social._onRender(context, options, this.element) Attributes._onRender(context, options, this.element) Combat._onRender(context, options, this.element) Effects._onRender(context, options, this.element) diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index 1e7eadce..f24f3189 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -1,6 +1,7 @@ import {LiturgyData} from "../data/miracle/liturgydata.mjs"; import {BlessingDataModel} from "../data/blessing.mjs"; import {Blessing} from "../documents/blessing.mjs"; +import {Profession} from "../documents/profession.mjs"; let months = [ "Praios", @@ -232,6 +233,28 @@ function mapMiracles(actor, liturgies) { } } +function mapProfessions(actor, professions) { + if (professions.string) { + professions = {hauptprofession: professions} + } + Object.values(professions).forEach(profession => { + actor.createEmbeddedDocuments('Item', [ + new Profession({ + name: profession.string, + type: "Profession", + system: { + description: "", + alias: profession.tarnidentitaet ? profession.tarnidentitaet : profession.string, + revealed: !profession.tarnidentitaet + } + }) + ]) + }) + // actor.update({"system.meta.professions": professions}) + + +} + /** * parses a json into a fitting character-json * @param rawJson the json parsed from the Helden-Software XML @@ -244,17 +267,7 @@ function mapRawJson(actor, rawJson) { 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 + mapProfessions(actor, held.basis.ausbildungen.ausbildung) json.meta.geschlecht = held.basis.geschlecht.name json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe json.meta.groesse = held.basis.rasse.groesse.value diff --git a/src/style/atoms/_typography.scss b/src/style/atoms/_typography.scss index 550bf4cf..109ead76 100644 --- a/src/style/atoms/_typography.scss +++ b/src/style/atoms/_typography.scss @@ -8,6 +8,11 @@ font-weight: bold; } + input, + .rkp .pill { + font-family: Andalus, sans-serif; + } + .editor.prosemirror.active, .editor.prosemirror.inactive { font-family: Gentium, sans-serif; } diff --git a/src/style/molecules/_attributes.scss b/src/style/molecules/_attributes.scss index 5bcbd8ed..3c8ef194 100644 --- a/src/style/molecules/_attributes.scss +++ b/src/style/molecules/_attributes.scss @@ -9,10 +9,6 @@ position: relative; .attributes { - position: absolute; - top: 8px; - right: 4px; - height: 48px; display: flex; .attribute.rollable { diff --git a/src/style/molecules/_pill.scss b/src/style/molecules/_pill.scss new file mode 100644 index 00000000..3c8ba82c --- /dev/null +++ b/src/style/molecules/_pill.scss @@ -0,0 +1,19 @@ +.application.sheet.dsa41 { + + .pill { + + height: 24px; + line-height: 24px; + font-size: 14px; + vertical-align: middle; + padding: 1px 4px; + margin-right: 4px; + border-radius: 8px; + border: 1px solid orange; + color: orange; + background-color: rgba(0, 0, 0, 0.6); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), inset -1px -1px 0 rgba(0, 0, 0, 0.1); + display: inline-block; + } + +} \ No newline at end of file diff --git a/src/style/molecules/_richtext-editor.scss b/src/style/molecules/_richtext-editor.scss index 1f1e331d..ffe51fae 100644 --- a/src/style/molecules/_richtext-editor.scss +++ b/src/style/molecules/_richtext-editor.scss @@ -1,7 +1,13 @@ -.dsa41.sheet { +.application.sheet.dsa41 { - .editor.prosemirror.active, .editor.prosemirror.inactive { + .editor.prosemirror { flex: 1; + background-color: rgba(0, 0, 0, 0.1); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.1); + border: 1px solid #666; + outline: 1px solid transparent; + border-radius: 4px; + } } \ No newline at end of file diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index e0180656..1240a2a9 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -1,6 +1,14 @@ @use "sass:color"; @use "../atoms/numbers"; @use "../atoms/colours" as colour; +@use "./character-tabs/meta"; +@use "./character-tabs/social"; +@use "./character-tabs/attributes"; +@use "./character-tabs/inventory"; +@use "./character-tabs/combat"; +@use "./character-tabs/spells"; +@use "./character-tabs/liturgies"; + .application.sheet.dsa41.actor.character { @@ -20,15 +28,24 @@ left: 0; height: $attribute-height; right: 0; + display: grid; + grid-template-columns: 1fr max-content; + gap: 0 8px; + + .name { + border: unset; + font-size: large; + } + } div.head-data { position: absolute; - left: 0; - top: $attribute-height; - width: $sidebar-width; - bottom: 0; - padding: 8px; + left: 16px; + top: $attribute-height+30px; + width: $sidebar-width - 16px; + bottom: 16px; + padding: 0; .profile-img { @@ -38,609 +55,49 @@ nav.sheet-tabs.tabs { position: absolute; - left: $sidebar-width; - top: $attribute-height+$tabs-spacing; - right: 0; + left: $sidebar-width+16px; + top: $attribute-height+$tabs-spacing+13px; + right: 16px; height: $tabs-height; } section.tab { position: absolute; - top: $attribute-height+$tabs-height+$tabs-spacing+4px; - left: $sidebar-width; - right: 4px; - bottom: 4px; - padding: 8px; + top: $attribute-height+$tabs-height+$tabs-spacing+21px; + left: $sidebar-width+16px; + right: 16px; + bottom: 16px; + padding: 0; overflow: auto; } - .tab.overview.active { - - display: flex; - flex-direction: column; - height: 100%; - - .meta-data { - flex: 0; - - columns: 2; - gap: 0 16px; - - - div { - break-inside: avoid; - padding: 4px 0; - } - - .double { - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-areas: 'label label' 'left right'; - gap: 0 8px; - - label { - grid-area: label; - } - } - - .editor { - background-color: rgba(0, 0, 0, 0.2) - } - - & + .meta-data { - flex: 1; - } - } - - .meta-data.html { - - & > div { - display: flex; - flex-direction: column; - height: 100%; - - label { - flex: 0; - } - - .editor { - flex: 1; - } - } - - } + .tab.meta.active { + @include meta.tab; + } + .tab.social.active { + @include social.tab; } .tab.attributes.active { - height: 100%; - - .attribute { - padding: 8px 0; - display: flex; - gap: 0 8px; - - label { - width: 120px; - text-align: right; - vertical-align: middle; - line-height: 24px; - } - - input { - max-width: 80px; - text-align: right; - } - - .mod { - color: grey; - text-shadow: 0 -1px 0 #ccc; - box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); - border-radius: 4px; - height: 24px; - width: 24px; - background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);; - display: inline-block; - text-align: center; - vertical-align: middle; - line-height: 24px; - margin-left: 4px; - } - - } - - .attributes-overview { - - columns: 2; - gap: 0 16px; - - } - - .resource-overview { - - .attribute { - - } - - } - - .advantages, .special-abilities { - margin-bottom: 16px; - - ul { - list-style-type: none; - padding: 0; - margin: 0; - text-indent: 0; - - li { - display: inline-block; - } - - .advantage, .special-ability { - position: relative; - border: 1px solid gold; - box-shadow: 2px 2px 4px #000; - border-radius: 8px; - height: 24px; - color: gold; - text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); - display: inline-block; - padding: 0 8px; - margin-left: 0; - margin-bottom: 4px; - background-image: url("../../assets/velvet_button.png"); - background-repeat: repeat-y; - background-size: cover; - - span { - position: relative; - z-index: 2; - line-height: 24px; - vertical-align: middle; - } - - &.special-ability { - &::after { - background: rgba(128, 0, 96, 0.5); - } - } - - &::after { - content: ""; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - border-radius: 8px; - background: rgba(0, 128, 0, 0.5); - } - - & + .advantage, & + .special-ability { - margin-left: 8px; - } - - &.disadvantage { - font-style: italic; - - &::after { - background: rgba(128, 0, 0, 0.5); - } - } - } - } - - } - - + @include attributes.tab; } - .backpack.active { - display: grid; - grid-template-columns: 1fr 320px; - grid-template-rows: 74px 1fr; - gap: 10px; - height: 100%; - grid-template-areas: - "capacity capacity" - "inventory equipment"; - - .capacity { - - grid-area: capacity; - - .resource { - - position: relative; - border: 1px inset #ccc; - background-color: rgba(0, 0, 0, 0.2); - height: 8px; - - span.fill { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); - } - - } - } - - .inventory { - grid-area: inventory; - - .equipment:hover { - .item-name { - text-shadow: 0 0 10px rgb(255 0 0); - } - } - } + .inventory.active { + @include inventory.tab; } .tab.combat.active { - - display: grid; - - grid-template-columns: 1fr 320px; - grid-template-rows: 32px 32px 1fr; - grid-template-areas: "res res" "wounds wounds" "actions actions"; - gap: 10px; - - .tab-resources { - grid-area: res; - } - - .wounds { - position: relative; - height: 24px; - display: flex; - margin-bottom: 8px; - padding-left: 130px; - grid-area: wounds; - - label { - position: absolute; - left: 0; - top: 0; - line-height: 24px; - width: 120px; - bottom: 0; - vertical-align: middle; - text-align: right; - height: 24px; - display: inline-block; - z-index: 2; - } - - .filled-segment { - border: 1px solid black; - background-image: url('/systems/DSA_4-1/assets/gradient.png'); - background-size: 24px 100%; - position: relative; - flex: 1; - text-align: center; - vertical-align: middle; - line-height: 24px; - color: white; - text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); - background-color: rgba(255, 0, 0, 0.8); - background-blend-mode: multiply; - - } - - .empty-segment { - border: 1px solid black; - background-image: url('/systems/DSA_4-1/assets/gradient.png'); - background-size: 32px 100%; - position: relative; - flex: 1; - text-align: center; - vertical-align: middle; - line-height: 24px; - color: gold; - text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); - background-color: rgba(0, 0, 0, 0.8); - background-blend-mode: multiply; - - } - - } - - .actions { - grid-area: actions; - } - - &.zones { - grid-template-areas: "res res" "wounds wounds" "actions paperdoll"; - - .paperdoll { - grid-area: paperdoll; - - div { - position: relative; - margin-left: 9px; - margin-top: 42px; - - .wound { - position: absolute; - width: 32px; - height: 32px; - border-radius: 16px; - border: 1px solid black; - background-color: rgba(0, 0, 0, 0.5); - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); - line-height: 32px; - vertical-align: middle; - text-align: center; - color: red; - - - &.armlinks { - top: 146px; - left: 210px; - } - - &.armrechts { - top: 146px; - left: 60px; - } - - &.beinlinks { - top: 346px; - left: 210px; - } - - &.beinrechts { - top: 346px; - left: 60px; - } - - &.bauch { - top: 166px; - left: 136px; - } - - &.kopf { - top: 6px; - left: 136px - } - - &.brust { - top: 86px; - left: 110px; - } - - } - - .armor { - position: absolute; - width: 32px; - height: 32px; - border-radius: 0 0 16px 16px; - line-height: 32px; - vertical-align: middle; - text-align: center; - border: 1px solid silver; - background-color: rgba(0, 0, 0, 0.5); - box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); - color: silver; - - &.armlinks { - top: 180px; - left: 210px; - } - - &.armrechts { - top: 180px; - left: 60px; - } - - &.beinlinks { - top: 380px; - left: 210px; - } - - &.beinrechts { - top: 380px; - left: 60px; - } - - &.bauch { - top: 200px; - left: 136px; - } - - &.kopf { - top: 40px; - left: 136px - } - - &.brust { - top: 120px; - left: 110px; - } - } - } - - } - - } - - + @include combat.tab; } .tab.spells { - - tr { - height: 24px; - margin: 0; - padding: 0; - } - - td { - margin: 0; - padding: 0; - height: 24px; - } - - $color: #05f; - - .spell.rollable svg { - width: 24px; - height: 24px; - top: 1px; - z-index: 1; - position: relative; - - .border { - fill: #0000; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } - } - - .die-column { - width: 24px; - } - - .clickable { - span { - position: relative; - z-index: 1; - } - } - - tbody { - - tr { - - position: relative; - - &::after { - content: ''; - background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient)); - border-top-right-radius: 8px; - border-bottom-right-radius: 8px; - position: absolute; - top: 2px; - left: 12px; - bottom: 2px; - right: 33%; - z-index: 0; - pointer-events: none; - } - - &:nth-child(odd) { - &::after { - background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient)); - } - } - } - - } - - .merkmal-list { - list-style: none; - margin: 0; - padding: 0; - text-indent: 0; - - li { - display: inline-block; - padding: 0 4px; - } - } - + @include spells.tab; } .tab.liturgies { - - table { - border-top: unset; - border-bottom: unset; - position: relative; - } - - .liturgy-header { - background: unset; - border: unset; - - tr { - height: 90px; - - th { - vertical-align: middle; - color: black; - text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2); - } - } - } - - td, th { - padding-left: 8px; - } - } - - .tab-resources { - display: flex; - justify-content: center; - gap: 0 16px; - padding-bottom: 8px; - - & > div { - - - height: 32px; - position: relative; - - label { - width: 80px; - line-height: 32px; - vertical-align: middle; - } - - input { - display: inline-block; - width: 40px; - height: 32px; - } - - span.inline { - line-height: 32px; - vertical-align: middle; - width: 40px; - text-align: center; - } - - - } - + @include liturgies.tab; } } diff --git a/src/style/organisms/character-tabs/_attributes.scss b/src/style/organisms/character-tabs/_attributes.scss new file mode 100644 index 00000000..e9a959bb --- /dev/null +++ b/src/style/organisms/character-tabs/_attributes.scss @@ -0,0 +1,121 @@ +@mixin tab { + height: 100%; + + .attribute { + padding: 8px 0; + display: flex; + gap: 0 8px; + + label { + width: 120px; + text-align: right; + vertical-align: middle; + line-height: 24px; + } + + input { + max-width: 80px; + text-align: right; + } + + .mod { + color: grey; + text-shadow: 0 -1px 0 #ccc; + box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); + border-radius: 4px; + height: 24px; + width: 24px; + background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);; + display: inline-block; + text-align: center; + vertical-align: middle; + line-height: 24px; + margin-left: 4px; + } + + } + + .attributes-overview { + + columns: 2; + gap: 0 16px; + + } + + .resource-overview { + + .attribute { + + } + + } + + .advantages, .special-abilities { + margin-bottom: 16px; + + ul { + list-style-type: none; + padding: 0; + margin: 0; + text-indent: 0; + + li { + display: inline-block; + } + + .advantage, .special-ability { + position: relative; + border: 1px solid gold; + box-shadow: 2px 2px 4px #000; + border-radius: 8px; + height: 24px; + color: gold; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + display: inline-block; + padding: 0 8px; + margin-left: 0; + margin-bottom: 4px; + background-image: url("../../assets/velvet_button.png"); + background-repeat: repeat-y; + background-size: cover; + + span { + position: relative; + z-index: 2; + line-height: 24px; + vertical-align: middle; + } + + &.special-ability { + &::after { + background: rgba(128, 0, 96, 0.5); + } + } + + &::after { + content: ""; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border-radius: 8px; + background: rgba(0, 128, 0, 0.5); + } + + & + .advantage, & + .special-ability { + margin-left: 8px; + } + + &.disadvantage { + font-style: italic; + + &::after { + background: rgba(128, 0, 0, 0.5); + } + } + } + } + + } +} diff --git a/src/style/organisms/character-tabs/_combat.scss b/src/style/organisms/character-tabs/_combat.scss new file mode 100644 index 00000000..adad410d --- /dev/null +++ b/src/style/organisms/character-tabs/_combat.scss @@ -0,0 +1,190 @@ +@mixin tab { + + display: grid; + + grid-template-columns: 1fr 320px; + grid-template-rows: 32px 32px 1fr; + grid-template-areas: "res res" "wounds wounds" "actions actions"; + gap: 10px; + + .tab-resources { + grid-area: res; + } + + .wounds { + position: relative; + height: 24px; + display: flex; + margin-bottom: 8px; + padding-left: 130px; + grid-area: wounds; + + label { + position: absolute; + left: 0; + top: 0; + line-height: 24px; + width: 120px; + bottom: 0; + vertical-align: middle; + text-align: right; + height: 24px; + display: inline-block; + z-index: 2; + } + + .filled-segment { + border: 1px solid black; + background-image: url('/systems/DSA_4-1/assets/gradient.png'); + background-size: 24px 100%; + position: relative; + flex: 1; + text-align: center; + vertical-align: middle; + line-height: 24px; + color: white; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); + background-color: rgba(255, 0, 0, 0.8); + background-blend-mode: multiply; + + } + + .empty-segment { + border: 1px solid black; + background-image: url('/systems/DSA_4-1/assets/gradient.png'); + background-size: 32px 100%; + position: relative; + flex: 1; + text-align: center; + vertical-align: middle; + line-height: 24px; + color: gold; + text-shadow: 2px 2px 0 rgba(0, 0, 0, 0.3); + background-color: rgba(0, 0, 0, 0.8); + background-blend-mode: multiply; + + } + + } + + .actions { + grid-area: actions; + } + + &.zones { + grid-template-areas: "res res" "wounds wounds" "actions paperdoll"; + + .paperdoll { + grid-area: paperdoll; + + div { + position: relative; + margin-left: 9px; + margin-top: 42px; + + .wound { + position: absolute; + width: 32px; + height: 32px; + border-radius: 16px; + border: 1px solid black; + background-color: rgba(0, 0, 0, 0.5); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); + line-height: 32px; + vertical-align: middle; + text-align: center; + color: red; + + + &.armlinks { + top: 146px; + left: 210px; + } + + &.armrechts { + top: 146px; + left: 60px; + } + + &.beinlinks { + top: 346px; + left: 210px; + } + + &.beinrechts { + top: 346px; + left: 60px; + } + + &.bauch { + top: 166px; + left: 136px; + } + + &.kopf { + top: 6px; + left: 136px + } + + &.brust { + top: 86px; + left: 110px; + } + + } + + .armor { + position: absolute; + width: 32px; + height: 32px; + border-radius: 0 0 16px 16px; + line-height: 32px; + vertical-align: middle; + text-align: center; + border: 1px solid silver; + background-color: rgba(0, 0, 0, 0.5); + box-shadow: 1px 1px 1px rgba(0, 0, 0, 0.3); + color: silver; + + &.armlinks { + top: 180px; + left: 210px; + } + + &.armrechts { + top: 180px; + left: 60px; + } + + &.beinlinks { + top: 380px; + left: 210px; + } + + &.beinrechts { + top: 380px; + left: 60px; + } + + &.bauch { + top: 200px; + left: 136px; + } + + &.kopf { + top: 40px; + left: 136px + } + + &.brust { + top: 120px; + left: 110px; + } + } + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_inventory.scss b/src/style/organisms/character-tabs/_inventory.scss new file mode 100644 index 00000000..94846cef --- /dev/null +++ b/src/style/organisms/character-tabs/_inventory.scss @@ -0,0 +1,42 @@ +@mixin tab { + display: grid; + grid-template-columns: 1fr 320px; + grid-template-rows: 74px 1fr; + gap: 10px; + height: 100%; + grid-template-areas: +"capacity capacity" +"inventory equipment"; + + .capacity { + + grid-area: capacity; + + .resource { + + position: relative; + border: 1px inset #ccc; + background-color: rgba(0, 0, 0, 0.2); + height: 8px; + + span.fill { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); + } + + } + } + + .inventory { + grid-area: inventory; + + .equipment:hover { + .item-name { + text-shadow: 0 0 10px rgb(255 0 0); + } + } + } +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_liturgies.scss b/src/style/organisms/character-tabs/_liturgies.scss new file mode 100644 index 00000000..d780da26 --- /dev/null +++ b/src/style/organisms/character-tabs/_liturgies.scss @@ -0,0 +1,63 @@ +@mixin tab { + + table { + border-top: unset; + border-bottom: unset; + position: relative; + } + + .liturgy-header { + background: unset; + border: unset; + + tr { + height: 90px; + + th { + vertical-align: middle; + color: black; + text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.2); + } + } + } + + td, th { + padding-left: 8px; + } +} + +.tab-resources { + display: flex; + justify-content: center; + gap: 0 16px; + padding-bottom: 8px; + + & > div { + + + height: 32px; + position: relative; + + label { + width: 80px; + line-height: 32px; + vertical-align: middle; + } + + input { + display: inline-block; + width: 40px; + height: 32px; + } + + span.inline { + line-height: 32px; + vertical-align: middle; + width: 40px; + text-align: center; + } + + + } + +} \ No newline at end of file diff --git a/src/style/organisms/character-tabs/_meta.scss b/src/style/organisms/character-tabs/_meta.scss new file mode 100644 index 00000000..62876997 --- /dev/null +++ b/src/style/organisms/character-tabs/_meta.scss @@ -0,0 +1,64 @@ +@mixin tab { + + display: flex; + flex-direction: column; + + .meta-data { + flex: 0; + height: unset; + columns: 2; + gap: 0 16px; + + + div { + break-inside: avoid; + } + + .meta-line { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + gap: 0 8px; + padding-bottom: 8px; + } + + .double { + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-areas: 'label label' 'left right'; + gap: 0 8px; + + label { + grid-area: label; + } + } + + & + .meta-data { + flex: 1; + } + } + + .meta-data.html { + height: unset; + display: flex; + flex-direction: row; + gap: 0 8px; + flex: 1; + + & > div { + flex: 1; + display: flex; + flex-direction: column; + height: 100%; + + label { + flex: 0; + } + + .editor { + flex: 1; + } + } + + } + +} diff --git a/src/style/organisms/character-tabs/_social.scss b/src/style/organisms/character-tabs/_social.scss new file mode 100644 index 00000000..bbfc49e7 --- /dev/null +++ b/src/style/organisms/character-tabs/_social.scss @@ -0,0 +1,38 @@ +@mixin tab { + + display: flex; + flex-direction: column; + + .social-line { + flex: 0; + height: unset; + display: grid; + grid-template-columns: 1fr 1fr 80px; + } + + .meta-data.html { + + height: unset; + display: flex; + flex-direction: row; + gap: 0 8px; + flex: 1; + + & > div { + display: flex; + flex-direction: column; + height: 100%; + flex: 1; + + label { + flex: 0; + } + + .editor { + flex: 1; + } + } + + } + +} diff --git a/src/style/organisms/character-tabs/_spells.scss b/src/style/organisms/character-tabs/_spells.scss new file mode 100644 index 00000000..433d556d --- /dev/null +++ b/src/style/organisms/character-tabs/_spells.scss @@ -0,0 +1,108 @@ +@use "sass:color"; +@use "../../atoms/numbers"; +@use "../../atoms/colours" as colour; + +@mixin tab { + tr { + height: 24px; + margin: 0; + padding: 0; + } + + td { + margin: 0; + padding: 0; + height: 24px; + } + + $color: #05f; + + .spell.rollable svg { + width: 24px; + height: 24px; + top: 1px; + z-index: 1; + position: relative; + + .border { + fill: #0000; + } + + .center { + fill: $color; + stroke: colour.$rollable-die-border-color; + } + + .topleft { + fill: color.adjust($color, $lightness: numbers.$lighter_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomleft { + fill: color.adjust($color, $lightness: numbers.$lightest_factor); + stroke: colour.$rollable-die-border-color; + } + + .topright { + fill: color.adjust($color, $lightness: numbers.$darken_factor); + stroke: colour.$rollable-die-border-color; + } + + .bottomright, .bottom { + fill: color.adjust($color, $lightness: numbers.$darkest_factor); + stroke: colour.$rollable-die-border-color; + } + } + + .die-column { + width: 24px; + } + + .clickable { + span { + position: relative; + z-index: 1; + } + } + + tbody { + + tr { + + position: relative; + + &::after { + content: ''; + background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_light), numbers.$end_2_gradient)); + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + position: absolute; + top: 2px; + left: 12px; + bottom: 2px; + right: 33%; + z-index: 0; + pointer-events: none; + } + + &:nth-child(odd) { + &::after { + background-image: linear-gradient(to right, rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$start_gradient), rgba(color.scale($color, $lightness: numbers.$zebra_dark), numbers.$end_2_gradient)); + } + } + } + + } + + .merkmal-list { + list-style: none; + margin: 0; + padding: 0; + text-indent: 0; + + li { + display: inline-block; + padding: 0 4px; + } + } +} \ No newline at end of file diff --git a/src/style/styles.scss b/src/style/styles.scss index b34105ce..97ef261f 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -1,20 +1,22 @@ @use "atoms/fonts"; @use "atoms/typography"; @use "atoms/svg"; +@use "molecules/pill"; @use "molecules/rollable"; @use "molecules/lists"; @use "molecules/attributes"; @use "molecules/sidebar-elements"; + +@use "molecules/tabs"; +@use "molecules/paperdoll"; +@use "molecules/player-action"; +@use "molecules/liturgy-banner"; +@use "molecules/richtext-editor"; @use "organisms/character-sheet"; @use "organisms/group-sheet"; -@use "molecules/tabs"; @use "organisms/equipment-sheet"; -@use "molecules/paperdoll"; @use "organisms/creature-sheet"; -@use "molecules/player-action"; @use "organisms/modify-liturgy"; -@use "molecules/liturgy-banner"; @use "organisms/skill-sheet"; @use "organisms/active-effect-sheet"; @use "organisms/advantage-sheet"; -@use "molecules/richtext-editor"; \ No newline at end of file diff --git a/src/system.json b/src/system.json index 64166527..ae1ac3de 100644 --- a/src/system.json +++ b/src/system.json @@ -127,6 +127,14 @@ } }, "Item": { + "Profession": { + "htmlFields": [ + "description" + ], + "booleanFields": [ + "revealed" + ] + }, "Equipment": { "stringFields": [ "name", diff --git a/src/templates/actor/character/main-sheet.hbs b/src/templates/actor/character/main-sheet.hbs index 089a3ae1..9f4c6003 100644 --- a/src/templates/actor/character/main-sheet.hbs +++ b/src/templates/actor/character/main-sheet.hbs @@ -3,7 +3,19 @@ {{!-- Sheet Header --}}
{{!-- Header stuff goes here --}} +
+
+ +
+ {{system.meta.spezies}} + {{system.meta.kultur}} + {{#each professions}} + {{this.name}} + {{/each}} +
+
{{#each attributes}} {{> "systems/DSA_4-1/templates/ui/partial-attribute-button.hbs" this}} @@ -13,10 +25,8 @@
-

- - + + {{/each}} - -
{{!-- Sheet Tab Navigation --}} diff --git a/src/templates/actor/character/tab-equipment.hbs b/src/templates/actor/character/tab-equipment.hbs index 526254f3..213deb5c 100644 --- a/src/templates/actor/character/tab-equipment.hbs +++ b/src/templates/actor/character/tab-equipment.hbs @@ -1,85 +1,5 @@ -
-
-

Kampftalente

-
    - {{#each skills.Kampf}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-weaponskill-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Körperliche Talente

-
    -
  • - {{#each skills.Körperlich}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Gesellschaftliche Talente

-
    -
  • - {{#each skills.Gesellschaft}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Natur Talente

-
    -
  • - {{#each skills.Natur}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Wissenstalente

-
    -
  • - {{#each skills.Wissen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Schriften & Sprachen

-
    -
  • - {{#each skills.Schriften}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} - {{#each skills.Sprachen}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-language-button.hbs" this}} -
  • - {{/each}} -
-
-
-

Handwerkliche Talente

-
    -
  • - {{#each skills.Handwerk}} -
  • - {{> "systems/DSA_4-1/templates/ui/partial-rollable-button.hbs" this}} -
  • - {{/each}} -
-
+
+ To be done
\ No newline at end of file diff --git a/src/templates/actor/character/tab-meta.hbs b/src/templates/actor/character/tab-meta.hbs index 324470dc..71fa322e 100644 --- a/src/templates/actor/character/tab-meta.hbs +++ b/src/templates/actor/character/tab-meta.hbs @@ -4,32 +4,18 @@
\ No newline at end of file diff --git a/src/templates/actor/character/tab-social.hbs b/src/templates/actor/character/tab-social.hbs new file mode 100644 index 00000000..d4a5256c --- /dev/null +++ b/src/templates/actor/character/tab-social.hbs @@ -0,0 +1,40 @@ +
+ + + +
\ No newline at end of file -- 2.43.0 From aa6a8d1bcc6911a263a792d1f2eb124ec292cc7b Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 22:06:10 +0200 Subject: [PATCH 23/40] restores visuals of skills --- src/style/molecules/_lists.scss | 4 +++ src/style/molecules/_rollable.scss | 43 +++++++++--------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/style/molecules/_lists.scss b/src/style/molecules/_lists.scss index 7372c8d6..29c868e6 100644 --- a/src/style/molecules/_lists.scss +++ b/src/style/molecules/_lists.scss @@ -7,6 +7,10 @@ .talent-group { break-inside: avoid-column; + display: unset; + height: unset; + gap: unset; + padding: unset; } ul { diff --git a/src/style/molecules/_rollable.scss b/src/style/molecules/_rollable.scss index de8f7ac2..fbeda860 100644 --- a/src/style/molecules/_rollable.scss +++ b/src/style/molecules/_rollable.scss @@ -146,7 +146,7 @@ $rollable_colours_font: ( .value { width: 28px; height: 28px; - left: 0; + left: -1px; top: -2px; scale: 0.8; @@ -171,39 +171,22 @@ $rollable_colours_font: ( .die { stroke-width: 0.5; + svg { + + margin: -4px; + + path { + fill: $color; + stroke: colour.$rollable-die-border-color; + stroke-width: 5px; + } + } + span.value { color: $font_color; + } - .border { - fill: colour.$rollable-die-border-color; - stroke: colour.$rollable-die-border-color; - } - - .center { - fill: $color; - stroke: colour.$rollable-die-border-color; - } - - .topleft { - fill: color.adjust($color, $lightness: numbers.$lighter_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomleft { - fill: color.adjust($color, $lightness: numbers.$lightest_factor); - stroke: colour.$rollable-die-border-color; - } - - .topright { - fill: color.adjust($color, $lightness: numbers.$darken_factor); - stroke: colour.$rollable-die-border-color; - } - - .bottomright, .bottom { - fill: color.adjust($color, $lightness: numbers.$darkest_factor); - stroke: colour.$rollable-die-border-color; - } } .container { -- 2.43.0 From e031fe712cad9bf5ad85aec67d25becf4e744143 Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 22:16:15 +0200 Subject: [PATCH 24/40] restores rollability --- src/module/sheets/character/skills.mjs | 2 +- src/module/sheets/characterSheet.mjs | 9 +++++++++ src/templates/ui/partial-rollable-button.hbs | 5 +++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs index b8c271c0..58e14280 100644 --- a/src/module/sheets/character/skills.mjs +++ b/src/module/sheets/character/skills.mjs @@ -22,7 +22,7 @@ export default { context.skills = {}; context.flatSkills = []; - Object.values(actorData.items).forEach((item, index) => { + actorData.items.forEach((item, index) => { if (item.type === "Skill") { const talentGruppe = item.system.gruppe; diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index d79341f9..d60bc6d1 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -29,6 +29,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { resizable: true, }, actions: { + rollSkill: CharacterSheet.#rollSkill, roll: CharacterSheet.#dieRoll, editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument, @@ -76,6 +77,14 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } } + static #rollSkill(event) { + const {id} = event.srcElement.dataset + const skill = this.document.items.get(id) + if (skill?.system?.roll) { + skill.system.roll("publicroll") + } + } + static #dieRoll(event) { event.preventDefault() const dataset = event.currentTarget.dataset diff --git a/src/templates/ui/partial-rollable-button.hbs b/src/templates/ui/partial-rollable-button.hbs index 535886b1..7007661b 100644 --- a/src/templates/ui/partial-rollable-button.hbs +++ b/src/templates/ui/partial-rollable-button.hbs @@ -1,12 +1,13 @@ -
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{#if this.taw}} + {{#if this.taw}} {{this.taw}} {{else}} {{#if this.liturgiekenntnis}} -- 2.43.0 From 2900a45959fe14d2499b2d023bfb33f0f6d79bf1 Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 22:55:44 +0200 Subject: [PATCH 25/40] restores rollability also for combat skills --- src/module/data/skill.mjs | 84 ++++++++++++++++++- src/module/documents/character.mjs | 6 +- src/module/sheets/characterSheet.mjs | 20 ++++- .../partial-rollable-weaponskill-button.hbs | 3 +- 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/module/data/skill.mjs b/src/module/data/skill.mjs index 90d2a4f1..4385777b 100644 --- a/src/module/data/skill.mjs +++ b/src/module/data/skill.mjs @@ -44,13 +44,89 @@ export class SkillDataModel extends BaseItem { } /** - * Handle clickable rolls. - * @param {RollMode} rollMode - * @private + * Determines the values to consult for the given type of roll (normal: talent roll, attack: AT, parry: PA + * @returns {{NORMAL: string, ATTACK: string, PARRY: string}} + * @constructor */ - async roll(rollMode = null) { + get SKILL_MODE() { + return { + NORMAL: "NORMAL", + ATTACK: "ATTACK", + PARRY: "PARRY", + } + } + + + /** + * + * @param rollMode {["publicroll","gmroll"] } + * @param mode + * @returns {Promise} + */ + async roll(rollMode = null, mode = this.SKILL_MODE.NORMAL) { + + + rollMode = rollMode ?? game.settings.get('core', 'rollMode'); + + switch (mode) { + case this.SKILL_MODE.NORMAL: + return this.#talentRoll(rollMode) + case this.SKILL_MODE.ATTACK: + case this.SKILL_MODE.PARRY: + return this.#combatRoll(rollMode, mode) + } + + } + + async #combatRoll(rollMode, mode) { const owner = this.parent.parent + const rollData = owner.getRollData() + + let targetNumber = 0 + + if (mode === this.SKILL_MODE.ATTACK) { + targetNumber = this.at + owner.system.at.basis + } else { + targetNumber = this.pa + owner.system.pa.basis + } + + let roll1 = new Roll(`1d20cs<${targetNumber}`, owner.getRollData()); + + let evaluated1 = (await roll1.evaluate()) + + const rolledValue = evaluated1.terms[0].results[0].result + + if (rolledValue === 1 || rolledValue === 20) { // TODO: Modify this target + // fill with actual evaluation (targetNumber should be reduced by X and roll against that again) + } + + let message = "" + if (mode === this.SKILL_MODE.ATTACK) { + if (rolledValue <= targetNumber) { + message = `Würde treffen [${rolledValue}]` + } else { + message = `Verfehlt [${rolledValue}]` + } + } else { + if (rolledValue <= targetNumber) { + message = `Würde parrieren [${rolledValue}]` + } else { + message = `Verfehlt die parade [${rolledValue}]` + } + } + + evaluated1.toMessage({ + speaker: ChatMessage.getSpeaker({actor: owner}), + flavor: message, + rollMode, + }) + + } + + async #talentRoll(rollMode) { + const owner = this.parent.parent + let roll1 = new Roll("3d20", owner.getRollData()); let evaluated1 = (await roll1.evaluate()) diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index eb1cfc8c..7ec909d5 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -223,14 +223,10 @@ export class Character extends Actor { getRollData() { const data = super.getRollData(); + this.prepareDerivedData() if (this.type !== 'character' && this.type !== 'creature') return; - if (data.attribute) { - for (let [k, v] of Object.entries(data.attribute)) { - data[k] = foundry.utils.deepClone(v); - } - } // move sonderfertigkeiten into data, if it isn't in data the actor doesn't have that sonderfertigkeit diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index d60bc6d1..92992f52 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -29,6 +29,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { resizable: true, }, actions: { + rollCombatSkill: CharacterSheet.#rollCombatSkill, rollSkill: CharacterSheet.#rollSkill, roll: CharacterSheet.#dieRoll, editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, @@ -77,14 +78,31 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } } + + /** + * + * @param {PointerEvent} event + */ static #rollSkill(event) { - const {id} = event.srcElement.dataset + const {id} = event.target.dataset const skill = this.document.items.get(id) if (skill?.system?.roll) { skill.system.roll("publicroll") } } + /** + * + * @param {PointerEvent} event + */ + static #rollCombatSkill(event) { + const {id} = event.target.dataset + const skill = this.document.items.get(id) + if (skill?.system?.roll) { + skill.system.roll("publicroll", event.shiftKey ? "PARRY" : "ATTACK") + } + } + static #dieRoll(event) { event.preventDefault() const dataset = event.currentTarget.dataset diff --git a/src/templates/ui/partial-rollable-weaponskill-button.hbs b/src/templates/ui/partial-rollable-weaponskill-button.hbs index e1d68f60..552ea31f 100644 --- a/src/templates/ui/partial-rollable-weaponskill-button.hbs +++ b/src/templates/ui/partial-rollable-weaponskill-button.hbs @@ -5,7 +5,8 @@
{{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - {{#if this.taw}} + {{#if this.taw}} {{this.taw}} {{else}} {{#if this.liturgiekenntnis}} -- 2.43.0 From 2dd920a094a510941dd972a45b0b67cee6a31919 Mon Sep 17 00:00:00 2001 From: macniel Date: Fri, 17 Oct 2025 23:28:02 +0200 Subject: [PATCH 26/40] shortens display of language skills --- src/module/sheets/character/skills.mjs | 2 +- src/style/atoms/_typography.scss | 17 +++++++- src/style/molecules/_lists.scss | 18 -------- src/style/molecules/_rollable.scss | 1 - src/style/organisms/_character-sheet.scss | 8 ++-- .../organisms/character-tabs/_skills.scss | 41 +++++++++++++++++++ src/templates/actor/character/tab-skills.hbs | 2 + 7 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 src/style/organisms/character-tabs/_skills.scss diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs index 58e14280..937633ba 100644 --- a/src/module/sheets/character/skills.mjs +++ b/src/module/sheets/character/skills.mjs @@ -38,7 +38,7 @@ export default { const obj = { type: "talent", gruppe: talentGruppe, - name: item.name, + name: item.name.replace(/Sprachen kennen/g, "Sprache:").replace(/Lesen\/Schreiben/g, "Schrift: "), taw: "" + item.system.taw, tawPath: `system.items.${index}.taw`, werte, diff --git a/src/style/atoms/_typography.scss b/src/style/atoms/_typography.scss index 109ead76..aa08a435 100644 --- a/src/style/atoms/_typography.scss +++ b/src/style/atoms/_typography.scss @@ -3,9 +3,24 @@ --font-body: Gentium, sans-serif; label, - .sheet-tabs.tabs a { + .sheet-tabs.tabs a, + h2 { font-family: Gentium, sans-serif; font-weight: bold; + font-size: 12pt; + } + + h2 { + height: 32px; + line-height: 32px; + padding: 0; + margin: 0; + } + + ul { + li { + margin-bottom: 16px; + } } input, diff --git a/src/style/molecules/_lists.scss b/src/style/molecules/_lists.scss index 29c868e6..790b51ca 100644 --- a/src/style/molecules/_lists.scss +++ b/src/style/molecules/_lists.scss @@ -1,22 +1,4 @@ .dsa41.sheet.actor.character { - .tab.skills { - columns: 2; - column-gap: 20px; - - .talent-group { - break-inside: avoid-column; - display: unset; - height: unset; - gap: unset; - padding: unset; - } - - ul { - list-style-type: none; - padding-left: 0; - } - - } } diff --git a/src/style/molecules/_rollable.scss b/src/style/molecules/_rollable.scss index fbeda860..a1c7cb5b 100644 --- a/src/style/molecules/_rollable.scss +++ b/src/style/molecules/_rollable.scss @@ -148,7 +148,6 @@ $rollable_colours_font: ( height: 28px; left: -1px; top: -2px; - scale: 0.8; img { position: absolute; diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index 1240a2a9..a18205f7 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -8,8 +8,7 @@ @use "./character-tabs/combat"; @use "./character-tabs/spells"; @use "./character-tabs/liturgies"; - - +@use "./character-tabs/skills"; .application.sheet.dsa41.actor.character { @@ -87,11 +86,14 @@ @include inventory.tab; } - .tab.combat.active { @include combat.tab; } + .tab.skills.active { + @include skills.tab; + } + .tab.spells { @include spells.tab; } diff --git a/src/style/organisms/character-tabs/_skills.scss b/src/style/organisms/character-tabs/_skills.scss new file mode 100644 index 00000000..ae8552b8 --- /dev/null +++ b/src/style/organisms/character-tabs/_skills.scss @@ -0,0 +1,41 @@ +@mixin tab { + + container: thisTab / inline-size; + + .collapsible { + + columns: 2; + column-gap: 20px; + padding: 8px; + display: block; + height: unset; + + .talent-group { + break-inside: avoid-column; + display: unset; + height: unset; + gap: unset; + padding: unset; + + } + + ul { + list-style-type: none; + padding-left: 0; + } + } + + + @container thisTab (inline-size <= 740px ) { + .collapsible { + columns: 1; + } + } + + @container thisTab (inline-size > 740px ) { + .collapsible { + columns: 2; + } + } + +} \ No newline at end of file diff --git a/src/templates/actor/character/tab-skills.hbs b/src/templates/actor/character/tab-skills.hbs index 526254f3..26c619c2 100644 --- a/src/templates/actor/character/tab-skills.hbs +++ b/src/templates/actor/character/tab-skills.hbs @@ -1,6 +1,7 @@
+

Kampftalente

    @@ -82,4 +83,5 @@ {{/each}}
+
\ No newline at end of file -- 2.43.0 From b13fc297917cb2a065b27797c1fb9d74050e385a Mon Sep 17 00:00:00 2001 From: yuna Date: Sat, 18 Oct 2025 11:47:04 +0200 Subject: [PATCH 27/40] fixes display of liturgies and preliminary styling --- src/module/sheets/character/liturgies.mjs | 16 ++++++---------- src/module/sheets/character/skills.mjs | 5 ++--- src/style/molecules/_liturgy-banner.scss | 6 +++--- .../organisms/character-tabs/_liturgies.scss | 5 +++++ src/templates/actor/character/tab-liturgies.hbs | 6 ++---- 5 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/module/sheets/character/liturgies.mjs b/src/module/sheets/character/liturgies.mjs index 062d5966..f31add4e 100644 --- a/src/module/sheets/character/liturgies.mjs +++ b/src/module/sheets/character/liturgies.mjs @@ -14,16 +14,13 @@ export default { context.liturgies = []; context.blessings = []; - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Blessing") { - context.blessings.push({ - deity: item.system.gottheit, - value: item.system.wert - }) - } + actorData.itemTypes.Blessing.forEach((item, index) => { + context.blessings.push({ + deity: item.system.gottheit, + value: item.system.wert + }) }) - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Liturgy") { + actorData.itemTypes.Liturgy.forEach((item, index) => { context.blessings.forEach(({deity, value}) => { let insertObject = context.liturgies.find(p => p.deity === deity); @@ -77,7 +74,6 @@ export default { } }) - } }) diff --git a/src/module/sheets/character/skills.mjs b/src/module/sheets/character/skills.mjs index 937633ba..9cf1d9d5 100644 --- a/src/module/sheets/character/skills.mjs +++ b/src/module/sheets/character/skills.mjs @@ -22,8 +22,7 @@ export default { context.skills = {}; context.flatSkills = []; - actorData.items.forEach((item, index) => { - if (item.type === "Skill") { + actorData.itemTypes.Skill.forEach((item, index) => { const talentGruppe = item.system.gruppe; const eigenschaften = Object.values(item.system.probe); @@ -68,7 +67,7 @@ export default { context.skills[talentGruppe].push(obj); context.flatSkills.push(obj); } - } + ) return context diff --git a/src/style/molecules/_liturgy-banner.scss b/src/style/molecules/_liturgy-banner.scss index c2ce6d46..c79f60cb 100644 --- a/src/style/molecules/_liturgy-banner.scss +++ b/src/style/molecules/_liturgy-banner.scss @@ -96,14 +96,14 @@ $deity_colours_tint: ( &::before { position: absolute; content: ''; - background-image: url("../../assets/velvet_strip.png"); + background-image: url("/systems/DSA_4-1/assets/velvet_strip.png"); background-repeat: repeat-y; background-size: cover; width: 86px; height: 100%; top: 45px; - left: 12px; + left: 28px; } &::after { /* for tinting the texture */ @@ -113,7 +113,7 @@ $deity_colours_tint: ( height: 100%; top: 45px; - left: 12px; + left: 28px; } } } diff --git a/src/style/organisms/character-tabs/_liturgies.scss b/src/style/organisms/character-tabs/_liturgies.scss index d780da26..197464df 100644 --- a/src/style/organisms/character-tabs/_liturgies.scss +++ b/src/style/organisms/character-tabs/_liturgies.scss @@ -1,5 +1,10 @@ @mixin tab { + + > div { + height: unset; + } + table { border-top: unset; border-bottom: unset; diff --git a/src/templates/actor/character/tab-liturgies.hbs b/src/templates/actor/character/tab-liturgies.hbs index 886f41bd..fdb869f5 100644 --- a/src/templates/actor/character/tab-liturgies.hbs +++ b/src/templates/actor/character/tab-liturgies.hbs @@ -1,7 +1,7 @@
- +
@@ -23,7 +23,6 @@ - {{#if this.countO}} @@ -43,7 +42,6 @@ {{/each}} - {{/if}} {{#if this.countI}} @@ -197,6 +195,6 @@ {{/each}} - +
\ No newline at end of file -- 2.43.0 From 32503a03c11654c2cb7a7a71485e7a9c288ef75f Mon Sep 17 00:00:00 2001 From: yuna Date: Sat, 18 Oct 2025 11:55:37 +0200 Subject: [PATCH 28/40] restores inventory template --- src/main.mjs | 1 - src/module/sheets/character/equipment.mjs | 5 +- .../actor/character/tab-equipment.hbs | 61 ++++++++++++++++++- 3 files changed, 61 insertions(+), 6 deletions(-) diff --git a/src/main.mjs b/src/main.mjs index ec48819c..1e3261c6 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -36,7 +36,6 @@ async function preloadHandlebarsTemplates() { 'systems/DSA_4-1/templates/ui/partial-sf-button.hbs', 'systems/DSA_4-1/templates/ui/partial-action-button.hbs', 'systems/DSA_4-1/templates/ui/partial-equipment-button.hbs', - 'systems/DSA_4-1/templates/ui/partial-equipment-group-button.hbs', 'systems/DSA_4-1/templates/ui/partial-array-editor.hbs', 'systems/DSA_4-1/templates/dialog/modify-liturgy.hbs' ]); diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 4739a516..8406eba8 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -30,8 +30,7 @@ export default { context.equipments = [] context.carryingweight = 0 - Object.values(actorData.items).forEach((item, index) => { - if (item.type === "Equipment") { + actorData.itemTypes.Equipment.forEach((item, index) => { // worn items are halved weight @@ -50,7 +49,7 @@ export default { worn: isWorn(item._id, object) }) context.carryingweight += item.system.quantity * effectiveWeight; - } + }) context.maxcarryingcapacity = actorData.system.attribute.kk.aktuell context.carryingpercentage = Math.min((context.carryingweight / context.maxcarryingcapacity) * 100, 100); diff --git a/src/templates/actor/character/tab-equipment.hbs b/src/templates/actor/character/tab-equipment.hbs index 213deb5c..99b1c335 100644 --- a/src/templates/actor/character/tab-equipment.hbs +++ b/src/templates/actor/character/tab-equipment.hbs @@ -1,5 +1,62 @@ -
- To be done +
+
+ +
+ +
+
+ + +
+

Inventar

+ + {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}} + +
+ +
+

Ausrüstung

+ {{!-- Set Tab Navigation --}} + + {{!-- Set Body --}} +
+ {{#each this.sets}} +
+ +
+ + + + + {{#each this.slots}} +
+ {{/each}} + {{#if (eq ../actor.system.setEquipped @index)}} + + {{else}} + + {{/if}} + +
+
+ {{/each}} + +
+
+ +
\ No newline at end of file -- 2.43.0 From ee578e430e6e82f0ea0561ab4e7413798c7fda5d Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 10:31:15 +0200 Subject: [PATCH 29/40] restores equipment drag and drop while sacrificing paperdoll view --- src/main.mjs | 7 +- src/module/sheets/character/equipment.mjs | 65 ++---- src/module/sheets/characterSheet.mjs | 216 ++---------------- src/module/sheets/groupSheet.mjs | 1 - src/style/organisms/_character-sheet.scss | 2 +- .../organisms/character-tabs/_inventory.scss | 55 ++--- .../actor/character/tab-equipment.hbs | 48 ++-- src/templates/actor/character/tab-set.hbs | 29 +++ 8 files changed, 108 insertions(+), 315 deletions(-) create mode 100644 src/templates/actor/character/tab-set.hbs diff --git a/src/main.mjs b/src/main.mjs index 1e3261c6..d4b0b9d7 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -198,13 +198,14 @@ Hooks.once("init", () => { }) Hooks.on('dropActorSheetData', (actor, sheet, data) => { - if (data.uuid) { + /*if (data.uuid) { if (actor.type === "character") { - return CharacterSheet.onDroppedData(actor, sheet, data); + return true } else { return GroupSheet.onDroppedData(actor, sheet, data); } - } + }*/ + return true }) Hooks.once("ready", async function () { diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 8406eba8..ff08ad0b 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -35,7 +35,7 @@ export default { // worn items are halved weight let effectiveWeight = item.system.weight ?? 0 - if (isWorn(item._id, object)) { + if (isWorn(item._id, context.document)) { effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 } @@ -46,7 +46,7 @@ export default { name: item.name, icon: item.img ?? "", weight: item.system.weight, - worn: isWorn(item._id, object) + worn: isWorn(item._id, context.document) }) context.carryingweight += item.system.quantity * effectiveWeight; @@ -142,57 +142,20 @@ export default { return context }, - _onRender: (context, options, element) => { - const mapAllSets = () => { - const updateObject = {} - Array.from(context.document.system.heldenausruestung).forEach((equipmentSet, index) => { - updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; - updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; - updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; - updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; - updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; - updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; - updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; - updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; - updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; - updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; - updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; - updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; + _onRender: (context, options, thisObject) => { - }) - return updateObject; - } - - new foundry.applications.ux.ContextMenu(element, '.equipped', [ - { - name: "Gegenstand vom Set entfernen", - callback: (event) => { - const {setId, target, actor} = event[0].dataset - - const updateObject = mapAllSets() - updateObject[`system.heldenausruestung.${setId}.${target}`] = null; - - object.update(updateObject); - }, - condition: () => true + new foundry.applications.ux.DragDrop.implementation({ + dragSelector: ".inventory-table .equipment", + dropSelector: ".inventory-table", + permissions: { + dragstart: thisObject._canDragStart.bind(thisObject), + drop: thisObject._canDragDrop.bind(thisObject) + }, + callbacks: { + dragstart: thisObject._onDragStart.bind(thisObject), + drop: thisObject._onDrop.bind(thisObject) } - ], { - jQuery: false - }); - - new foundry.applications.ux.ContextMenu(element, '.equipment', [ - { - name: "Aus dem Inventar entfernen", - icon: '', - callback: (event) => { - // TODO find id on heldenausruestung to remove the worn items as well - object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); + }).bind(thisObject.element); }, _getTabConfig: (group) => { group.tabs.push({id: "equipment", group: "sheet", label: "Ausrüstung"}) diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 92992f52..4e832082 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -369,212 +369,32 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { Attributes._onRender(context, options, this.element) Combat._onRender(context, options, this.element) Effects._onRender(context, options, this.element) - Equipment._onRender(context, options, this.element) + Equipment._onRender(context, options, this) Liturgies._onRender(context, options, this.element) Skills._onRender(context, options, this.element) Spells._onRender(context, options, this.element) } - /* showAdjustAttributeDialog(attributeName, attributeField, previousValue) { - const thisActor = this; - const myContent = ` - Value: - - `; + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + const actor = this.actor; + const allowed = Hooks.call("dropActorSheetData", actor, this, data); + if (allowed === false) return; - function updateAttribute(html) { - const value = html.find("input#attributeValue").val(); - const attribute = {} - attribute[attributeField.toLowerCase()] = { - aktuell: value - } - thisActor.object.update({system: {attribute}}) + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + const document = await documentClass.fromDropData(data); + await this._onDropDocument(event, document); + + // No duplication by moving items from one actor to another + if (document.parent) { + document.parent.items.get(document._id).delete() } - - new Dialog({ - title: `${attributeName} ändern auf`, - content: myContent, - buttons: { - button1: { - label: "Ändern", - callback: (html) => { - updateAttribute(html) - }, - icon: `` - } - } - }).render(true); - - }*/ - - /* - activateListeners(html) { - super.activateListeners(html); - - const tabs = new foundry.applications.ux.Tabs({ - navSelector: ".paperdoll-tabs.tabs", - contentSelector: ".sheet-body.paperdoll-sets", - initial: "set" + (this.object.system.setEquipped + 1) - }); - tabs.bind(html[0]); - - html.on('click', '.attribute.rollable', (evt) => { - this._onAttributeRoll(evt); - }); - - html.on('click', '[data-operation="switchSet"]', (evt) => { - const {id} = evt.currentTarget.dataset; - console.log(id); - this.object.update({"system.setEquipped": id}) - }) - - html.on('click', '[data-operation="removeEffect"]', (evt) => { - const {actorId, effectId} = evt.currentTarget.dataset; - if (game.user.isGM) { - this.object.items.get(effectId).delete(); - } - }) - - html.on('click', '.talent.rollable', (evt) => { - this._onTalentRoll(evt); - }); - - html.on('click', '.sidebar-element.rollable', (evt) => { - this._onRoll(evt); - }); - - // TODO: merge into click.clickable handler - html.on('click', '.talent .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.advantage .name', (evt) => { - this.openEmbeddedDocument(evt.target.dataset.id); - evt.stopPropagation(); - }) - - // TODO: merge into click.clickable handler - html.on('click', '.equipment', (evt) => { - this.openEmbeddedDocument(evt.target.parentElement.dataset.id); - evt.stopPropagation(); - }) - - html.on('click', '.clickable', async (evt) => { - const {id, operation} = evt.currentTarget.dataset; - if (operation === "openActorSheet") { - this.openEmbeddedDocument(id); - evt.stopPropagation(); - } - }) - - new foundry.applications.ux.ContextMenu(html[0], '.talent.rollable', [ - { - name: "Entfernen", - icon: '', - callback: (event) => { - this.object.deleteEmbeddedDocuments('Item', [event[0].dataset.id]) - }, - condition: () => true - } - ], { - jQuery: false - }); - - - new foundry.applications.ux.ContextMenu(html[0], '.attribute.rollable', [ - { - name: "Anpassen", - icon: '', - callback: (event) => { - this.showAdjustAttributeDialog(event[0].dataset.name, event[0].dataset.label, event[0].dataset.value) - }, - condition: () => true - } - ], { - jQuery: false - }); - - let handler = evt => { - const talentId = evt.target.dataset.id - evt.dataTransfer.setData("application/json", JSON.stringify({ - talentId - })); - this._onDragStart(evt) - } - - // 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); - }); - - html.on('click', '[data-operation="addWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '[data-operation="reduceWounds"]', async (evt) => { - const {value} = evt.currentTarget.dataset - this.object.update({"system.wunden.aktuell": value}) - }) - - html.on('click', '.liturgy.rollable', async (evt) => { - - evt.stopPropagation(); - - const {id, rank, lkp, deity} = evt.currentTarget.dataset; - const document = await this.object.items.get(id) - - const data = {}; - - data.rank = rank; - data.lkp = lkp; - data.deity = deity; - data.variations = []; - const ranks = LiturgyData.ranks - ranks.forEach(rank => { - if (document.system.auswirkung[rank]) { - data.variations.push({ - rank, - effect: document.system.auswirkung[rank] - }) - } - }) - data.mods = []; - - const htmlContent = await renderTemplate('systems/DSA_4-1/templates/dialog/modify-liturgy.hbs', data); - - const dialogData = { - title: document.name, - content: htmlContent, - data: {}, - buttons: { - submit: { - label: "Wirken", - icon: '', - callback: (html) => { - }, - }, - }, - } - dialogData.render = new ModifyLiturgy(data).handleRender - - const dialog = new Dialog(dialogData, { - classes: ['dsa41', 'dialog', 'liturgy'], - height: 480 - }) - - dialog.render(true); - - return false; - }) - - } - */ + } + } export default CharacterSheet diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index b3ed1427..74fe6912 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -311,7 +311,6 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { if (document.parent) { document.parent.items.get(document._id).delete() } - await this._onDropDocument(event, document); } } diff --git a/src/style/organisms/_character-sheet.scss b/src/style/organisms/_character-sheet.scss index a18205f7..f04ae439 100644 --- a/src/style/organisms/_character-sheet.scss +++ b/src/style/organisms/_character-sheet.scss @@ -82,7 +82,7 @@ @include attributes.tab; } - .inventory.active { + .tab.equipment.active { @include inventory.tab; } diff --git a/src/style/organisms/character-tabs/_inventory.scss b/src/style/organisms/character-tabs/_inventory.scss index 94846cef..de57c16e 100644 --- a/src/style/organisms/character-tabs/_inventory.scss +++ b/src/style/organisms/character-tabs/_inventory.scss @@ -1,41 +1,44 @@ @mixin tab { - display: grid; - grid-template-columns: 1fr 320px; - grid-template-rows: 74px 1fr; - gap: 10px; - height: 100%; - grid-template-areas: + + & > div { + display: grid; + grid-template-columns: 1fr 320px; + grid-template-rows: 74px 1fr; + gap: 10px; + height: 100%; + grid-template-areas: "capacity capacity" "inventory equipment"; - .capacity { + .capacity { - grid-area: capacity; + grid-area: capacity; - .resource { + .resource { - position: relative; - border: 1px inset #ccc; - background-color: rgba(0, 0, 0, 0.2); - height: 8px; + position: relative; + border: 1px inset #ccc; + background-color: rgba(0, 0, 0, 0.2); + height: 8px; + + span.fill { + position: absolute; + left: 0; + top: 0; + bottom: 0; + background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); + } - span.fill { - position: absolute; - left: 0; - top: 0; - bottom: 0; - background: linear-gradient(to bottom, #0bad29 0%, #11f128 50%, #0cde24 51%, #6ff77b 100%); } - } - } - .inventory { - grid-area: inventory; + .inventory { + grid-area: inventory; - .equipment:hover { - .item-name { - text-shadow: 0 0 10px rgb(255 0 0); + .equipment:hover { + .item-name { + text-shadow: 0 0 10px rgb(255 0 0); + } } } } diff --git a/src/templates/actor/character/tab-equipment.hbs b/src/templates/actor/character/tab-equipment.hbs index 99b1c335..8b6a83e4 100644 --- a/src/templates/actor/character/tab-equipment.hbs +++ b/src/templates/actor/character/tab-equipment.hbs @@ -16,47 +16,25 @@ {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" equipments}}
- +
\ No newline at end of file diff --git a/src/templates/actor/character/tab-set.hbs b/src/templates/actor/character/tab-set.hbs new file mode 100644 index 00000000..43b5bb2c --- /dev/null +++ b/src/templates/actor/character/tab-set.hbs @@ -0,0 +1,29 @@ +
+ + +
+ + + + + {{#each this.slots}} +
+ {{/each}} + {{#if (eq ../actor.system.setEquipped @index)}} + + {{else}} + + {{/if}} + +
+ +
\ No newline at end of file -- 2.43.0 From e118e8ba92bbbbd35b0b2411dfea41fddb4d7ee6 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 10:43:49 +0200 Subject: [PATCH 30/40] restores opening of linked documents in their respective sheet --- src/module/sheets/characterSheet.mjs | 6 +++-- src/module/sheets/groupSheet.mjs | 15 +++++++----- .../actor/character/tab-liturgies.hbs | 18 +++++++-------- src/templates/actor/character/tab-spells.hbs | 2 +- src/templates/actor/group/tab-inventory.hbs | 23 +------------------ src/templates/actor/group/tab-members.hbs | 5 ++-- src/templates/ui/partial-equipment-button.hbs | 2 +- 7 files changed, 27 insertions(+), 44 deletions(-) diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 4e832082..24652248 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -118,8 +118,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } } - static #openEmbeddedDocument(documentId) { - this.object.items.get(documentId).sheet.render(true) + static #openEmbeddedDocument(event) { + const dataset = event.target.parentElement.dataset + const id = dataset.itemId ?? dataset.id + this.document.items.get(id).sheet.render(true) } /** diff --git a/src/module/sheets/groupSheet.mjs b/src/module/sheets/groupSheet.mjs index 74fe6912..1f64a1e5 100644 --- a/src/module/sheets/groupSheet.mjs +++ b/src/module/sheets/groupSheet.mjs @@ -79,14 +79,17 @@ export class GroupSheet extends HandlebarsApplicationMixin(ActorSheetV2) { return s } - static async #openEmbeddedDocument(evt) { - const {documentId} = evt.srcElement.dataset - this.document.items.get(documentId).sheet.render(true) + + static #openEmbeddedDocument(event) { + const dataset = event.target.parentElement.dataset + const id = dataset.itemId ?? dataset.id + this.document.items.get(id).sheet.render(true) } - static async #openActorDocument(evt) { - const {id} = evt.srcElement.dataset - evt.stopPropagation() + + static async #openActorDocument(event) { + const dataset = event.target.parentElement.dataset + const id = dataset.itemId ?? dataset.id game.actors.get(id).sheet.render(true) } diff --git a/src/templates/actor/character/tab-liturgies.hbs b/src/templates/actor/character/tab-liturgies.hbs index fdb869f5..6bc342d8 100644 --- a/src/templates/actor/character/tab-liturgies.hbs +++ b/src/templates/actor/character/tab-liturgies.hbs @@ -37,7 +37,7 @@ data-lkp="{{../lkp}}" data-deity="{{this.deity}}"> {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - + {{this.name}} @@ -56,7 +56,7 @@ data-lkp="{{../lkp}}" data-deity="{{this.deity}}"> {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - + {{this.name}} @@ -77,7 +77,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}} @@ -96,7 +96,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}} @@ -115,7 +115,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}}{{/if}} {{#if this.countV}} @@ -133,7 +133,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}} @@ -152,7 +152,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}}{{#if this.countVII}} @@ -170,7 +170,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}}{{#if this.countVIII}} @@ -188,7 +188,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} {{this.name}} + data-action="openActorSheet">{{this.name}} {{/each}} {{/if}} diff --git a/src/templates/actor/character/tab-spells.hbs b/src/templates/actor/character/tab-spells.hbs index ed6cda06..b8ea3278 100644 --- a/src/templates/actor/character/tab-spells.hbs +++ b/src/templates/actor/character/tab-spells.hbs @@ -32,7 +32,7 @@ {{> 'systems/DSA_4-1/templates/ui/partial-die.hbs' }} - + {{this.name}} {{this.eigenschaft1}} {{this.eigenschaft2}} diff --git a/src/templates/actor/group/tab-inventory.hbs b/src/templates/actor/group/tab-inventory.hbs index d238d631..e3a6eae2 100644 --- a/src/templates/actor/group/tab-inventory.hbs +++ b/src/templates/actor/group/tab-inventory.hbs @@ -2,27 +2,6 @@ data-tab="{{tabs.inventory.id}}" data-group="{{tabs.inventory.group}}"> - - - - - - + {{> "systems/DSA_4-1/templates/ui/partial-equipment-button.hbs" inventoryItems}} - - - - - {{#each inventoryItems}} - - - - - - - {{/each}} - -
AnzahlGewicht
{{this.name}}{{this.quantity}}{{this.weight}}
- -
diff --git a/src/templates/actor/group/tab-members.hbs b/src/templates/actor/group/tab-members.hbs index 60da70cd..a89491c3 100644 --- a/src/templates/actor/group/tab-members.hbs +++ b/src/templates/actor/group/tab-members.hbs @@ -6,7 +6,7 @@ {{#each this.characters}} {{#if this.isVisible}}
-
+
{{this.name}} {{this.name}} @@ -24,8 +24,7 @@ {{#each this.fields.head}}
-
+
{{this.name}} {{this.name}} diff --git a/src/templates/ui/partial-equipment-button.hbs b/src/templates/ui/partial-equipment-button.hbs index 68121064..63c98791 100644 --- a/src/templates/ui/partial-equipment-button.hbs +++ b/src/templates/ui/partial-equipment-button.hbs @@ -11,7 +11,7 @@ {{#each this}} - + {{this.name}} {{this.quantity}} -- 2.43.0 From 49896e0966e86cfe33d8f36bf10c48296a652678 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 12:24:43 +0200 Subject: [PATCH 31/40] repairs visuals of combat tab --- .../organisms/character-tabs/_combat.scss | 33 +++++++++++++++++-- src/templates/actor/character/tab-combat.hbs | 12 ++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/style/organisms/character-tabs/_combat.scss b/src/style/organisms/character-tabs/_combat.scss index adad410d..77878569 100644 --- a/src/style/organisms/character-tabs/_combat.scss +++ b/src/style/organisms/character-tabs/_combat.scss @@ -5,16 +5,39 @@ grid-template-columns: 1fr 320px; grid-template-rows: 32px 32px 1fr; grid-template-areas: "res res" "wounds wounds" "actions actions"; - gap: 10px; + padding: 8px; + gap: 8px; - .tab-resources { + div.combatline { grid-area: res; + display: flex; + flex-direction: row; + justify-self: center; + height: unset; + padding: 0; + gap: 0 8px; + + + input { + width: 48px; + height: 32px; + } + + span, label { + line-height: 32px; + height: 32px; + vertical-align: middle; + } + } .wounds { position: relative; height: 24px; display: flex; + flex-direction: unset; + gap: unset; + padding: unset; margin-bottom: 8px; padding-left: 130px; grid-area: wounds; @@ -69,8 +92,14 @@ .actions { grid-area: actions; + padding: 0; + + .grid-of-actions { + display: unset; + } } + &.zones { grid-template-areas: "res res" "wounds wounds" "actions paperdoll"; diff --git a/src/templates/actor/character/tab-combat.hbs b/src/templates/actor/character/tab-combat.hbs index ab59267e..6e86390f 100644 --- a/src/templates/actor/character/tab-combat.hbs +++ b/src/templates/actor/character/tab-combat.hbs @@ -2,7 +2,7 @@ data-tab="{{tabs.combat.id}}" data-group="{{tabs.combat.group}}"> -
+
@@ -12,16 +12,16 @@
- + von - +
{{#if ausdauer}}
- + von - +
{{/if}} {{#if (not zonenruestung)}} @@ -54,9 +54,11 @@

Aktionen im Kampf

+
{{#each this.actions}} {{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}} {{/each}} +
{{#if (or trefferzonen zonenruestung)}} -- 2.43.0 From 523cbb9f623b95222c13c7247ae1b229cba0d972 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 12:24:46 +0200 Subject: [PATCH 32/40] repairs visuals of combat tab --- src/module/documents/character.mjs | 43 +++++++ src/module/sheets/actions/action-manager.mjs | 41 +++++-- src/module/sheets/character/equipment.mjs | 118 ++++++++++++++++--- src/module/sheets/characterSheet.mjs | 43 +++---- 4 files changed, 199 insertions(+), 46 deletions(-) diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index 7ec909d5..42261274 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -1,6 +1,7 @@ import {importCharacter} from "../xml-import/xml-import.mjs"; import {LiturgyData} from "../data/miracle/liturgydata.mjs"; import {Zonenruestung, Zonenwunde} from "../data/Trefferzone.js"; +import {PlayerCharacterDataModel} from "../data/character.mjs"; export class Character extends Actor { @@ -241,6 +242,48 @@ export class Character extends Actor { return data; } + + findEquipmentOnSlot(slot, setNumber) { + return this.items.get(this.system.heldenausruestung[setNumber ?? this.system.setEquipped]?.[slot]) + } + + getEquipmentSetUpdateObject() { + const updateObject = {} + Array.from(this.system.heldenausruestung).forEach((equipmentSet, index) => { + updateObject[`system.heldenausruestung.${index}.links`] = equipmentSet.links; + updateObject[`system.heldenausruestung.${index}.rechts`] = equipmentSet.rechts; + updateObject[`system.heldenausruestung.${index}.brust`] = equipmentSet.brust; + updateObject[`system.heldenausruestung.${index}.bauch`] = equipmentSet.bauch; + updateObject[`system.heldenausruestung.${index}.ruecken`] = equipmentSet.ruecken; + updateObject[`system.heldenausruestung.${index}.kopf`] = equipmentSet.kopf; + updateObject[`system.heldenausruestung.${index}.fernkampf`] = equipmentSet.fernkampf; + updateObject[`system.heldenausruestung.${index}.munition`] = equipmentSet.munition; + updateObject[`system.heldenausruestung.${index}.armlinks`] = equipmentSet.armlinks; + updateObject[`system.heldenausruestung.${index}.armrechts`] = equipmentSet.armrechts; + updateObject[`system.heldenausruestung.${index}.beinlinks`] = equipmentSet.beinlinks; + updateObject[`system.heldenausruestung.${index}.beinrechts`] = equipmentSet.beinrechts; + + }) + return updateObject; + } + + + isWorn(itemId) { + + const slots = PlayerCharacterDataModel.getSlots() + const set = this.system.heldenausruestung[this.system.setEquipped] + if (set) { + for (const slot of slots) { + const equipmentSlotId = set[slot] + if (equipmentSlotId === itemId) { + return slot + } + } + } + + return false + } + /** * * @param amount diff --git a/src/module/sheets/actions/action-manager.mjs b/src/module/sheets/actions/action-manager.mjs index 2aa31643..3e1aee6e 100644 --- a/src/module/sheets/actions/action-manager.mjs +++ b/src/module/sheets/actions/action-manager.mjs @@ -68,21 +68,21 @@ export class ActionManager { type: ActionManager.ATTACK, cost: ActionManager.REGULAR, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatWaffeinHand() }, { name: "Schnellschuss", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatFernkampfWaffeinHand() }, { name: "Schnellschuss (Scharfschütze)", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Scharfschütze") + eval: () => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Scharfschütze") }, { name: "Abwehraktion", @@ -110,7 +110,14 @@ export class ActionManager { type: ActionManager.ATTACK, cost: ActionManager.REGULAR, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Finte") + eval: () => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Finte") + }, + { + name: "Wuchtschlag", + type: ActionManager.ATTACK, + cost: ActionManager.REGULAR, + source: ActionManager.DEFAULT, + eval: () => true }, { name: "Wuchtschlag", @@ -162,21 +169,21 @@ export class ActionManager { type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Schnellladen (Bogen)") + eval: () => this.#hatMunition() && this.#hatFernkampfWaffeinHand("Bogen") && this.#hatSonderfertigkeit("Schnellladen (Bogen)") }, { name: "Schnellladen (Armbrust)", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.SF, - eval: () => this.#hatSonderfertigkeit("Schnellladen (Armbrust)") + eval: () => this.#hatMunition() && this.#hatFernkampfWaffeinHand("Armbrust") && this.#hatSonderfertigkeit("Schnellladen (Armbrust)") }, { name: "Nachladen", type: ActionManager.INTERACTION, cost: ActionManager.CONTINUING, source: ActionManager.DEFAULT, - eval: () => true + eval: () => this.#hatMunition() }, { name: "Talenteinsatz", @@ -201,6 +208,26 @@ export class ActionManager { } ] + + #hatWaffeinHand() { + const item = this.actor.findEquipmentOnSlot("links") ?? this.actor.findEquipmentOnSlot("rechts") + console.log(item) + return item + } + + #hatMunition() { + const item = this.actor.findEquipmentOnSlot("munition") + const weapon = this.actor.findEquipmentOnSlot("fernkampf") + console.log(item?.system.quantity, weapon) + return item + } + + #hatFernkampfWaffeinHand(art) { + const item = this.actor.findEquipmentOnSlot("fernkampf") + console.log(item) + return item + } + #hatSonderfertigkeitBeginnendMit(name) { return this.actor.system.sonderfertigkeiten?.find(p => p.name.startsWith(name)) != null } diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index ff08ad0b..47957a1d 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -12,22 +12,6 @@ export default { context.name = context.derived.name ?? actorData.name context.effects = actorData.effects ?? [] - const isWorn = (itemId, object) => { - - const slots = PlayerCharacterDataModel.getSlots() - const set = object.system.heldenausruestung[object.system.setEquipped] - if (set) { - for (const slot of slots) { - const equipmentSlotId = set[slot] - if (equipmentSlotId === itemId) { - return slot - } - } - } - - return false - } - context.equipments = [] context.carryingweight = 0 actorData.itemTypes.Equipment.forEach((item, index) => { @@ -35,7 +19,7 @@ export default { // worn items are halved weight let effectiveWeight = item.system.weight ?? 0 - if (isWorn(item._id, context.document)) { + if (context.document.isWorn(item._id)) { effectiveWeight = item.system.weight ? item.system.weight / 2 : 0 } @@ -46,7 +30,7 @@ export default { name: item.name, icon: item.img ?? "", weight: item.system.weight, - worn: isWorn(item._id, context.document) + worn: context.document.isWorn(item._id) }) context.carryingweight += item.system.quantity * effectiveWeight; @@ -156,6 +140,104 @@ export default { drop: thisObject._onDrop.bind(thisObject) } }).bind(thisObject.element); + + new ContextMenu( + thisObject.element, + ".equipment", + [ + { + name: "Abrüsten", + icon: '', + callback: (target) => { + const {itemId} = target.dataset + const itemSlot = thisObject.document.isWorn(itemId) + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + delete updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.${itemSlot}`] + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const itemIsWorn = thisObject.document.isWorn(itemId) + return itemIsWorn + } + }, + { + name: "Ausrüsten (Munition)", + + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.munition`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + console.log(item.system.category) + return !thisObject.document.isWorn(itemId) + } + }, + { + name: "Ausrüsten", + callback: (target) => { + //thisObject.deleteEmbeddedDocuments('Item', [event.dataset.id]) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Rüstung") != -1 + } + }, + { + name: "Ausrüsten (Rechte Hand)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.rechts`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Nahkampfwaffe") != -1 + } + }, + { + name: "Ausrüsten (Linke Hand)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.links`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Nahkampfwaffe") != -1 + } + }, + { + name: "Ausrüsten (Fernkampf)", + callback: (target) => { + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + updateObject[`system.heldenausruestung.${thisObject.document.system.setEquipped}.fernkampf`] = target.dataset.itemId + thisObject.document.update(updateObject) + }, + condition: (target) => { + const {itemId} = target.dataset + const item = thisObject.document.items.get(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Fernkampfwaffe") != -1 + } + }, + { + name: "Aus dem Inventar entfernen", + icon: '', + callback: (target) => { + thisObject.deleteEmbeddedDocuments('Item', [target.dataset.id]) + }, + condition: (target) => { + const {itemId} = target.dataset + !thisObject.document.isWorn(itemId) + } + } + ], {jQuery: false}); }, _getTabConfig: (group) => { group.tabs.push({id: "equipment", group: "sheet", label: "Ausrüstung"}) diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 24652248..a8ff97d8 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -118,6 +118,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } } + /** + * + * @param {MouseEvent} event + */ static #openEmbeddedDocument(event) { const dataset = event.target.parentElement.dataset const id = dataset.itemId ?? dataset.id @@ -156,9 +160,6 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { switch (partId) { case "form": - const findEquipmentOnSlot = (slot, setNumber, object) => { - return object.items.get(object.system.heldenausruestung[setNumber]?.[slot]) - } const actorData = context.document context.system = actorData.system @@ -212,9 +213,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.aupcurrent = actorData.system.aup.aktuell ?? 0 - const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) - const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) - const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) + const fernkampf = actorData.findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData) + const links = actorData.findEquipmentOnSlot("links", actorData.system.setEquipped, actorData) + const rechts = actorData.findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData) context.attacks = []; if (fernkampf) { @@ -224,8 +225,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.attacks.push({ name: obj.name, using: fernkampf.name, - atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`, - at: `${object.system.fk.aktuell + obj.system.at}`, + atroll: `1d20cs<${this.document.system.fk.aktuell + obj.system.at}`, + at: `${this.document.system.fk.aktuell + obj.system.at}`, tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod tp: `${fernkampf.system.rangedAttackDamage}`, iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`, @@ -246,9 +247,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.attacks.push({ name: obj.name, using: links.name, - atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M + atroll: `1d20cs<${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, - paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M + paroll: `1d20cs<${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod tp: `${links.system.meleeAttackDamage}`, @@ -270,9 +271,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { context.attacks.push({ name: obj.name, using: rechts.name, - atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M + atroll: `1d20cs<${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, - paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M + paroll: `1d20cs<${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod tp: `${rechts.system.meleeAttackDamage}`, @@ -335,31 +336,31 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { break; case "meta": - await Meta._prepareContext(context, this.object) + await Meta._prepareContext(context, this.document) break case "social": - await Social._prepareContext(context, this.object) + await Social._prepareContext(context, this.document) break case "attributes": - await Attributes._prepareContext(context, this.object) + await Attributes._prepareContext(context, this.document) break case "combat": - await Combat._prepareContext(context, this.object) + await Combat._prepareContext(context, this.document) break case "equipment": - await Equipment._prepareContext(context, this.object) + await Equipment._prepareContext(context, this.document) break case "skills": - await Skills._prepareContext(context, this.object) + await Skills._prepareContext(context, this.document) break case "spells": - await Spells._prepareContext(context, this.object) + await Spells._prepareContext(context, this.document) break case "liturgies": - await Liturgies._prepareContext(context, this.object) + await Liturgies._prepareContext(context, this.document) break case "effects": - await Effects._prepareContext(context, this.object) + await Effects._prepareContext(context, this.document) break } return context -- 2.43.0 From eb88377f14e4f701fd951f103336fce257cc43ae Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 12:34:00 +0200 Subject: [PATCH 33/40] repairs visuals advantages and special abilities --- src/module/sheets/character/advsf.mjs | 45 +++++ src/module/sheets/character/attributes.mjs | 128 -------------- src/module/sheets/characterSheet.mjs | 14 +- src/style/atoms/_typography.scss | 2 +- .../organisms/character-tabs/_attributes.scss | 161 +++++++----------- src/templates/actor/character/tab-advsf.hbs | 22 +++ .../actor/character/tab-attributes.hbs | 161 ------------------ 7 files changed, 135 insertions(+), 398 deletions(-) create mode 100644 src/module/sheets/character/advsf.mjs delete mode 100644 src/module/sheets/character/attributes.mjs create mode 100644 src/templates/actor/character/tab-advsf.hbs delete mode 100644 src/templates/actor/character/tab-attributes.hbs diff --git a/src/module/sheets/character/advsf.mjs b/src/module/sheets/character/advsf.mjs new file mode 100644 index 00000000..7b77ed96 --- /dev/null +++ b/src/module/sheets/character/advsf.mjs @@ -0,0 +1,45 @@ +export default { + _prepareContext: async (context, options, object) => { + + const actorData = context.document + context.system = actorData.system + context.flags = actorData.flags + context.derived = context.document.system + context.originalName = actorData.name + context.name = context.derived.name ?? actorData.name + context.effects = actorData.effects ?? [] + context.advantages = [] + + actorData.itemTypes.Advantage.forEach((item) => { + context.advantages.push({ + id: item._id, + name: item.name, + value: item.system.value, + options: item.system.auswahl, + description: item.system.description, + isAdvantage: !item.system.nachteil, + isDisadvantage: item.system.nachteil, + isBadAttribute: item.system.schlechteEigenschaft + }) + } + ) + + context.specialAbilities = [] + actorData.itemTypes.SpecialAbility.forEach((item) => { + context.specialAbilities.push({ + id: item._id, + name: item.name, + }); + } + ); + + return context + }, + _onRender: (context, options) => { + + }, + _getTabConfig: (group) => { + group.tabs.push({id: "advsf", group: "sheet", label: "Vorteile"}) + }, + template: `systems/DSA_4-1/templates/actor/character/tab-advsf.hbs` +} \ No newline at end of file diff --git a/src/module/sheets/character/attributes.mjs b/src/module/sheets/character/attributes.mjs deleted file mode 100644 index b01333eb..00000000 --- a/src/module/sheets/character/attributes.mjs +++ /dev/null @@ -1,128 +0,0 @@ -export default { - _prepareContext: async (context, options, object) => { - - const actorData = context.document - context.system = actorData.system - context.flags = actorData.flags - context.derived = context.document.system - context.originalName = actorData.name - context.name = context.derived.name ?? actorData.name - context.effects = actorData.effects ?? [] - context.advantages = [] - - const getModsOfAttribute = async (keyPath, object) => { - let returnValue = []; - Array.from(object.appliedEffects).forEach( - (e) => - e.changes.filter(c => c.key === keyPath).forEach(change => { - returnValue.push({ - name: e.name, - value: change.value > 0 ? "+" + change.value : "" + change.value, - icon: e.icon, - }) - })) - return returnValue - } - - context.mods = { - "mu": await getModsOfAttribute('system.attribute.mu.mod', actorData), - "kl": await getModsOfAttribute('system.attribute.kl.mod', actorData), - "in": await getModsOfAttribute('system.attribute.in.mod', actorData), - "ch": await getModsOfAttribute('system.attribute.ch.mod', actorData), - "ff": await getModsOfAttribute('system.attribute.ff.mod', actorData), - "ge": await getModsOfAttribute('system.attribute.ge.mod', actorData), - "ko": await getModsOfAttribute('system.attribute.ko.mod', actorData), - "kk": await getModsOfAttribute('system.attribute.kk.mod', actorData), - "at": await getModsOfAttribute('system.at.mod', actorData), - "pa": await getModsOfAttribute('system.pa.mod', actorData), - "fk": await getModsOfAttribute('system.fk.mod', actorData), - } - - context.attributes = [ - { - eigenschaft: "mu", - name: "MU", - tooltip: "Mut", - wert: context.derived.attribute.mu.aktuell ?? 0, - }, - { - eigenschaft: "kl", - name: "KL", - tooltip: "Klugheit", - wert: context.derived.attribute.kl.aktuell ?? 0, - }, - { - eigenschaft: "in", - name: "IN", - tooltip: "Intuition", - wert: context.derived.attribute.in.aktuell ?? 0, - }, - { - eigenschaft: "ch", - name: "CH", - tooltip: "Charisma", - wert: context.derived.attribute.ch.aktuell ?? 0, - }, - { - eigenschaft: "ff", - name: "FF", - tooltip: "Fingerfertigkeit", - wert: context.derived.attribute.ff.aktuell ?? 0, - }, - { - eigenschaft: "ge", - name: "GE", - tooltip: "Geschicklichkeit", - wert: context.derived.attribute.ge.aktuell ?? 0, - }, - { - eigenschaft: "ko", - name: "KO", - tooltip: "Konstitution", - wert: context.derived.attribute.ko.aktuell ?? 0, - }, - { - eigenschaft: "kk", - name: "KK", - tooltip: "Körperkraft", - wert: context.derived.attribute.kk.aktuell ?? 0, - }, - ] - - Object.values(actorData.items).forEach((item) => { - if (item.type === "Advantage") { - context.advantages.push({ - id: item._id, - name: item.name, - value: item.system.value, - options: item.system.auswahl, - description: item.system.description, - isAdvantage: !item.system.nachteil, - isDisadvantage: item.system.nachteil, - isBadAttribute: item.system.schlechteEigenschaft - }) - } - } - ) - - context.specialAbilities = [] - Object.values(actorData.items).forEach((item) => { - if (item.type === "SpecialAbility") { - context.specialAbilities.push({ - id: item._id, - name: item.name, - }); - } - } - ); - - return context - }, - _onRender: (context, options) => { - - }, - _getTabConfig: (group) => { - group.tabs.push({id: "attributes", group: "sheet", label: "Eigenschaften"}) - }, - template: `systems/DSA_4-1/templates/actor/character/tab-attributes.hbs` -} \ No newline at end of file diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index a8ff97d8..73613520 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -1,4 +1,4 @@ -import Attributes from "./character/attributes.mjs" +import Advsf from "./character/advsf.mjs" import Combat from "./character/combat.mjs" import Effects from "./character/effects.mjs" import Equipment from "./character/equipment.mjs" @@ -55,8 +55,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { social: { template: Social.template }, - attributes: { - template: Attributes.template + advsf: { + template: Advsf.template }, combat: { template: Combat.template @@ -146,7 +146,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) Meta._getTabConfig(tabs, this); Social._getTabConfig(tabs, this); - Attributes._getTabConfig(tabs, this) + Advsf._getTabConfig(tabs, this) Combat._getTabConfig(tabs, this) Equipment._getTabConfig(tabs, this) Skills._getTabConfig(tabs, this) @@ -341,8 +341,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { case "social": await Social._prepareContext(context, this.document) break - case "attributes": - await Attributes._prepareContext(context, this.document) + case "advsf": + await Advsf._prepareContext(context, this.document) break case "combat": await Combat._prepareContext(context, this.document) @@ -369,7 +369,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { _onRender(context, options) { Meta._onRender(context, options, this.element) Social._onRender(context, options, this.element) - Attributes._onRender(context, options, this.element) + Advsf._onRender(context, options, this.element) Combat._onRender(context, options, this.element) Effects._onRender(context, options, this.element) Equipment._onRender(context, options, this) diff --git a/src/style/atoms/_typography.scss b/src/style/atoms/_typography.scss index aa08a435..e3cb3ab3 100644 --- a/src/style/atoms/_typography.scss +++ b/src/style/atoms/_typography.scss @@ -4,7 +4,7 @@ label, .sheet-tabs.tabs a, - h2 { + h2, h3 { font-family: Gentium, sans-serif; font-weight: bold; font-size: 12pt; diff --git a/src/style/organisms/character-tabs/_attributes.scss b/src/style/organisms/character-tabs/_attributes.scss index e9a959bb..f64cafe8 100644 --- a/src/style/organisms/character-tabs/_attributes.scss +++ b/src/style/organisms/character-tabs/_attributes.scss @@ -1,121 +1,80 @@ @mixin tab { height: 100%; - .attribute { - padding: 8px 0; - display: flex; - gap: 0 8px; + .advantages-and-specialabilities { - label { - width: 120px; - text-align: right; - vertical-align: middle; - line-height: 24px; - } + height: unset; + display: unset; + gap: 0; + padding: unset; - input { - max-width: 80px; - text-align: right; - } + .advantages, .special-abilities { + margin-bottom: 16px; - .mod { - color: grey; - text-shadow: 0 -1px 0 #ccc; - box-Shadow: 1px 1px 1px rgba(0, 0, 0, 0.5); - border-radius: 4px; - height: 24px; - width: 24px; - background: linear-gradient(0deg, rgba(24, 24, 24, 1) 0%, rgba(80, 80, 80, 1) 100%);; - display: inline-block; - text-align: center; - vertical-align: middle; - line-height: 24px; - margin-left: 4px; - } + ul { + list-style-type: none; + padding: 0; + margin: 0; + text-indent: 0; - } + li { + display: inline-block; + } - .attributes-overview { - - columns: 2; - gap: 0 16px; - - } - - .resource-overview { - - .attribute { - - } - - } - - .advantages, .special-abilities { - margin-bottom: 16px; - - ul { - list-style-type: none; - padding: 0; - margin: 0; - text-indent: 0; - - li { - display: inline-block; - } - - .advantage, .special-ability { - position: relative; - border: 1px solid gold; - box-shadow: 2px 2px 4px #000; - border-radius: 8px; - height: 24px; - color: gold; - text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); - display: inline-block; - padding: 0 8px; - margin-left: 0; - margin-bottom: 4px; - background-image: url("../../assets/velvet_button.png"); - background-repeat: repeat-y; - background-size: cover; - - span { + .advantage, .special-ability { position: relative; - z-index: 2; - line-height: 24px; - vertical-align: middle; - } - - &.special-ability { - &::after { - background: rgba(128, 0, 96, 0.5); - } - } - - &::after { - content: ""; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; + border: 1px solid gold; + box-shadow: 2px 2px 4px #000; border-radius: 8px; - background: rgba(0, 128, 0, 0.5); - } + height: 24px; + color: gold; + text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.2); + display: inline-block; + padding: 0 8px; + margin-left: 0; + margin-bottom: 4px; + background-image: url("../../assets/velvet_button.png"); + background-repeat: repeat-y; + background-size: cover; - & + .advantage, & + .special-ability { - margin-left: 8px; - } + span { + position: relative; + z-index: 2; + line-height: 24px; + vertical-align: middle; + } - &.disadvantage { - font-style: italic; + &.special-ability { + &::after { + background: rgba(128, 0, 96, 0.5); + } + } &::after { - background: rgba(128, 0, 0, 0.5); + content: ""; + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + border-radius: 8px; + background: rgba(0, 128, 0, 0.5); + } + + & + .advantage, & + .special-ability { + margin-left: 8px; + } + + &.disadvantage { + font-style: italic; + + &::after { + background: rgba(128, 0, 0, 0.5); + } } } } - } + } } } diff --git a/src/templates/actor/character/tab-advsf.hbs b/src/templates/actor/character/tab-advsf.hbs new file mode 100644 index 00000000..346a6ba4 --- /dev/null +++ b/src/templates/actor/character/tab-advsf.hbs @@ -0,0 +1,22 @@ +
+
+
+

Vor- und Nachteile

+
    + {{#each this.advantages}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • + {{/each}} +
+
+
+

Sonderfertigkeiten

+
    + {{#each this.specialAbilities}} +
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • + {{/each}} +
+
+
+
diff --git a/src/templates/actor/character/tab-attributes.hbs b/src/templates/actor/character/tab-attributes.hbs deleted file mode 100644 index 842f2973..00000000 --- a/src/templates/actor/character/tab-attributes.hbs +++ /dev/null @@ -1,161 +0,0 @@ -
- -
-
- - -
- {{#each this.mods.mu}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.kl}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.in}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ch}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ff}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ge}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.ko}} - {{this.value}} - {{/each}} -
- -
-
- - -
- {{#each this.mods.kk}} - {{this.value}} - {{/each}} -
- -
-
- - -
-
- - -
- {{#each this.mods.at}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.pa}} - {{this.value}} - {{/each}} -
-
-
- - -
- {{#each this.mods.fk}} - {{this.value}} - {{/each}} -
-
-
-
-
- - - -
- {{#if ausdauer}} -
- - - -
- {{/if}} - {{#if hasSpells}} -
- - - -
- {{/if}} - {{#if hasLiturgies}} -
- - - -
- {{/if}} -
-
-

Vor- und Nachteile

-
    - {{#each this.advantages}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-advantage-button.hbs" this}}
  • - {{/each}} -
-
-
-

Sonderfertigkeiten

-
    - {{#each this.specialAbilities}} -
  • {{> "systems/DSA_4-1/templates/ui/partial-sf-button.hbs" this}}
  • - {{/each}} -
-
- -
-- 2.43.0 From c9f9c920a6063fa5c12a76395255435def24b5a0 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 12:46:05 +0200 Subject: [PATCH 34/40] fixes Wounds for simplified system --- src/module/documents/character.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index 42261274..824f99d2 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -1,6 +1,6 @@ import {importCharacter} from "../xml-import/xml-import.mjs"; import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {Zonenruestung, Zonenwunde} from "../data/Trefferzone.js"; +import {Zonenruestung, Zonenwunde, Wunde} from "../data/Trefferzone.js"; import {PlayerCharacterDataModel} from "../data/character.mjs"; export class Character extends Actor { -- 2.43.0 From ad28cf48f383859022bcb80803a6e670e7ca749c Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 12:47:25 +0200 Subject: [PATCH 35/40] fixes Wounds display --- src/style/organisms/character-tabs/_combat.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/style/organisms/character-tabs/_combat.scss b/src/style/organisms/character-tabs/_combat.scss index 77878569..ee4e0aa3 100644 --- a/src/style/organisms/character-tabs/_combat.scss +++ b/src/style/organisms/character-tabs/_combat.scss @@ -50,7 +50,7 @@ width: 120px; bottom: 0; vertical-align: middle; - text-align: right; + text-align: left; height: 24px; display: inline-block; z-index: 2; -- 2.43.0 From 321ba7d3d6c61dc3ee602ebeacfc782e31c78433 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 18:11:52 +0200 Subject: [PATCH 36/40] restores drag and drop functionality for items onto character sheet --- src/module/data/character.mjs | 4 +- src/module/data/equipment.mjs | 19 ++- src/module/sheets/character/advsf.mjs | 12 +- src/module/sheets/character/equipment.mjs | 3 +- src/module/sheets/characterSheet.mjs | 18 ++- src/module/sheets/equipmentSheet.mjs | 111 ++++++++++++------ src/packs/_source/munition/balläster-m.json | 24 ++-- src/packs/_source/munition/eisenwalder-m.json | 24 ++-- src/packs/_source/munition/elfenbogen-m.json | 24 ++-- .../_source/munition/kompositbogen-m.json | 24 ++-- src/packs/_source/munition/kriegsbogen-m.json | 24 ++-- src/packs/_source/munition/kurzbogen-m.json | 24 ++-- src/packs/_source/munition/langbogen-m.json | 24 ++-- .../_source/munition/leichte-armbrust-m.json | 24 ++-- .../_source/munition/windenarmbrust-m.json | 24 ++-- src/packs/_source/ruestzeug/buckler.json | 14 +-- .../_source/ruestzeug/dicke-kleidung.json | 23 ++-- .../_source/ruestzeug/garether-platte.json | 23 ++-- .../ruestzeug/horasischer-reiterharnisch.json | 25 ++-- .../_source/ruestzeug/kettenhemd-halbarm.json | 25 ++-- .../ruestzeug/komplette-gestechruestung.json | 25 ++-- src/packs/_source/ruestzeug/kroetenhaut.json | 23 ++-- src/packs/_source/ruestzeug/kuerass.json | 25 ++-- .../_source/ruestzeug/langes-kettenhemd.json | 25 ++-- .../_source/ruestzeug/lederharnisch.json | 25 ++-- .../_source/ruestzeug/leichte-platte.json | 25 ++-- .../_source/ruestzeug/schuppenpanzer.json | 25 ++-- .../_source/ruestzeug/spiegelpanzer.json | 25 ++-- .../ruestzeug/wattierte-unterkleidung.json | 10 +- .../ruestzeug/wattierter-waffenrock.json | 23 ++-- src/style/molecules/_droppables.scss | 27 +++++ .../item/equipment/tab-ammunition.hbs | 15 +++ src/templates/item/equipment/tab-armor.hbs | 47 +++++++- .../item/equipment/tab-container.hbs | 7 -- src/templates/item/equipment/tab-meta.hbs | 4 +- src/templates/item/equipment/tab-settings.hbs | 25 ++++ src/templates/ui/partial-equipment-button.hbs | 2 +- 37 files changed, 434 insertions(+), 417 deletions(-) create mode 100644 src/style/molecules/_droppables.scss create mode 100644 src/templates/item/equipment/tab-ammunition.hbs delete mode 100644 src/templates/item/equipment/tab-container.hbs create mode 100644 src/templates/item/equipment/tab-settings.hbs diff --git a/src/module/data/character.mjs b/src/module/data/character.mjs index 433c8865..fc0ed27d 100644 --- a/src/module/data/character.mjs +++ b/src/module/data/character.mjs @@ -1,12 +1,12 @@ +import {Equipment} from "../documents/equipment.mjs"; + const { SchemaField, NumberField, StringField, HTMLField, - EmbeddedDocumentField, DocumentIdField, ArrayField, - ForeignDocumentField } = foundry.data.fields; export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel { diff --git a/src/module/data/equipment.mjs b/src/module/data/equipment.mjs index 7025da9a..0e4a1ea8 100644 --- a/src/module/data/equipment.mjs +++ b/src/module/data/equipment.mjs @@ -1,7 +1,8 @@ import BaseItem from "./base-item.mjs"; +import {Equipment} from "../documents/equipment.mjs"; const { - ArrayField, NumberField, StringField, HTMLField + ArrayField, EmbeddedCollectionField, SchemaField, NumberField, StringField, HTMLField } = foundry.data.fields; export class EquipmentDataModel extends BaseItem { @@ -34,9 +35,23 @@ export class EquipmentDataModel extends BaseItem { rangedAttackDamage: new StringField(), rangedReloadTime: new NumberField({required: false}), - armorValue: new NumberField({required: false}), + armorValue: new SchemaField({ + total: new NumberField({required: true, initial: 0}), + arme: new NumberField({required: true, initial: 0}), + beine: new NumberField({required: true, initial: 0}), + rücken: new NumberField({required: true, initial: 0}), + bauch: new NumberField({required: true, initial: 0}), + brust: new NumberField({required: true, initial: 0}), + kopf: new NumberField({required: true, initial: 0}), + }, {required: false}), armorHandicap: new NumberField({required: false}), + + ammunition: new SchemaField({ + max: new NumberField({required: true, initial: 1}), + count: new NumberField({required: true, initial: 1}), + }, {required: false}), } } + } diff --git a/src/module/sheets/character/advsf.mjs b/src/module/sheets/character/advsf.mjs index 7b77ed96..018cbf53 100644 --- a/src/module/sheets/character/advsf.mjs +++ b/src/module/sheets/character/advsf.mjs @@ -35,8 +35,16 @@ export default { return context }, - _onRender: (context, options) => { - + _onRender: (context, options, thisObject) => { + new foundry.applications.ux.DragDrop.implementation({ + dropSelector: ".advantages, .special-abilities", + permissions: { + drop: thisObject._canDragDrop.bind(thisObject) + }, + callbacks: { + drop: thisObject._onDrop.bind(thisObject), + } + }).bind(thisObject.element); }, _getTabConfig: (group) => { group.tabs.push({id: "advsf", group: "sheet", label: "Vorteile"}) diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 47957a1d..9e474974 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -137,7 +137,8 @@ export default { }, callbacks: { dragstart: thisObject._onDragStart.bind(thisObject), - drop: thisObject._onDrop.bind(thisObject) + drop: thisObject._onDrop.bind(thisObject), + dragover: thisObject._onDragOver.bind(thisObject) } }).bind(thisObject.element); diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 73613520..d39318cc 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -369,7 +369,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { _onRender(context, options) { Meta._onRender(context, options, this.element) Social._onRender(context, options, this.element) - Advsf._onRender(context, options, this.element) + Advsf._onRender(context, options, this) Combat._onRender(context, options, this.element) Effects._onRender(context, options, this.element) Equipment._onRender(context, options, this) @@ -378,6 +378,11 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { Spells._onRender(context, options, this.element) } + async _canDragDrop() { + return true + } + + // TODO needs to be fixed once Character Sheet is migrated to ActorSheetV2 async _onDrop(event) { const data = TextEditor.implementation.getDragEventData(event); @@ -389,11 +394,14 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { const documentClass = foundry.utils.getDocumentClass(data.type); if (documentClass) { const document = await documentClass.fromDropData(data); - await this._onDropDocument(event, document); - // No duplication by moving items from one actor to another - if (document.parent) { - document.parent.items.get(document._id).delete() + if (document.type === "Equipment" || document.type === "Advantage" || document.type === "Spell" || document.type === "Liturgy" || document.type === "ActiveEffect" || document.type === "SpecialAbility") { + // No duplication by moving items from one actor to another + if (document.parent && document.parent !== this.actor) { + document.parent.items.get(document._id).delete() + } + + await this._onDropDocument(event, document); } } } diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs index a5c3f878..d087fd4c 100644 --- a/src/module/sheets/equipmentSheet.mjs +++ b/src/module/sheets/equipmentSheet.mjs @@ -56,12 +56,16 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) ranged: { template: `systems/DSA_4-1/templates/item/equipment/tab-ranged.hbs` }, - container: { - template: `systems/DSA_4-1/templates/item/equipment/tab-container.hbs` + ammunition: { + template: `systems/DSA_4-1/templates/item/equipment/tab-ammunition.hbs` }, armor: { template: `systems/DSA_4-1/templates/item/equipment/tab-armor.hbs` - } + }, + settings: { + template: `systems/DSA_4-1/templates/item/equipment/tab-settings.hbs` + }, + } /** @@ -84,6 +88,17 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } }) + // manage categories into array + normalisedFormData['system.category'] = [] + if (normalisedFormData.isMelee) normalisedFormData['system.category'].push("Nahkampfwaffe") + delete normalisedFormData.isMelee + if (normalisedFormData.isRanged) normalisedFormData['system.category'].push("Fernkampfwaffe") + delete normalisedFormData.isRanged + if (normalisedFormData.isAmmunition) normalisedFormData['system.category'].push("Munition") + delete normalisedFormData.isAmmunition + if (normalisedFormData.isArmor) normalisedFormData['system.category'].push("Rüstung") + delete normalisedFormData.isArmor + await this.document.update(normalisedFormData) // Note: formData.object } @@ -98,12 +113,12 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) case 'ranged': this.#prepareRangedContext(context) break; - case 'container': - this.#prepareContainerContext(context) - break; case 'armor': this.#prepareArmorContext(context) break; + case 'settings': + this.#prepareSettingsContext(context) + break; } context.tab = context.tabs[partId] return context @@ -123,7 +138,6 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) Nahkampfwaffe: "Nahkampfwaffe", Fernkampfwaffe: "Fernkampfwaffe", Behälter: "Behälter", - Rüstung: "Rüstung", }, entries: equipmentData.category, targetField: "category" @@ -171,7 +185,7 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } } - #prepareContainerContext(context) { + #prepareAmmunitionContext(context) { } @@ -179,44 +193,49 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) } + #prepareSettingsContext(context) { + context.isMelee = this.document.system.category.includes("Nahkampfwaffe") + context.isRanged = this.document.system.category.includes("Fernkampfwaffe") + context.isAmmunition = this.document.system.category.includes("Munition") + context.isArmor = this.document.system.category.includes("Rüstung") + } + /** * Adds Tabs based on the items nature * - * @param {String} tabGroup + * @param {String} group * @private */ - _prepareTabs(tabGroup) { + _getTabsConfig(group) { - const currentTabs = super._prepareTabs(tabGroup) + const tabs = foundry.utils.deepClone(super._getTabsConfig(group)) const category = this.document.system.category /** * * @type {[{ApplicationTab}]} */ - let tabs = currentTabs if (category.includes("Nahkampfwaffe")) { - tabs.melee = { - id: 'melee', group: tabGroup, label: 'Nahkampfwaffe' - } + tabs.tabs.push({ + id: 'melee', group: group, label: 'Nahkampfwaffe' + }) } if (category.includes("Fernkampfwaffe")) { - tabs.ranged = { - id: 'ranged', group: tabGroup, label: 'Fernkampfwaffe' - } - } - if (category.includes("Behälter")) { - tabs.container = { - id: 'container', group: tabGroup, label: 'Behälter' - } + tabs.tabs.push({ + id: 'ranged', group: group, label: 'Fernkampfwaffe' + }) } if (category.includes("Rüstung")) { - tabs.armor = { - id: 'armor', group: tabGroup, label: 'Rüstung' - } + tabs.tabs.push({ + id: 'armor', group: group, label: 'Rüstung' + }) } + tabs.tabs.push({ + id: 'settings', group: group, label: 'Einstellungen' + }) + return tabs } @@ -226,6 +245,8 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) const context = await super._prepareContext(options) context.price = context.document.system.price context.weight = context.document.system.weight + context.inventoryItems = [] + context.containerVolume = context.document.system.containerVolume return context } @@ -238,14 +259,38 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) * @protected */ _onRender(context, options) { - this.element.querySelector('.array-editor select').addEventListener('change', (evt) => { - const addingValue = evt.currentTarget.value - const fieldToTarget = evt.currentTarget.dataset.targetField - const newSkills = [...this.document.system[fieldToTarget], addingValue] - this.document.update({system: {[fieldToTarget]: newSkills}}) - evt.currentTarget.value = "" - }) + new foundry.applications.ux.DragDrop.implementation({ + dropSelector: ".inventory-table", + permissions: { + drop: this._canDragDrop.bind(this) + }, + callbacks: { + drop: this._onDrop.bind(this) + } + }).bind(this.element); + } + + _canDragDrop(event) { + console.log(event) + return true + } + + async _onDrop(event) { + const data = TextEditor.implementation.getDragEventData(event); + + // Dropped Documents + const documentClass = foundry.utils.getDocumentClass(data.type); + if (documentClass) { + + const document = await documentClass.fromDropData(data) + + console.log(document, document.parent) + + // Dropped Documents + + document.update({"parent": this.document}) + } } } diff --git a/src/packs/_source/munition/balläster-m.json b/src/packs/_source/munition/balläster-m.json index 27ef87dc..14817e5e 100644 --- a/src/packs/_source/munition/balläster-m.json +++ b/src/packs/_source/munition/balläster-m.json @@ -2,24 +2,14 @@ "name": "Munition (Balläster)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.125, "price": 0.6, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/eisenwalder-m.json b/src/packs/_source/munition/eisenwalder-m.json index 008ca7b9..3d9780ac 100644 --- a/src/packs/_source/munition/eisenwalder-m.json +++ b/src/packs/_source/munition/eisenwalder-m.json @@ -2,24 +2,14 @@ "name": "Munition (Eisenwalder)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0, "price": 1.5, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 10, + "count": 10 + } } diff --git a/src/packs/_source/munition/elfenbogen-m.json b/src/packs/_source/munition/elfenbogen-m.json index 64c590fb..2aef5eaa 100644 --- a/src/packs/_source/munition/elfenbogen-m.json +++ b/src/packs/_source/munition/elfenbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Elfenbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow2.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 0.4, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kompositbogen-m.json b/src/packs/_source/munition/kompositbogen-m.json index cd73f87a..055aae0c 100644 --- a/src/packs/_source/munition/kompositbogen-m.json +++ b/src/packs/_source/munition/kompositbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kompositbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.05, "price": 0.25, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kriegsbogen-m.json b/src/packs/_source/munition/kriegsbogen-m.json index 08ddb371..66e7a9ac 100644 --- a/src/packs/_source/munition/kriegsbogen-m.json +++ b/src/packs/_source/munition/kriegsbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kriegsbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.1, "price": 0.6, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/kurzbogen-m.json b/src/packs/_source/munition/kurzbogen-m.json index 2e174c37..5ac2fc28 100644 --- a/src/packs/_source/munition/kurzbogen-m.json +++ b/src/packs/_source/munition/kurzbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Kurzbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.05, "price": 0.25, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/langbogen-m.json b/src/packs/_source/munition/langbogen-m.json index 5d8978a7..fc89dfbf 100644 --- a/src/packs/_source/munition/langbogen-m.json +++ b/src/packs/_source/munition/langbogen-m.json @@ -2,24 +2,14 @@ "name": "Munition (Langbogen)", "image": "systems/DSA_4-1/assets/arsenal/arrow1.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 0.4, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/leichte-armbrust-m.json b/src/packs/_source/munition/leichte-armbrust-m.json index e61e3b5f..fc700dfa 100644 --- a/src/packs/_source/munition/leichte-armbrust-m.json +++ b/src/packs/_source/munition/leichte-armbrust-m.json @@ -2,24 +2,14 @@ "name": "Munition (Leichte Armbrust)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.075, "price": 1.5, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/munition/windenarmbrust-m.json b/src/packs/_source/munition/windenarmbrust-m.json index 3086a929..5cf359bd 100644 --- a/src/packs/_source/munition/windenarmbrust-m.json +++ b/src/packs/_source/munition/windenarmbrust-m.json @@ -2,24 +2,14 @@ "name": "Munition (Windenarmbrust)", "image": "systems/DSA_4-1/assets/arsenal/arrow3.png", "category": [ - "Gegenstand" + "Gegenstand", + "Munition" ], "weight": 0.1, "price": 2, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 0, - "armorHandicap": 0, - "description": "" + "description": "", + "ammunition": { + "max": 1, + "count": 1 + } } diff --git a/src/packs/_source/ruestzeug/buckler.json b/src/packs/_source/ruestzeug/buckler.json index 8915102f..c7ea362d 100644 --- a/src/packs/_source/ruestzeug/buckler.json +++ b/src/packs/_source/ruestzeug/buckler.json @@ -8,21 +8,13 @@ "weight": 1, "price": 40, "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 1, + "iniModifier": -1, + "attackModifier": -2, + "parryModifier": -1, "meleeAttackModifier": 0, "meleeAttackModifierIncrement": 0, "meleeSkills": [ "Schilde" ], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 1, - "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/dicke-kleidung.json b/src/packs/_source/ruestzeug/dicke-kleidung.json index e0a41a1a..d4fd700a 100644 --- a/src/packs/_source/ruestzeug/dicke-kleidung.json +++ b/src/packs/_source/ruestzeug/dicke-kleidung.json @@ -7,20 +7,15 @@ ], "weight": 3, "price": 0, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 1, + "armorValue": { + "total": 1, + "kopf": 0, + "brust": 1, + "rücken": 1, + "bauch": 1, + "arme": 1, + "beine": 1 + }, "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/garether-platte.json b/src/packs/_source/ruestzeug/garether-platte.json index e4dcc56d..52a1bfde 100644 --- a/src/packs/_source/ruestzeug/garether-platte.json +++ b/src/packs/_source/ruestzeug/garether-platte.json @@ -7,20 +7,15 @@ ], "weight": 14, "price": 750, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 6, + "armorValue": { + "total": 5, + "kopf": 0, + "brust": 6, + "rücken": 5, + "bauch": 6, + "arme": 5, + "beine": 4 + }, "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json index 478b77b7..edc31c64 100644 --- a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json +++ b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json @@ -7,20 +7,15 @@ ], "weight": 17, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 8, - "armorHandicap": 5, + "armorValue": { + "total": 6, + "kopf": 3, + "brust": 7, + "rücken": 5, + "bauch": 7, + "arme": 5, + "beine": 5 + }, + "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json index 7f18342b..df24043e 100644 --- a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json +++ b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json @@ -7,20 +7,15 @@ ], "weight": 6.5, "price": 150, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 3, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 4, + "rücken": 4, + "bauch": 4, + "arme": 2, + "beine": 1 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/komplette-gestechruestung.json b/src/packs/_source/ruestzeug/komplette-gestechruestung.json index 77e2e1d3..4d6468b2 100644 --- a/src/packs/_source/ruestzeug/komplette-gestechruestung.json +++ b/src/packs/_source/ruestzeug/komplette-gestechruestung.json @@ -7,20 +7,15 @@ ], "weight": 30, "price": 2500, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 12, - "armorHandicap": 10, + "armorValue": { + "total": 8, + "kopf": 8, + "brust": 8, + "rücken": 7, + "bauch": 8, + "arme": 7, + "beine": 7 + }, + "armorHandicap": 8, "description": "" } diff --git a/src/packs/_source/ruestzeug/kroetenhaut.json b/src/packs/_source/ruestzeug/kroetenhaut.json index c32534f9..b38e0f29 100644 --- a/src/packs/_source/ruestzeug/kroetenhaut.json +++ b/src/packs/_source/ruestzeug/kroetenhaut.json @@ -7,20 +7,15 @@ ], "weight": 4, "price": 60, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 3, + "rücken": 2, + "bauch": 2, + "arme": 1, + "beine": 0 + }, "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/kuerass.json b/src/packs/_source/ruestzeug/kuerass.json index 36cd7334..c026a910 100644 --- a/src/packs/_source/ruestzeug/kuerass.json +++ b/src/packs/_source/ruestzeug/kuerass.json @@ -7,20 +7,15 @@ ], "weight": 4, "price": 110, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 2, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 5, + "rücken": 1, + "bauch": 2, + "arme": 0, + "beine": 0 + }, + "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/langes-kettenhemd.json b/src/packs/_source/ruestzeug/langes-kettenhemd.json index fe571b4c..c43d1723 100644 --- a/src/packs/_source/ruestzeug/langes-kettenhemd.json +++ b/src/packs/_source/ruestzeug/langes-kettenhemd.json @@ -7,20 +7,15 @@ ], "weight": 10, "price": 180, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 4, - "armorHandicap": 4, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 4, + "rücken": 4, + "bauch": 4, + "arme": 3, + "beine": 2 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/lederharnisch.json b/src/packs/_source/ruestzeug/lederharnisch.json index a6e06681..2cd665b8 100644 --- a/src/packs/_source/ruestzeug/lederharnisch.json +++ b/src/packs/_source/ruestzeug/lederharnisch.json @@ -7,20 +7,15 @@ ], "weight": 4.5, "price": 80, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 3, - "armorHandicap": 3, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 3, + "rücken": 3, + "bauch": 3, + "arme": 0, + "beine": 0 + }, + "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/leichte-platte.json b/src/packs/_source/ruestzeug/leichte-platte.json index b3312630..bbfe4310 100644 --- a/src/packs/_source/ruestzeug/leichte-platte.json +++ b/src/packs/_source/ruestzeug/leichte-platte.json @@ -7,20 +7,15 @@ ], "weight": 7.5, "price": 250, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 4, - "armorHandicap": 3, + "armorValue": { + "total": 3, + "kopf": 0, + "brust": 5, + "rücken": 4, + "bauch": 5, + "arme": 0, + "beine": 2 + }, + "armorHandicap": 2, "description": "" } diff --git a/src/packs/_source/ruestzeug/schuppenpanzer.json b/src/packs/_source/ruestzeug/schuppenpanzer.json index 508c6f19..476a8da7 100644 --- a/src/packs/_source/ruestzeug/schuppenpanzer.json +++ b/src/packs/_source/ruestzeug/schuppenpanzer.json @@ -7,20 +7,15 @@ ], "weight": 12, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 5, - "armorHandicap": 5, + "armorValue": { + "total": 4, + "kopf": 0, + "brust": 5, + "rücken": 5, + "bauch": 5, + "arme": 3, + "beine": 3 + }, + "armorHandicap": 4, "description": "" } diff --git a/src/packs/_source/ruestzeug/spiegelpanzer.json b/src/packs/_source/ruestzeug/spiegelpanzer.json index 9a04ba63..d3273d63 100644 --- a/src/packs/_source/ruestzeug/spiegelpanzer.json +++ b/src/packs/_source/ruestzeug/spiegelpanzer.json @@ -7,20 +7,15 @@ ], "weight": 10, "price": 1000, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 5, - "armorHandicap": 4, + "armorValue": { + "total": 4, + "kopf": 0, + "brust": 5, + "rücken": 5, + "bauch": 5, + "arme": 3, + "beine": 2 + }, + "armorHandicap": 3, "description": "" } diff --git a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json index defd8026..589ac6be 100644 --- a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json +++ b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json @@ -20,7 +20,15 @@ "rangedRangeDamageModifier": "", "rangedAttackDamage": "", "rangedReloadTime": 0, - "armorValue": 1, + "armorValue": { + "total": 1.5, + "kopf": 0, + "brust": 1, + "rücken": 1, + "bauch": 1, + "arme": 1, + "beine": 1 + }, "armorHandicap": 1, "description": "" } diff --git a/src/packs/_source/ruestzeug/wattierter-waffenrock.json b/src/packs/_source/ruestzeug/wattierter-waffenrock.json index c2aeb7a4..28d54f5f 100644 --- a/src/packs/_source/ruestzeug/wattierter-waffenrock.json +++ b/src/packs/_source/ruestzeug/wattierter-waffenrock.json @@ -7,20 +7,15 @@ ], "weight": 3, "price": 40, - "breakFactor": 0, - "iniModifier": 0, - "attackModifier": 0, - "parryModifier": 0, - "meleeAttackModifier": 0, - "meleeAttackModifierIncrement": 0, - "meleeSkills": [], - "meleeAttackDamage": "", - "rangedSkills": [], - "rangedRangeModifier": "", - "rangedRangeDamageModifier": "", - "rangedAttackDamage": "", - "rangedReloadTime": 0, - "armorValue": 2, + "armorValue": { + "total": 2, + "kopf": 0, + "brust": 2, + "rücken": 2, + "bauch": 2, + "arme": 1, + "beine": 1 + }, "armorHandicap": 2, "description": "" } diff --git a/src/style/molecules/_droppables.scss b/src/style/molecules/_droppables.scss new file mode 100644 index 00000000..a3eabd6a --- /dev/null +++ b/src/style/molecules/_droppables.scss @@ -0,0 +1,27 @@ +.droppable { + + .inventory-table { + position: relative; + } + + .inventory-table::after { + + content: 'Gegenstände hier fallen lassen'; + pointer-events: none; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + border-radius: 8px; + border-style: dashed; + border-color: gray; + line-height: 34px; + height: 34px; + vertical-align: middle; + text-align: center; + background-color: rgba(0, 0, 0, 0.4); + color: gray; + } + +} \ No newline at end of file diff --git a/src/templates/item/equipment/tab-ammunition.hbs b/src/templates/item/equipment/tab-ammunition.hbs new file mode 100644 index 00000000..bc18aed5 --- /dev/null +++ b/src/templates/item/equipment/tab-ammunition.hbs @@ -0,0 +1,15 @@ +
+
+
+ + +
+
+
\ No newline at end of file diff --git a/src/templates/item/equipment/tab-armor.hbs b/src/templates/item/equipment/tab-armor.hbs index 7bfcd6de..90e476cf 100644 --- a/src/templates/item/equipment/tab-armor.hbs +++ b/src/templates/item/equipment/tab-armor.hbs @@ -3,11 +3,48 @@ data-group="{{tabs.armor.group}}">
-
- -
+
+ Rüstungswerte + +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
-
+ {{!-- categories are now in their on tab --}}
+
+
+ Art des Gegenstands + + + + +
+
+ \ No newline at end of file diff --git a/src/templates/ui/partial-equipment-button.hbs b/src/templates/ui/partial-equipment-button.hbs index 63c98791..63c733a8 100644 --- a/src/templates/ui/partial-equipment-button.hbs +++ b/src/templates/ui/partial-equipment-button.hbs @@ -12,7 +12,7 @@ {{#each this}} - + {{this.name}} {{this.quantity}} {{#if this.worn}}({{/if}}{{this.weight}}{{#if this.worn}}){{/if}} -- 2.43.0 From 89d427b7114a2e25bfc97651d7ad354b24902e1d Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 19:43:43 +0200 Subject: [PATCH 37/40] fixes kinks in equipping weapons --- src/module/sheets/character/equipment.mjs | 9 +++++---- src/module/sheets/characterSheet.mjs | 8 ++++---- src/style/organisms/character-tabs/_inventory.scss | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 9e474974..8ae6d0db 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -174,13 +174,14 @@ export default { const {itemId} = target.dataset const item = thisObject.document.items.get(itemId) console.log(item.system.category) - return !thisObject.document.isWorn(itemId) + return !thisObject.document.isWorn(itemId) && item.system.category.indexOf("Munition") != -1 } }, { name: "Ausrüsten", callback: (target) => { - //thisObject.deleteEmbeddedDocuments('Item', [event.dataset.id]) + const updateObject = thisObject.document.getEquipmentSetUpdateObject() + }, condition: (target) => { const {itemId} = target.dataset @@ -231,11 +232,11 @@ export default { name: "Aus dem Inventar entfernen", icon: '', callback: (target) => { - thisObject.deleteEmbeddedDocuments('Item', [target.dataset.id]) + thisObject.document.deleteEmbeddedDocuments('Item', [target.dataset.itemId]) }, condition: (target) => { const {itemId} = target.dataset - !thisObject.document.isWorn(itemId) + return !thisObject.document.isWorn(itemId) } } ], {jQuery: false}); diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index d39318cc..1075b200 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -248,9 +248,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { name: obj.name, using: links.name, atroll: `1d20cs<${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M - at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, + at: `${this.document.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, paroll: `1d20cs<${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M - pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, + pa: `${this.document.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod tp: `${links.system.meleeAttackDamage}`, iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`, @@ -272,9 +272,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { name: obj.name, using: rechts.name, atroll: `1d20cs<${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M - at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, + at: `${this.document.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, paroll: `1d20cs<${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M - pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, + pa: `${this.document.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod tp: `${rechts.system.meleeAttackDamage}`, iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`, diff --git a/src/style/organisms/character-tabs/_inventory.scss b/src/style/organisms/character-tabs/_inventory.scss index de57c16e..62d8f8c2 100644 --- a/src/style/organisms/character-tabs/_inventory.scss +++ b/src/style/organisms/character-tabs/_inventory.scss @@ -34,6 +34,20 @@ .inventory { grid-area: inventory; + display: flex; + flex-direction: column; + + h3 { + flex: 0; + } + + .inventory-table { + flex: 1; + + .equipment { + height: 32px; + } + } .equipment:hover { .item-name { -- 2.43.0 From b3f5e68c2350ebf8859c29ebfc0cec3dcf4085a2 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 20:30:54 +0200 Subject: [PATCH 38/40] reestablishes armor values --- src/module/data/equipment.mjs | 8 +- src/module/documents/character.mjs | 98 +++++++------------ src/module/sheets/character/equipment.mjs | 18 +++- src/module/sheets/equipmentSheet.mjs | 3 + .../_source/ruestzeug/dicke-kleidung.json | 8 +- .../_source/ruestzeug/garether-platte.json | 9 +- .../ruestzeug/horasischer-reiterharnisch.json | 8 +- .../_source/ruestzeug/kettenhemd-halbarm.json | 8 +- .../ruestzeug/komplette-gestechruestung.json | 8 +- src/packs/_source/ruestzeug/kroetenhaut.json | 8 +- src/packs/_source/ruestzeug/kuerass.json | 8 +- .../_source/ruestzeug/langes-kettenhemd.json | 8 +- .../_source/ruestzeug/lederharnisch.json | 8 +- .../_source/ruestzeug/leichte-platte.json | 8 +- .../_source/ruestzeug/schuppenpanzer.json | 8 +- .../_source/ruestzeug/spiegelpanzer.json | 8 +- .../ruestzeug/wattierte-unterkleidung.json | 8 +- .../ruestzeug/wattierter-waffenrock.json | 8 +- .../organisms/character-tabs/_combat.scss | 10 ++ src/templates/actor/character/tab-combat.hbs | 2 + src/templates/item/equipment/tab-armor.hbs | 20 +++- 21 files changed, 156 insertions(+), 116 deletions(-) diff --git a/src/module/data/equipment.mjs b/src/module/data/equipment.mjs index 0e4a1ea8..fd2a4f33 100644 --- a/src/module/data/equipment.mjs +++ b/src/module/data/equipment.mjs @@ -37,9 +37,11 @@ export class EquipmentDataModel extends BaseItem { armorValue: new SchemaField({ total: new NumberField({required: true, initial: 0}), - arme: new NumberField({required: true, initial: 0}), - beine: new NumberField({required: true, initial: 0}), - rücken: new NumberField({required: true, initial: 0}), + armlinks: new NumberField({required: true, initial: 0}), + beinlinks: new NumberField({required: true, initial: 0}), + armrechts: new NumberField({required: true, initial: 0}), + beinrechts: new NumberField({required: true, initial: 0}), + ruecken: new NumberField({required: true, initial: 0}), bauch: new NumberField({required: true, initial: 0}), brust: new NumberField({required: true, initial: 0}), kopf: new NumberField({required: true, initial: 0}), diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index 824f99d2..da36c15e 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -117,6 +117,7 @@ export class Character extends Actor { systemData.wunden.kopf = 0; systemData.wunden.brust = 0; systemData.wunden.bauch = 0; + systemData.wunden.ruecken = 0; systemData.wunden.armlinks = 0; systemData.wunden.armrechts = 0; systemData.wunden.beinlinks = 0; @@ -128,73 +129,40 @@ export class Character extends Actor { // map current set to RS and BE const ausruestung = systemData.heldenausruestung[systemData.setEquipped]; - if (ausruestung) { - if (ausruestung.brust) { - systemData.be += systemData.parent.items.get(ausruestung.brust).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.brust = systemData.parent.items.get(ausruestung.brust).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.brust).system.armorValue ?? 0 - } - } - if (ausruestung.bauch) { - systemData.be += systemData.parent.items.get(ausruestung.bauch).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.bauch = systemData.parent.items.get(ausruestung.bauch).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.bauch).system.armorValue ?? 0 - } - } - if (ausruestung.ruecken) { - systemData.be += systemData.parent.items.get(ausruestung.ruecken).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - // ruecken is not a valid trefferzone - } else { - systemData.rs += systemData.parent.items.get(ausruestung.ruecken).system.armorValue ?? 0 - } - } - if (ausruestung.armlinks) { - systemData.be += systemData.parent.items.get(ausruestung.armlinks).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.armlinks = systemData.parent.items.get(ausruestung.armlinks).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.armlinks).system.armorValue ?? 0 - } - } - if (ausruestung.armrechts) { - systemData.be += systemData.parent.items.get(ausruestung.armrechts).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.armrechts = systemData.parent.items.get(ausruestung.armrechts).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.armrechts).system.armorValue ?? 0 - } - } - if (ausruestung.beinlinks) { - systemData.be += systemData.parent.items.get(ausruestung.beinlinks).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.beinlinks = systemData.parent.items.get(ausruestung.beinlinks).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.beinlinks).system.armorValue ?? 0 - } - } - if (ausruestung.beinrechts) { - systemData.be += systemData.parent.items.get(ausruestung.beinrechts).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.beinrechts = systemData.parent.items.get(ausruestung.beinrechts).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.beinrechts).system.armorValue ?? 0 - } - } - if (ausruestung.kopf) { - systemData.be += systemData.parent.items.get(ausruestung.kopf).system.armorHandicap ?? 0 - if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { - systemData.rs.kopf = systemData.parent.items.get(ausruestung.kopf).system.armorValue ?? 0 - } else { - systemData.rs += systemData.parent.items.get(ausruestung.kopf).system.armorValue ?? 0 - } - } + const zonesToCheck = [ + "brust", + "bauch", + "ruecken", + "kopf", + "armlinks", + "armrechts", + "beinlinks", + "beinrechts"] + + if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { + systemData.rs.gesamt = 0 + systemData.rs.brust = 0 + systemData.rs.bauch = 0 + systemData.rs.ruecken = 0 + systemData.rs.kopf = 0 + systemData.rs.armlinks = 0 + systemData.rs.armrechts = 0 + systemData.rs.beinlinks = 0 + systemData.rs.beinrechts = 0 + } else { + systemData.rs = 0 } + zonesToCheck.forEach((zone) => { + systemData.be += systemData.parent.items.get(ausruestung[zone])?.system.armorHandicap ?? 0 + if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { + zonesToCheck.forEach((itemZone) => { + systemData.rs[itemZone] += systemData.parent.items.get(ausruestung[zone])?.system.armorValue[itemZone] ?? 0 + }) + } else { + systemData.rs += systemData.parent.items.get(ausruestung[zone])?.system.armorValue.total ?? 0 + } + }) systemData.kap.max = 0; diff --git a/src/module/sheets/character/equipment.mjs b/src/module/sheets/character/equipment.mjs index 8ae6d0db..ee434403 100644 --- a/src/module/sheets/character/equipment.mjs +++ b/src/module/sheets/character/equipment.mjs @@ -181,7 +181,23 @@ export default { name: "Ausrüsten", callback: (target) => { const updateObject = thisObject.document.getEquipmentSetUpdateObject() - + // find next unoccupied slot and enter the item + console.log(updateObject) + const nextUnoccupiedSlot = Object.entries(updateObject).find(([key, value]) => { + // but not when it is a weapon slot + console.log(key, value === null + && key.indexOf(".links") === -1 + && key.indexOf(".rechts") === -1 + && key.indexOf(".fernkampf") === -1 + && key.indexOf(".munition") === -1) + return value === null + && key.indexOf(".links") === -1 + && key.indexOf(".rechts") === -1 + && key.indexOf(".fernkampf") === -1 + && key.indexOf(".munition") === -1 + }) + updateObject[nextUnoccupiedSlot[0]] = target.dataset.itemId + thisObject.document.update(updateObject) }, condition: (target) => { const {itemId} = target.dataset diff --git a/src/module/sheets/equipmentSheet.mjs b/src/module/sheets/equipmentSheet.mjs index d087fd4c..d0fb20ac 100644 --- a/src/module/sheets/equipmentSheet.mjs +++ b/src/module/sheets/equipmentSheet.mjs @@ -23,6 +23,9 @@ export class EquipmentSheet extends HandlebarsApplicationMixin(DocumentSheetV2) closeOnSubmit: false, handler: EquipmentSheet.#onSubmitForm }, + window: { + resizable: true, + }, actions: { editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage diff --git a/src/packs/_source/ruestzeug/dicke-kleidung.json b/src/packs/_source/ruestzeug/dicke-kleidung.json index d4fd700a..b6eb7922 100644 --- a/src/packs/_source/ruestzeug/dicke-kleidung.json +++ b/src/packs/_source/ruestzeug/dicke-kleidung.json @@ -11,10 +11,12 @@ "total": 1, "kopf": 0, "brust": 1, - "rücken": 1, + "ruecken": 1, "bauch": 1, - "arme": 1, - "beine": 1 + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 }, "armorHandicap": 1, "description": "" diff --git a/src/packs/_source/ruestzeug/garether-platte.json b/src/packs/_source/ruestzeug/garether-platte.json index 52a1bfde..7a41ef07 100644 --- a/src/packs/_source/ruestzeug/garether-platte.json +++ b/src/packs/_source/ruestzeug/garether-platte.json @@ -1,4 +1,5 @@ { + itemZone "name": "Garether Platte", "image": "systems/DSA_4-1/assets/armory/platemail.png", "category": [ @@ -11,10 +12,12 @@ "total": 5, "kopf": 0, "brust": 6, - "rücken": 5, + "ruecken": 5, "bauch": 6, - "arme": 5, - "beine": 4 + "armlinks": 5, + "armrechts": 5, + "beinlinks": 4, + "beinrechts": 4 }, "armorHandicap": 4, "description": "" diff --git a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json index edc31c64..0c9d9ad8 100644 --- a/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json +++ b/src/packs/_source/ruestzeug/horasischer-reiterharnisch.json @@ -11,10 +11,12 @@ "total": 6, "kopf": 3, "brust": 7, - "rücken": 5, + "ruecken": 5, "bauch": 7, - "arme": 5, - "beine": 5 + "armlinks": 5, + "beinlinks": 5, + "armrechts": 5, + "beinrechts": 5 }, "armorHandicap": 4, "description": "" diff --git a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json index df24043e..87b805d7 100644 --- a/src/packs/_source/ruestzeug/kettenhemd-halbarm.json +++ b/src/packs/_source/ruestzeug/kettenhemd-halbarm.json @@ -11,10 +11,12 @@ "total": 3, "kopf": 0, "brust": 4, - "rücken": 4, + "ruecken": 4, "bauch": 4, - "arme": 2, - "beine": 1 + "armlinks": 2, + "armrechts": 2, + "beinlinks": 1, + "beinrechts": 1 }, "armorHandicap": 2, "description": "" diff --git a/src/packs/_source/ruestzeug/komplette-gestechruestung.json b/src/packs/_source/ruestzeug/komplette-gestechruestung.json index 4d6468b2..aec4ce3c 100644 --- a/src/packs/_source/ruestzeug/komplette-gestechruestung.json +++ b/src/packs/_source/ruestzeug/komplette-gestechruestung.json @@ -11,10 +11,12 @@ "total": 8, "kopf": 8, "brust": 8, - "rücken": 7, + "ruecken": 7, "bauch": 8, - "arme": 7, - "beine": 7 + "armlinks": 7, + "beinlinks": 7, + "armrechts": 7, + "beinrechts": 7 }, "armorHandicap": 8, "description": "" diff --git a/src/packs/_source/ruestzeug/kroetenhaut.json b/src/packs/_source/ruestzeug/kroetenhaut.json index b38e0f29..6c6a54a8 100644 --- a/src/packs/_source/ruestzeug/kroetenhaut.json +++ b/src/packs/_source/ruestzeug/kroetenhaut.json @@ -11,10 +11,12 @@ "total": 2, "kopf": 0, "brust": 3, - "rücken": 2, + "ruecken": 2, "bauch": 2, - "arme": 1, - "beine": 0 + "armlinks": 1, + "beinlinks": 0, + "armrechts": 1, + "beinrechts": 0 }, "armorHandicap": 2, "description": "" diff --git a/src/packs/_source/ruestzeug/kuerass.json b/src/packs/_source/ruestzeug/kuerass.json index c026a910..0570b973 100644 --- a/src/packs/_source/ruestzeug/kuerass.json +++ b/src/packs/_source/ruestzeug/kuerass.json @@ -11,10 +11,12 @@ "total": 2, "kopf": 0, "brust": 5, - "rücken": 1, + "ruecken": 1, "bauch": 2, - "arme": 0, - "beine": 0 + "armlinks": 0, + "beinlinks": 0, + "armrechts": 0, + "beinrechts": 0 }, "armorHandicap": 1, "description": "" diff --git a/src/packs/_source/ruestzeug/langes-kettenhemd.json b/src/packs/_source/ruestzeug/langes-kettenhemd.json index c43d1723..28e952c5 100644 --- a/src/packs/_source/ruestzeug/langes-kettenhemd.json +++ b/src/packs/_source/ruestzeug/langes-kettenhemd.json @@ -11,10 +11,12 @@ "total": 3, "kopf": 0, "brust": 4, - "rücken": 4, + "ruecken": 4, "bauch": 4, - "arme": 3, - "beine": 2 + "armlinks": 3, + "armrechts": 3, + "beinlinks": 2, + "beinrechts": 2 }, "armorHandicap": 2, "description": "" diff --git a/src/packs/_source/ruestzeug/lederharnisch.json b/src/packs/_source/ruestzeug/lederharnisch.json index 2cd665b8..c9d37a51 100644 --- a/src/packs/_source/ruestzeug/lederharnisch.json +++ b/src/packs/_source/ruestzeug/lederharnisch.json @@ -11,10 +11,12 @@ "total": 2, "kopf": 0, "brust": 3, - "rücken": 3, + "ruecken": 3, "bauch": 3, - "arme": 0, - "beine": 0 + "armlinks": 0, + "beinlinks": 0, + "armrechts": 0, + "beinrechts": 0 }, "armorHandicap": 1, "description": "" diff --git a/src/packs/_source/ruestzeug/leichte-platte.json b/src/packs/_source/ruestzeug/leichte-platte.json index bbfe4310..b75a8472 100644 --- a/src/packs/_source/ruestzeug/leichte-platte.json +++ b/src/packs/_source/ruestzeug/leichte-platte.json @@ -11,10 +11,12 @@ "total": 3, "kopf": 0, "brust": 5, - "rücken": 4, + "ruecken": 4, "bauch": 5, - "arme": 0, - "beine": 2 + "armlinks": 0, + "armrechts": 0, + "beinlinks": 2, + "beinrechts": 2 }, "armorHandicap": 2, "description": "" diff --git a/src/packs/_source/ruestzeug/schuppenpanzer.json b/src/packs/_source/ruestzeug/schuppenpanzer.json index 476a8da7..f1969f89 100644 --- a/src/packs/_source/ruestzeug/schuppenpanzer.json +++ b/src/packs/_source/ruestzeug/schuppenpanzer.json @@ -11,10 +11,12 @@ "total": 4, "kopf": 0, "brust": 5, - "rücken": 5, + "ruecken": 5, "bauch": 5, - "arme": 3, - "beine": 3 + "armlinks": 3, + "beinlinks": 3, + "armrechts": 3, + "beinrechts": 3 }, "armorHandicap": 4, "description": "" diff --git a/src/packs/_source/ruestzeug/spiegelpanzer.json b/src/packs/_source/ruestzeug/spiegelpanzer.json index d3273d63..8887fc45 100644 --- a/src/packs/_source/ruestzeug/spiegelpanzer.json +++ b/src/packs/_source/ruestzeug/spiegelpanzer.json @@ -11,10 +11,12 @@ "total": 4, "kopf": 0, "brust": 5, - "rücken": 5, + "ruecken": 5, "bauch": 5, - "arme": 3, - "beine": 2 + "armlinks": 3, + "armrechts": 3, + "beinlinks": 2, + "beinrechts": 2 }, "armorHandicap": 3, "description": "" diff --git a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json index 589ac6be..6bf993eb 100644 --- a/src/packs/_source/ruestzeug/wattierte-unterkleidung.json +++ b/src/packs/_source/ruestzeug/wattierte-unterkleidung.json @@ -24,10 +24,12 @@ "total": 1.5, "kopf": 0, "brust": 1, - "rücken": 1, + "ruecken": 1, "bauch": 1, - "arme": 1, - "beine": 1 + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 }, "armorHandicap": 1, "description": "" diff --git a/src/packs/_source/ruestzeug/wattierter-waffenrock.json b/src/packs/_source/ruestzeug/wattierter-waffenrock.json index 28d54f5f..922862e6 100644 --- a/src/packs/_source/ruestzeug/wattierter-waffenrock.json +++ b/src/packs/_source/ruestzeug/wattierter-waffenrock.json @@ -11,10 +11,12 @@ "total": 2, "kopf": 0, "brust": 2, - "rücken": 2, + "ruecken": 2, "bauch": 2, - "arme": 1, - "beine": 1 + "armlinks": 1, + "beinlinks": 1, + "armrechts": 1, + "beinrechts": 1 }, "armorHandicap": 2, "description": "" diff --git a/src/style/organisms/character-tabs/_combat.scss b/src/style/organisms/character-tabs/_combat.scss index ee4e0aa3..d8c667b2 100644 --- a/src/style/organisms/character-tabs/_combat.scss +++ b/src/style/organisms/character-tabs/_combat.scss @@ -160,6 +160,11 @@ left: 110px; } + &.ruecken { + top: 86px; + left: 160px; + } + } .armor { @@ -205,6 +210,11 @@ left: 136px } + &.ruecken { + top: 120px; + left: 160px; + } + &.brust { top: 120px; left: 110px; diff --git a/src/templates/actor/character/tab-combat.hbs b/src/templates/actor/character/tab-combat.hbs index 6e86390f..1dbe9569 100644 --- a/src/templates/actor/character/tab-combat.hbs +++ b/src/templates/actor/character/tab-combat.hbs @@ -80,6 +80,7 @@ {{derived.wunden.brust}} {{derived.wunden.armlinks}} {{derived.wunden.armrechts}} + {{derived.wunden.ruecken}} {{derived.wunden.bauch}} {{derived.wunden.beinlinks}} {{derived.wunden.beinrechts}} @@ -89,6 +90,7 @@ {{derived.rs.brust}} {{derived.rs.armlinks}} {{derived.rs.armrechts}} + {{derived.rs.ruecken}} {{derived.rs.bauch}} {{derived.rs.beinlinks}} {{derived.rs.beinrechts}} diff --git a/src/templates/item/equipment/tab-armor.hbs b/src/templates/item/equipment/tab-armor.hbs index 90e476cf..69f49f1f 100644 --- a/src/templates/item/equipment/tab-armor.hbs +++ b/src/templates/item/equipment/tab-armor.hbs @@ -13,13 +13,23 @@
-
-
+
+ +
+
+
@@ -35,7 +45,7 @@
-- 2.43.0 From faa5853aa496a00c3d5460589e3bdb9f3712bb93 Mon Sep 17 00:00:00 2001 From: macniel Date: Mon, 20 Oct 2025 20:57:14 +0200 Subject: [PATCH 39/40] adjusts styling of actions --- .../_source/ruestzeug/garether-platte.json | 1 - src/style/atoms/_colours.scss | 8 +++--- src/style/molecules/_player-action.scss | 25 ++++++++++++++++--- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/packs/_source/ruestzeug/garether-platte.json b/src/packs/_source/ruestzeug/garether-platte.json index 7a41ef07..084cac96 100644 --- a/src/packs/_source/ruestzeug/garether-platte.json +++ b/src/packs/_source/ruestzeug/garether-platte.json @@ -1,5 +1,4 @@ { - itemZone "name": "Garether Platte", "image": "systems/DSA_4-1/assets/armory/platemail.png", "category": [ diff --git a/src/style/atoms/_colours.scss b/src/style/atoms/_colours.scss index 25c572ee..26d0d225 100644 --- a/src/style/atoms/_colours.scss +++ b/src/style/atoms/_colours.scss @@ -70,9 +70,9 @@ $rollable-die-border-color: #000; $dice-box-border-color: #333; -$default-action: #c41; -$default-action-color: #FFF; +$default-action: rgba(204, 68, 17, 0.8); +$default-action-color: #000; -$special-action: #42c; +$special-action: rgba(68, 34, 204, 0.8); -$special-action-color: #FFF; +$special-action-color: #000; diff --git a/src/style/molecules/_player-action.scss b/src/style/molecules/_player-action.scss index dddba46e..f2cd4931 100644 --- a/src/style/molecules/_player-action.scss +++ b/src/style/molecules/_player-action.scss @@ -10,16 +10,35 @@ height: 80px; float: left; margin: 0 8px 8px 0; + position: relative; border: 1px solid #333; - background-color: color.scale(colours.$default-action, $alpha: 20%); color: colours.$default-action-color; + background: url('../../../ui/parchment.jpg'); + background-size: 128px 100%; border-radius: 4px; box-shadow: numbers.$pill-box-inset numbers.$pill-box-inset numbers.$pill-box-blur-radius colours.$pill-box-shadow; + span { + position: relative; + z-index: 2; + } - &.special-ability { - background-color: color.scale(colours.$special-action, $alpha: 20%); + &::after { /* for tinting the texture */ + content: ""; + position: absolute; + background-color: colours.$default-action; + background-blend-mode: multiply; + + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1; + } + + &.special-ability::after { + background-color: colours.$special-action; color: colours.$special-action-color; } -- 2.43.0 From 905b0eb405231245966440050c6760671355e95e Mon Sep 17 00:00:00 2001 From: macniel Date: Tue, 21 Oct 2025 01:17:41 +0200 Subject: [PATCH 40/40] prepares xml-import to no longer append items, but instead cleans them out before adding. This will be controllable via dialog --- gulpfile.mjs | 5 + src/main.mjs | 40 ++-- src/module/data/culture.mjs | 15 ++ src/module/data/species.mjs | 15 ++ src/module/documents/character.mjs | 2 +- src/module/documents/culture.mjs | 9 + src/module/documents/species.mjs | 9 + src/module/sheets/CultureSheet.mjs | 54 +++++ src/module/sheets/ProfessionSheet.mjs | 55 +++++ src/module/sheets/SpeciesSheet.mjs | 55 +++++ src/module/sheets/actions/action-manager.mjs | 5 - src/module/sheets/characterSheet.mjs | 33 ++- src/module/xml-import/xml-import.mjs | 214 ++++++++++++++---- .../helden.model.kultur.Mittelreich.json | 6 + .../helden.model.rasse.Mittellaender.json | 7 + .../_source/zauber/MemorabiaFalsafir.json | 2 +- src/packs/_source/zauber/Windstille.json | 14 +- .../zauber/XenographusSchriftenkunde.json | 2 +- src/style/organisms/_culture-sheet.scss | 26 +++ src/style/organisms/_profession-sheet.scss | 26 +++ src/style/organisms/_species-sheet.scss | 26 +++ src/style/styles.scss | 4 + src/system.json | 37 +++ src/templates/actor/character/main-sheet.hbs | 8 +- src/templates/item/culture-sheet.hbs | 21 ++ src/templates/item/profession-sheet.hbs | 21 ++ src/templates/item/species-sheet.hbs | 25 ++ 27 files changed, 658 insertions(+), 78 deletions(-) create mode 100644 src/module/data/culture.mjs create mode 100644 src/module/data/species.mjs create mode 100644 src/module/documents/culture.mjs create mode 100644 src/module/documents/species.mjs create mode 100644 src/module/sheets/CultureSheet.mjs create mode 100644 src/module/sheets/ProfessionSheet.mjs create mode 100644 src/module/sheets/SpeciesSheet.mjs create mode 100644 src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json create mode 100644 src/packs/_source/spezien/helden.model.rasse.Mittellaender.json create mode 100644 src/style/organisms/_culture-sheet.scss create mode 100644 src/style/organisms/_profession-sheet.scss create mode 100644 src/style/organisms/_species-sheet.scss create mode 100644 src/templates/item/culture-sheet.hbs create mode 100644 src/templates/item/profession-sheet.hbs create mode 100644 src/templates/item/species-sheet.hbs diff --git a/gulpfile.mjs b/gulpfile.mjs index 0c1c432d..d7277532 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -43,6 +43,7 @@ const convert = function (from, to, ofType) { mkdirSync(DEST) readdirSync(SOURCE).forEach(file => { + console.log(file) let originalSource = JSON.parse(readFileSync(join(SOURCE, file), {encoding: "utf8"})); let id = randomID(); @@ -104,6 +105,10 @@ async function prepareDB() { convert("./src/packs/_source/liturgien-und-segnungen", "./src/packs/__source/liturgien", "Liturgy"); convert("./src/packs/_source/wunden", "./src/packs/__source/wunden", "ActiveEffect"); + convert("./src/packs/_source/kulturen", "./src/packs/__source/kulturen", "Culture"); + convert("./src/packs/_source/spezien", "./src/packs/__source/spezien", "Species"); + convert("./src/packs/_source/professionen", "./src/packs/__source/professionen", "Profession"); + } catch (err) { console.error(err); } diff --git a/src/main.mjs b/src/main.mjs index d4b0b9d7..9776ffe3 100644 --- a/src/main.mjs +++ b/src/main.mjs @@ -22,6 +22,11 @@ import {ActiveEffectSheet} from "./module/sheets/ActiveEffectSheet.mjs"; import {ActiveEffectDataModel} from "./module/data/activeeffect.mjs"; import {Trefferzone, Wunde, Zonenruestung, Zonenwunde} from "./module/data/Trefferzone.js"; import {ProfessionDataModel} from "./module/data/profession.mjs"; +import {SpeciesDataModel} from "./module/data/species.mjs"; +import {CultureDataModel} from "./module/data/culture.mjs"; +import {CultureSheet} from "./module/sheets/CultureSheet.mjs"; +import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs"; +import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs"; async function preloadHandlebarsTemplates() { return foundry.applications.handlebars.loadTemplates([ @@ -71,6 +76,8 @@ Hooks.once("init", () => { SpecialAbility: SpecialAbilityDataModel, ActiveEffect: ActiveEffectDataModel, Profession: ProfessionDataModel, + Spezies: SpeciesDataModel, + Kultur: CultureDataModel, } CONFIG.Combat.initiative = { @@ -95,8 +102,6 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.GroupLabel.Item' }) - - // Register sheet application classes foundry.documents.collections.Items.registerSheet('dsa41.skill', SkillSheet, { types: ["Skill"], makeDefault: true, @@ -132,6 +137,21 @@ Hooks.once("init", () => { makeDefault: true, label: 'DSA41.ActiveEffectLabels.ActiveEffect' }) + foundry.documents.collections.Items.registerSheet('dsa41.culture', CultureSheet, { + types: ['Culture'], + makeDefault: true, + label: 'DSA41.CultureLabels.Culture' + }) + foundry.documents.collections.Items.registerSheet('dsa41.spezien', SpeciesSheet, { + types: ['Species'], + makeDefault: true, + label: 'DSA41.SpeciesLabels.Species' + }) + foundry.documents.collections.Items.registerSheet('dsa41.profession', ProfessionSheet, { + types: ['Profession'], + makeDefault: true, + label: 'DSA41.ProfessionLabels.Profession' + }) game.settings.register('DSA_4-1', 'optional_colorfuldice', { name: "Optional: Farbige Würfel nach Paramanthus", @@ -144,8 +164,6 @@ Hooks.once("init", () => { }, requiresReload: false }) - - game.settings.register('DSA_4-1', 'optional_trefferzonen', { name: "Optional: Trefferzonen", hint: "Ersetzt das Wundensystem aus dem BRW durch das Trefferzonensystem aus WdH", @@ -157,7 +175,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_ruestungzonen', { name: "Optional: Zonenrüstung", hint: "Ersetzt das Rüstungssystem aus dem BRW durch das Zonenrüstungssystem aus WdH", @@ -169,7 +186,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_ausdauer', { name: "Optional: Ausdauerregeln", hint: "Aktiviert Regeln für das Spiel mit Ausdauer", @@ -181,7 +197,6 @@ Hooks.once("init", () => { }, requiresReload: true }) - game.settings.register('DSA_4-1', 'optional_distanzklassen', { name: "Optional: Distanzklassen", hint: "Aktiviert Regeln für das Spiel mit Distanzklassen", @@ -197,17 +212,6 @@ Hooks.once("init", () => { return preloadHandlebarsTemplates(); }) -Hooks.on('dropActorSheetData', (actor, sheet, data) => { - /*if (data.uuid) { - if (actor.type === "character") { - return true - } else { - return GroupSheet.onDroppedData(actor, sheet, data); - } - }*/ - return true -}) - 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) => { diff --git a/src/module/data/culture.mjs b/src/module/data/culture.mjs new file mode 100644 index 00000000..ac5f2cc4 --- /dev/null +++ b/src/module/data/culture.mjs @@ -0,0 +1,15 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, StringField, HTMLField} = foundry.data.fields; + +export class CultureDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + variant: new StringField(), + feminineDemonym: new StringField(), + masculineDemonym: new StringField() + } + } +} \ No newline at end of file diff --git a/src/module/data/species.mjs b/src/module/data/species.mjs new file mode 100644 index 00000000..4b487b7d --- /dev/null +++ b/src/module/data/species.mjs @@ -0,0 +1,15 @@ +import BaseItem from "./base-item.mjs"; + +const {BooleanField, NumberField, StringField, HTMLField} = foundry.data.fields; + +export class SpeciesDataModel extends BaseItem { + + static defineSchema() { + return { + description: new HTMLField(), + baseSpeed: new NumberField({required: true, initial: 6, integer: true}), + feminineDemonym: new StringField(), + masculineDemonym: new StringField(), + } + } +} \ No newline at end of file diff --git a/src/module/documents/character.mjs b/src/module/documents/character.mjs index da36c15e..00bb83db 100644 --- a/src/module/documents/character.mjs +++ b/src/module/documents/character.mjs @@ -92,7 +92,7 @@ export class Character extends Actor { systemData.mr.basis = Math.round((mu + kl + ko) / 5) systemData.mr.aktuell = systemData.mr.basis + (systemData.mr.mod ?? 0); systemData.gs.basis = 6; - systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from species + systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from spezien if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { diff --git a/src/module/documents/culture.mjs b/src/module/documents/culture.mjs new file mode 100644 index 00000000..98da9ab2 --- /dev/null +++ b/src/module/documents/culture.mjs @@ -0,0 +1,9 @@ +export class Culture extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/documents/species.mjs b/src/module/documents/species.mjs new file mode 100644 index 00000000..f1e0f707 --- /dev/null +++ b/src/module/documents/species.mjs @@ -0,0 +1,9 @@ +export class Species extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + } + +} diff --git a/src/module/sheets/CultureSheet.mjs b/src/module/sheets/CultureSheet.mjs new file mode 100644 index 00000000..abd78fda --- /dev/null +++ b/src/module/sheets/CultureSheet.mjs @@ -0,0 +1,54 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class CultureSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'culture'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: CultureSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/culture-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {CultureSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.masculineDemonym = context.document.system.masculineDemonym + context.feminineDemonym = context.document.system.feminineDemonym + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/ProfessionSheet.mjs b/src/module/sheets/ProfessionSheet.mjs new file mode 100644 index 00000000..dbaa2465 --- /dev/null +++ b/src/module/sheets/ProfessionSheet.mjs @@ -0,0 +1,55 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class ProfessionSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'species'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: ProfessionSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/profession-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {ProfessionSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.alias = context.document.system.alias + context.isOwner = context.document.owner + context.revealed = context.document.system.revealed + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/SpeciesSheet.mjs b/src/module/sheets/SpeciesSheet.mjs new file mode 100644 index 00000000..61c2999a --- /dev/null +++ b/src/module/sheets/SpeciesSheet.mjs @@ -0,0 +1,55 @@ +const {DocumentSheetV2, HandlebarsApplicationMixin} = foundry.applications.api + +export class SpeciesSheet extends HandlebarsApplicationMixin(DocumentSheetV2) { + + /** @inheritDoc */ + static DEFAULT_OPTIONS = { + position: {width: 520, height: 480}, + classes: ['dsa41', 'sheet', 'item', 'species'], + tag: 'form', + form: { + submitOnChange: true, + closeOnSubmit: false, + handler: SpeciesSheet.#onSubmitForm + }, + actions: { + editImage: DocumentSheetV2.DEFAULT_OPTIONS.actions.editImage, + } + } + + /** @inheritDoc */ + static PARTS = { + form: { + template: `systems/DSA_4-1/templates/item/species-sheet.hbs` + }, + } + + /** + * Handle form submission + * @this {SpeciesSheet} + * @param {SubmitEvent} event + * @param {HTMLFormElement} form + * @param {FormDataExtended} formData + */ + static async #onSubmitForm(event, form, formData) { + event.preventDefault() + + await this.document.update(formData.object) // Note: formData.object + } + + /** @override */ + async _prepareContext(options) { + + const context = await super._prepareContext(options) + context.system = context.document.system + + context.name = context.document.name + context.img = context.document.img + context.description = context.document.system.description + context.baseSpeed = context.document.baseSpeed + context.masculineDemonym = context.document.system.masculineDemonym + context.feminineDemonym = context.document.system.feminineDemonym + + return context + } +} \ No newline at end of file diff --git a/src/module/sheets/actions/action-manager.mjs b/src/module/sheets/actions/action-manager.mjs index 3e1aee6e..05205b5e 100644 --- a/src/module/sheets/actions/action-manager.mjs +++ b/src/module/sheets/actions/action-manager.mjs @@ -211,20 +211,17 @@ export class ActionManager { #hatWaffeinHand() { const item = this.actor.findEquipmentOnSlot("links") ?? this.actor.findEquipmentOnSlot("rechts") - console.log(item) return item } #hatMunition() { const item = this.actor.findEquipmentOnSlot("munition") const weapon = this.actor.findEquipmentOnSlot("fernkampf") - console.log(item?.system.quantity, weapon) return item } #hatFernkampfWaffeinHand(art) { const item = this.actor.findEquipmentOnSlot("fernkampf") - console.log(item) return item } @@ -238,8 +235,6 @@ export class ActionManager { evaluate() { let actionArray = [...this.#freeActions, ...this.#regularActions, ...this.#continuingActions] - - return actionArray.filter(action => action.eval()); } diff --git a/src/module/sheets/characterSheet.mjs b/src/module/sheets/characterSheet.mjs index 1075b200..d0b6e6ec 100644 --- a/src/module/sheets/characterSheet.mjs +++ b/src/module/sheets/characterSheet.mjs @@ -34,6 +34,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { roll: CharacterSheet.#dieRoll, editImage: ActorSheetV2.DEFAULT_OPTIONS.actions.editImage, openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument, + openCultureDocument: CharacterSheet.#openCultureDocument, + openSpeciesDocument: CharacterSheet.#openSpeciesDocument, + } } @@ -123,11 +126,19 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { * @param {MouseEvent} event */ static #openEmbeddedDocument(event) { - const dataset = event.target.parentElement.dataset + const dataset = event.target.dataset const id = dataset.itemId ?? dataset.id this.document.items.get(id).sheet.render(true) } + static #openCultureDocument() { + this.document.itemTypes["Culture"]?.[0]?.sheet.render(true) + } + + static #openSpeciesDocument() { + this.document.itemTypes["Species"]?.[0]?.sheet.render(true) + } + /** * Handle form submission * @this {AdvantageSheet} @@ -183,6 +194,26 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) { } }) + context.spezies = "" + if (actorData.itemTypes["Species"]?.[0]) { + const speciesData = actorData.itemTypes["Species"][0] + if (actorData.system.geschlecht === "männlich") { + context.spezies = speciesData.system.masculineDemonym + } else { + context.spezies = speciesData.system.feminineDemonym + } + } + + context.kultur = "" + if (actorData.itemTypes["Culture"]?.[0]) { + const cultureData = actorData.itemTypes["Culture"][0] + if (actorData.system.geschlecht === "männlich") { + context.kultur = cultureData.system.masculineDemonym + } else { + context.kultur = cultureData.system.feminineDemonym + } + } + context.originalName = actorData.name context.name = context.derived.name ?? actorData.name context.img = actorData.img diff --git a/src/module/xml-import/xml-import.mjs b/src/module/xml-import/xml-import.mjs index f24f3189..3427a1d2 100644 --- a/src/module/xml-import/xml-import.mjs +++ b/src/module/xml-import/xml-import.mjs @@ -1,7 +1,8 @@ import {LiturgyData} from "../data/miracle/liturgydata.mjs"; -import {BlessingDataModel} from "../data/blessing.mjs"; import {Blessing} from "../documents/blessing.mjs"; import {Profession} from "../documents/profession.mjs"; +import {Culture} from "../documents/culture.mjs"; +import {Species} from "../documents/species.mjs"; let months = [ "Praios", @@ -19,20 +20,48 @@ let months = [ "Namenloser Tag" ] +/** + * @typedef ImportOptions + * @property {Boolean} skipSpecies + * @property {Boolean} skipCulture + * @property {Boolean} skipProfessions + * @property {Boolean} skipAdvantages + * @property {Boolean} skipSpecialAbilities + * @property {Boolean} skipEquipment + * @property {Boolean} skipSpells + * @property {Boolean} skipLiturgies + * @property {Boolean} skipSkills + **/ /** * 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 + * @param {ImportOptions?} options the set of item types the import should skip */ -export async function importCharacter(actorId, file) { +export async function importCharacter(actorId, file, options = undefined) { 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(actor, rawJson) + + if (!options) { + options = { + skipSpecies: false, + skipCulture: false, + skipProfessions: false, + skipAdvantages: false, + skipSpecialAbilities: false, + skipEquipment: false, + skipSkills: false, + skipSpells: false, + skipLiturgies: false + } + } + + let characterJson = mapRawJson(actor, rawJson, options) actor.update(characterJson) } @@ -75,6 +104,38 @@ function getJsonFromXML(dom) { 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` +} + + async function addSkillFromCompendiumByNameToActor(talentName, taw, actor, combatStatistics, attributes) { const compendiumOfSkills = game.packs.get('DSA_4-1.talente'); const talentId = compendiumOfSkills.index.find(skill => skill.name === talentName) @@ -122,6 +183,7 @@ async function addAdvantageFromCompendiumByNameToActor(advantageName, advantageV } async function addSpellsFromCompendiumByNameToActor(spellName, zfw, representation, hauszauber, actor) { + const compendiumOfSpells = game.packs.get('DSA_4-1.spells'); const SCREAMING_NAME = spellName.toUpperCase() const spellId = compendiumOfSpells.index.find(spell => spell.name === SCREAMING_NAME) @@ -155,38 +217,17 @@ async function addLiturgiesFromCompendiumByNameToActor(liturgyName, actor) { } } -/** - * 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` -} - function mapSkills(actor, held, kampfwerte) { + if (actor.itemTypes["Skill"].length > 0) { + actor.itemTypes["Skill"].forEach(s => { + actor.items.get(s._id).delete() + }) + } + if (actor.itemTypes["Blessing"].length > 0) { + actor.itemTypes["Blessing"].forEach(p => { + actor.items.get(p._id).delete() + }) + } for (let talent in held.talentliste.talent) { talent = held.talentliste.talent[talent] @@ -213,6 +254,11 @@ function mapSkills(actor, held, kampfwerte) { } function mapAdvantages(actor, held) { + if (actor.itemTypes["Advantage"].length > 0) { + actor.itemTypes["Advantage"].forEach(a => { + actor.items.get(a._id).delete() + }) + } for (let advantage in held.vt.vorteil) { advantage = held.vt.vorteil[advantage] addAdvantageFromCompendiumByNameToActor(advantage.name, advantage.value, actor) @@ -220,20 +266,35 @@ function mapAdvantages(actor, held) { } function mapSpells(actor, held) { + if (actor.itemTypes["Spell"].length > 0) { + actor.itemTypes["Spell"].forEach(s => { + actor.items.get(s._id).delete() + }) + } for (let spell in held.zauberliste.zauber) { spell = held.zauberliste.zauber[spell] addSpellsFromCompendiumByNameToActor(spell.name, spell.value, spell.repraesentation, spell.hauszauber === "true", actor) } } -function mapMiracles(actor, liturgies) { +function mapLiturgies(actor, liturgies) { + if (actor.itemTypes["Liturgy"].length > 0) { + actor.itemTypes["Liturgy"].forEach(l => { + actor.items.get(l._id).delete() + }) + } for (let liturgy in liturgies) { liturgy = liturgies[liturgy] addLiturgiesFromCompendiumByNameToActor(liturgy.name, actor) } } -function mapProfessions(actor, professions) { +async function mapProfessions(actor, professions) { + if (actor.itemTypes["Profession"].length > 0) { + actor.itemTypes["Profession"].forEach(p => { + actor.items.get(p._id).delete() + }) + } if (professions.string) { professions = {hauptprofession: professions} } @@ -251,23 +312,88 @@ function mapProfessions(actor, professions) { ]) }) // actor.update({"system.meta.professions": professions}) +} +async function mapSpezies(actor, spezies) { + if (actor.itemTypes["Species"].length > 0) { + actor.itemTypes["Species"].forEach(s => { + actor.items.get(s._id).delete() + }) + } + const compendiumOfSpecies = game.packs.get('DSA_4-1.spezien'); + const speciesId = compendiumOfSpecies?.index.find(species => species.name === spezies.name) + + if (speciesId) { + const species = + await compendiumOfSpecies.getDocument(speciesId); + try { + await actor.createEmbeddedDocuments('Item', [species]) + } catch (e) { + } + } else { + actor.createEmbeddedDocuments('Item', [ + new Species({ + name: spezies.name, + type: "Species", + system: { + feminineDemonym: spezies.string, + masculineDemonym: spezies.string, + description: "Importiert", + } + }) + ]) + } + +} + +async function mapKultur(actor, kultur) { + if (actor.itemTypes["Culture"].length > 0) { + actor.itemTypes["Culture"].forEach(c => { + actor.items.get(c._id).delete() + }) + } + const compendiumOfCultures = game.packs.get('DSA_4-1.kulturen'); + const cultureId = compendiumOfCultures?.index.find(culture => culture.name === kultur.name) + + if (cultureId) { + const culture = + await compendiumOfCultures.getDocument(cultureId); + try { + await actor.createEmbeddedDocuments('Item', [culture]) + } catch (e) { + } + } else { + actor.createEmbeddedDocuments('Item', [ + new Culture({ + name: kultur.name, + type: "Culture", + system: { + variant: kultur.variante.name ?? "", + feminineDemonym: kultur.string, + masculineDemonym: kultur.string, + description: "Importiert", + } + }) + ]) + } } /** * parses a json into a fitting character-json + * @param {Character} actor * @param rawJson the json parsed from the Helden-Software XML + * @param {ImportOptions} options * @returns {{}} a json representation of the character */ -function mapRawJson(actor, rawJson) { +function mapRawJson(actor, rawJson, options) { 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 - mapProfessions(actor, held.basis.ausbildungen.ausbildung) + if (!options.skipSpecies) mapSpezies(actor, held.basis.rasse) // as string includes the demonymized form + if (!options.skipCulture) mapKultur(actor, held.basis.kultur) // as string includes the demonymized form + if (!options.skipProfessions) mapProfessions(actor, held.basis.ausbildungen.ausbildung) json.meta.geschlecht = held.basis.geschlecht.name json.meta.haarfarbe = held.basis.rasse.aussehen.haarfarbe json.meta.groesse = held.basis.rasse.groesse.value @@ -324,7 +450,7 @@ function mapRawJson(actor, rawJson) { aktuell: attribute.value } json.attribute.so = getAttributeJson(attributes, "Sozialstatus") - mapAdvantages(actor, held) + if (!options.skipAdvantages) mapAdvantages(actor, held) let specialAbilities = [] let liturgies = [] for (let specialAbility in held.sf.sonderfertigkeit) { @@ -372,9 +498,9 @@ function mapRawJson(actor, rawJson) { } json.kampfwerte = combatValues - mapSkills(actor, held, combatValues) - mapSpells(actor, held) - mapMiracles(actor, liturgies) + if (!options.skipSkills) mapSkills(actor, held, combatValues) + if (!options.skipSpells) mapSpells(actor, held) + if (!options.skipLiturgies) mapLiturgies(actor, liturgies) let notes = [] for (let note in held.kommentare) { diff --git a/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json b/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json new file mode 100644 index 00000000..f8c00cc0 --- /dev/null +++ b/src/packs/_source/kulturen/helden.model.kultur.Mittelreich.json @@ -0,0 +1,6 @@ +{ + "name": "helden.model.kultur.Mittelreich", + "masculineDemonym": "Mittelländische Landbevölkerung", + "feminineDemonym": "Mittelländische Landbevölkerung", + "description": "" +} \ No newline at end of file diff --git a/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json b/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json new file mode 100644 index 00000000..88b9b572 --- /dev/null +++ b/src/packs/_source/spezien/helden.model.rasse.Mittellaender.json @@ -0,0 +1,7 @@ +{ + "name": "helden.model.rasse.Mittellaender", + "masculineDemonym": "Mittelländer", + "feminineDemonym": "Mittelländerin", + "description": "", + "baseSpeed": 6 +} \ No newline at end of file diff --git a/src/packs/_source/zauber/MemorabiaFalsafir.json b/src/packs/_source/zauber/MemorabiaFalsafir.json index becc1728..04ce1171 100644 --- a/src/packs/_source/zauber/MemorabiaFalsafir.json +++ b/src/packs/_source/zauber/MemorabiaFalsafir.json @@ -26,7 +26,7 @@ "mod": "+7", "description": "Der Magier ersetzt die verdrängte Erinnerung wahlweise mit einer eigenen Erinnerung oder fügt das gestohlene Wissen des Opfers seiner eigenen Erinnerung hinzu.", "limit": "11" - }, + } }, "reversalis": "bringt die durch den MEMORABIA verdrängte Erinnerung wieder zurück.", "antimagie": "BEHERRSCHUNG BRECHEN hebt den Zauber auf und bringt die Erinnerung wieder zurück; in einer Zone dieses Zaubers kann der MEMORABIA nur erschwert gesprochen werden.", diff --git a/src/packs/_source/zauber/Windstille.json b/src/packs/_source/zauber/Windstille.json index 5bfbfb14..09e50f5e 100644 --- a/src/packs/_source/zauber/Windstille.json +++ b/src/packs/_source/zauber/Windstille.json @@ -1,7 +1,11 @@ { "seite": "287", "name": "WINDSTILLE", - "probe": ["KL", "CH", "KK"], + "probe": [ + "KL", + "CH", + "KK" + ], "technik": "Der Elf formt die Hände über seinem Kopf zu einem Dach, spricht 'rongra sala bian'dao' und breitet die Arme aus.", "zauberdauer": "30 Aktionen", "wirkung": "Der Zauber erschafft eine Zone völliger Windstille, unabhängig von der Windstärke außerhalb. Diese Zone bewegt sich mit dem Elfen. Innerhalb dieser Zone steht die Luft still – selbst Blätter und Rauch verharren. Geräusche tragen schlechter, Pfeile und Geschosse verlieren an Reichweite, und fliegende Wesen haben Mühe, sich zu bewegen. Die Zauberprobe ist um die aktuelle Windstärke (nach Beaufort-Skala) erschwert. Der Effekt wirkt bis zur Windstärke 12 (Orkan).", @@ -29,7 +33,11 @@ }, "reversalis": "Jede Luftbewegung innerhalb der Zone wird um ZfP*/2 Windstärken verstärkt, sodass schon ein leichtes Blasen einen kräftigen Wind erzeugen kann. Diese Variante kostet 10 AsP pro Spielrunde.", "antimagie": "VERÄNDERUNG AUFHEBEN oder LUFTBANN können den Zauber schwächen oder beenden. Befindet sich die Zone in einem Sturm, kann dieser abgeschwächt, aber nicht aufgehoben werden.", - "merkmal": ["Elementar (Luft)", "Umwelt"], + "merkmal": [ + "Elementar (Luft)", + "Umwelt" + ], "komplexität": "C", "repräsentation": "Elf 6, Mag, Dru (Mag) je 2", - "info": "WINDSTILLE gilt als Teil einer Hexalogie des Banns elementarer Gewalten, die vermutlich von el + "info": "WINDSTILLE gilt als Teil einer Hexalogie des Banns elementarer Gewalten, die vermutlich von el" +} diff --git a/src/packs/_source/zauber/XenographusSchriftenkunde.json b/src/packs/_source/zauber/XenographusSchriftenkunde.json index 753cffdc..73da6dda 100644 --- a/src/packs/_source/zauber/XenographusSchriftenkunde.json +++ b/src/packs/_source/zauber/XenographusSchriftenkunde.json @@ -17,4 +17,4 @@ "komplexität": "E", "repräsentation": "Mag 2", "info": "Der Zauber wurde erstmals in Punin dokumentiert und vermutlich aus einem alten Text über Rohals Systeme abgeleitet. Heute wird er in der Puniner Akademie, der Thorwaler Hellsichtschule und dem Khunchomer Artefaktmagier-Zirkel gelehrt. XENOGRAPHUS SCHRIFTENKUNDE wird vor allem von Gelehrten, Artefaktmagiern und Historikern genutzt, um uralte Texte, magische Runen oder verschlüsselte Aufzeichnungen zu entziffern. Der Zauber übersetzt jedoch keine Sprache und vermittelt auch kein echtes Sprachverständnis." -}, +} diff --git a/src/style/organisms/_culture-sheet.scss b/src/style/organisms/_culture-sheet.scss new file mode 100644 index 00000000..034e17b6 --- /dev/null +++ b/src/style/organisms/_culture-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.culture { + + section.culture { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/organisms/_profession-sheet.scss b/src/style/organisms/_profession-sheet.scss new file mode 100644 index 00000000..5c9a5023 --- /dev/null +++ b/src/style/organisms/_profession-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.profession { + + section.profession { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/organisms/_species-sheet.scss b/src/style/organisms/_species-sheet.scss new file mode 100644 index 00000000..dc0c31c6 --- /dev/null +++ b/src/style/organisms/_species-sheet.scss @@ -0,0 +1,26 @@ +.application.sheet.dsa41.item.species { + + section.species { + + display: flex; + flex-direction: column; + flex: 1; + + div { + flex: 0; + } + + div.editor { + flex: 1; + display: flex; + flex-direction: column; + + label { + flex: 0; + } + + } + + } + +} \ No newline at end of file diff --git a/src/style/styles.scss b/src/style/styles.scss index 97ef261f..32e2a996 100644 --- a/src/style/styles.scss +++ b/src/style/styles.scss @@ -20,3 +20,7 @@ @use "organisms/skill-sheet"; @use "organisms/active-effect-sheet"; @use "organisms/advantage-sheet"; +@use "organisms/culture-sheet"; +@use "organisms/species-sheet"; +@use "organisms/profession-sheet"; + diff --git a/src/system.json b/src/system.json index ae1ac3de..378e2ba9 100644 --- a/src/system.json +++ b/src/system.json @@ -92,6 +92,30 @@ "type": "Item", "path": "packs/wunden", "private": false + }, + { + "name": "Professions", + "label": "Professionen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/professionen", + "private": false + }, + { + "name": "Species", + "label": "Rassen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/spezien", + "private": false + }, + { + "name": "Cultures", + "label": "Kulturen", + "system": "DSA_4-1", + "type": "Item", + "path": "packs/kulturen", + "private": false } ], "languages": [ @@ -127,6 +151,19 @@ } }, "Item": { + "Culture": { + "htmlFields": [ + "description" + ] + }, + "Species": { + "htmlFields": [ + "description" + ], + "numberFields": [ + "baseSpeed" + ] + }, "Profession": { "htmlFields": [ "description" diff --git a/src/templates/actor/character/main-sheet.hbs b/src/templates/actor/character/main-sheet.hbs index 9f4c6003..ec7e1e6a 100644 --- a/src/templates/actor/character/main-sheet.hbs +++ b/src/templates/actor/character/main-sheet.hbs @@ -8,11 +8,11 @@
- {{system.meta.spezies}} - {{system.meta.kultur}} + {{spezies}} + {{kultur}} {{#each professions}} - {{this.name}} + {{this.name}} {{/each}}
diff --git a/src/templates/item/culture-sheet.hbs b/src/templates/item/culture-sheet.hbs new file mode 100644 index 00000000..b3b864ea --- /dev/null +++ b/src/templates/item/culture-sheet.hbs @@ -0,0 +1,21 @@ +
+
+ + +
+
+ + +
+
+ + + {{{description}}} + +
+
\ No newline at end of file diff --git a/src/templates/item/profession-sheet.hbs b/src/templates/item/profession-sheet.hbs new file mode 100644 index 00000000..dabd4e73 --- /dev/null +++ b/src/templates/item/profession-sheet.hbs @@ -0,0 +1,21 @@ +
+
+ + + {{#if isOwner}} + {{/if}} + +
+
+ + + {{{system.description}}} + +
+
\ No newline at end of file diff --git a/src/templates/item/species-sheet.hbs b/src/templates/item/species-sheet.hbs new file mode 100644 index 00000000..7f45c5d9 --- /dev/null +++ b/src/templates/item/species-sheet.hbs @@ -0,0 +1,25 @@ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + {{{description}}} + +
+
\ No newline at end of file -- 2.43.0