- +{{experience.modifier}}
+ +{{experience.total}}
From 61f04df765102dfb9b25d7d11042dfdbc160ae51 Mon Sep 17 00:00:00 2001
From: WBHarry <89362246+WBHarry@users.noreply.github.com>
Date: Tue, 8 Jul 2025 20:04:54 +0200
Subject: [PATCH 2/4] 289 - Confirm Delete Dialogs (#298)
* Added confirm dialogs to delete
* Localization fix
---
lang/en.json | 4 +++
.../sheets-configs/adversary-settings.mjs | 12 +++++++++
.../sheets-configs/environment-settings.mjs | 22 ++++++++++++---
.../applications/sheets/actors/character.mjs | 22 ++++++++++++---
.../applications/sheets/api/actor-setting.mjs | 5 +++-
.../sheets/api/application-mixin.mjs | 19 +++++++++++--
module/applications/sheets/api/base-item.mjs | 27 +++++++++++++++++++
7 files changed, 101 insertions(+), 10 deletions(-)
diff --git a/lang/en.json b/lang/en.json
index 857a9387..75c8cfa7 100755
--- a/lang/en.json
+++ b/lang/en.json
@@ -213,6 +213,10 @@
"encounter": "Encounter"
}
},
+ "DeleteConfirmation": {
+ "title": "Delete {type} - {name}",
+ "text": "Are you sure you want to delete {name}?"
+ },
"DamageReduction": {
"armorMarks": "Armor Marks",
"armorWithStress": "Spend 1 stress to use an extra mark",
diff --git a/module/applications/sheets-configs/adversary-settings.mjs b/module/applications/sheets-configs/adversary-settings.mjs
index d95e6129..57deea25 100644
--- a/module/applications/sheets-configs/adversary-settings.mjs
+++ b/module/applications/sheets-configs/adversary-settings.mjs
@@ -70,6 +70,18 @@ export default class DHAdversarySettings extends DHBaseActorSettings {
* @type {ApplicationClickAction}
*/
static async #removeExperience(_, target) {
+ const experience = this.actor.system.experiences[target.dataset.experience];
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: game.i18n.localize(`DAGGERHEART.GENERAL.Experience.single`),
+ name: experience.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: experience.name })
+ });
+ if (!confirmed) return;
+
await this.actor.update({ [`system.experiences.-=${target.dataset.experience}`]: null });
}
diff --git a/module/applications/sheets-configs/environment-settings.mjs b/module/applications/sheets-configs/environment-settings.mjs
index d0ca897a..7422f5fc 100644
--- a/module/applications/sheets-configs/environment-settings.mjs
+++ b/module/applications/sheets-configs/environment-settings.mjs
@@ -82,10 +82,24 @@ export default class DHEnvironmentSettings extends DHBaseActorSettings {
static async #deleteAdversary(event, target) {
const adversaryKey = target.dataset.adversary;
const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries`;
- console.log(target.dataset.potentialAdversar);
- const newAdversaries = foundry.utils
- .getProperty(this.actor, path)
- .filter(x => x && (x?.uuid ?? x) !== adversaryKey);
+ const property = foundry.utils.getProperty(this.actor, path);
+ const adversary = property.find(x => (x?.uuid ?? x) === adversaryKey);
+
+ if (adversary) {
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: game.i18n.localize('TYPES.Actor.adversary'),
+ name: adversary.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: adversary.name })
+ });
+
+ if (!confirmed) return;
+ }
+
+ const newAdversaries = property.filter(x => x && (x?.uuid ?? x) !== adversaryKey);
await this.actor.update({ [path]: newAdversaries });
}
diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs
index 02e693d7..a77fe71f 100644
--- a/module/applications/sheets/actors/character.mjs
+++ b/module/applications/sheets/actors/character.mjs
@@ -249,7 +249,23 @@ export default class CharacterSheet extends DHBaseActorSheet {
{
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Delete',
icon: '
',
- callback: el => getItem(el).delete()
+ callback: async el => {
+ const item = getItem(el);
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: game.i18n.localize(`TYPES.${item.documentName}.${item.type}`),
+ name: item.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', {
+ name: item.name
+ })
+ });
+ if (!confirmed) return;
+
+ item.delete();
+ }
}
];
}
@@ -372,7 +388,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
li.hidden = !(menu.has(item.id) && matchesSearch);
}
}
-
+
/* -------------------------------------------- */
/* Filter Menus */
/* -------------------------------------------- */
@@ -495,7 +511,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
const config = {
event: event,
title: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`,
- headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilitychecktitle', {
+ headerTitle: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: abilityLabel
}),
roll: {
diff --git a/module/applications/sheets/api/actor-setting.mjs b/module/applications/sheets/api/actor-setting.mjs
index 50e2b0a9..79aa1c37 100644
--- a/module/applications/sheets/api/actor-setting.mjs
+++ b/module/applications/sheets/api/actor-setting.mjs
@@ -42,9 +42,12 @@ export default class DHBaseActorSettings extends DHApplicationMixin(DocumentShee
/**@inheritdoc */
async _prepareContext(options) {
const context = await super._prepareContext(options);
- context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
context.isNPC = this.actor.isNPC;
+ if (context.systemFields.attack) {
+ context.systemFields.attack.fields = this.actor.system.attack.schema.fields;
+ }
+
return context;
}
}
diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs
index d0ef63d6..0e5f211d 100644
--- a/module/applications/sheets/api/application-mixin.mjs
+++ b/module/applications/sheets/api/application-mixin.mjs
@@ -218,7 +218,6 @@ export default function DHApplicationMixin(Base) {
*/
static async #createDoc(event, button) {
const { documentClass, type } = button.dataset;
- console.log(documentClass, type);
const parent = this.document;
const cls = getDocumentClass(documentClass);
@@ -250,7 +249,23 @@ export default function DHApplicationMixin(Base) {
*/
static async #deleteDoc(_event, button) {
const { type, docId } = button.dataset;
- await this.document.getEmbeddedDocument(type, docId, { strict: true }).delete();
+ const document = this.document.getEmbeddedDocument(type, docId, { strict: true });
+ const typeName = game.i18n.localize(
+ document.type === 'base' ? `DOCUMENT.${type}` : `TYPES.${type}.${document.type}`
+ );
+
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: typeName,
+ name: document.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: document.name })
+ });
+ if (!confirmed) return;
+
+ await document.delete();
}
}
diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs
index f9d52025..d624acc6 100644
--- a/module/applications/sheets/api/base-item.mjs
+++ b/module/applications/sheets/api/base-item.mjs
@@ -139,6 +139,19 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
static async #removeAction(event, button) {
event.stopPropagation();
const actionIndex = button.closest('[data-index]').dataset.index;
+ const action = this.document.system.actions[actionIndex];
+
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
+ name: action.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: action.name })
+ });
+ if (!confirmed) return;
+
await this.document.update({
'system.actions': this.document.system.actions.filter((_, index) => index !== Number.parseInt(actionIndex))
});
@@ -180,6 +193,20 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
static async #removeFeature(event, button) {
event.stopPropagation();
const target = button.closest('.feature-item');
+ const feature = this.document.system.features.find(x => x && x.id === target.id);
+
+ if (feature) {
+ const confirmed = await foundry.applications.api.DialogV2.confirm({
+ window: {
+ title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
+ type: game.i18n.localize(`TYPES.Item.feature`),
+ name: feature.name
+ })
+ },
+ content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: feature.name })
+ });
+ if (!confirmed) return;
+ }
await this.document.update({
'system.features': this.document.system.features
From 861dfd977dbae69ccd840196ea4e8902e2ce1f02 Mon Sep 17 00:00:00 2001
From: WBHarry <89362246+WBHarry@users.noreply.github.com>
Date: Tue, 8 Jul 2025 21:01:28 +0200
Subject: [PATCH 3/4] Beastform Improvements (#294)
* BeastformEffect is editable. Added SubjectTexture field.
* Using handlebars disabled helper
---
lang/en.json | 1 +
.../applications/sheets/actors/character.mjs | 12 +++-
.../applications/sheets/items/beastform.mjs | 13 +++-
module/data/activeEffect/beastformEffect.mjs | 10 +++
module/data/item/beastform.mjs | 65 ++++++++++++-------
templates/sheets/global/tabs/tab-effects.hbs | 2 +-
templates/sheets/items/beastform/settings.hbs | 10 +--
7 files changed, 81 insertions(+), 32 deletions(-)
diff --git a/lang/en.json b/lang/en.json
index 75c8cfa7..797781d8 100755
--- a/lang/en.json
+++ b/lang/en.json
@@ -1129,6 +1129,7 @@
"examples": { "label": "Examples" },
"advantageOn": { "label": "Gain Advantage On" },
"tokenImg": { "label": "Token Image" },
+ "tokenRingImg": { "label": "Subject Texture" },
"tokenSize": {
"placeholder": "Using character dimensions",
"height": { "label": "Height" },
diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs
index a77fe71f..c24bcfec 100644
--- a/module/applications/sheets/actors/character.mjs
+++ b/module/applications/sheets/actors/character.mjs
@@ -188,7 +188,17 @@ export default class CharacterSheet extends DHBaseActorSheet {
* @param {HTMLElement} el
* @returns {foundry.documents.Item?}
*/
- const getItem = el => this.actor.items.get(el.closest('[data-item-id]')?.dataset.itemId);
+ const getItem = element => {
+ const listElement = (element.target ?? element).closest('[data-item-id]');
+ const itemId = listElement.dataset.itemId;
+
+ switch (listElement.dataset.type) {
+ case 'effect':
+ return this.document.effects.get(itemId);
+ default:
+ return this.document.items.get(itemId);
+ }
+ };
return [
{
diff --git a/module/applications/sheets/items/beastform.mjs b/module/applications/sheets/items/beastform.mjs
index e3b72d01..194f3ab1 100644
--- a/module/applications/sheets/items/beastform.mjs
+++ b/module/applications/sheets/items/beastform.mjs
@@ -30,8 +30,17 @@ export default class BeastformSheet extends DHBaseItemSheet {
};
/**@inheritdoc */
- async _preparePartContext(partId, context) {
- await super._preparePartContext(partId, context);
+ async _prepareContext(_options) {
+ const context = await super._prepareContext(_options);
+
+ context.document = context.document.toObject();
+ context.document.effects = this.document.effects.map(effect => {
+ const data = effect.toObject();
+ data.id = effect.id;
+ if (effect.type === 'beastform') data.mandatory = true;
+
+ return data;
+ });
return context;
}
diff --git a/module/data/activeEffect/beastformEffect.mjs b/module/data/activeEffect/beastformEffect.mjs
index 3aa25bef..6445f65d 100644
--- a/module/data/activeEffect/beastformEffect.mjs
+++ b/module/data/activeEffect/beastformEffect.mjs
@@ -10,6 +10,11 @@ export default class BeastformEffect extends foundry.abstract.TypeDataModel {
base64: false,
nullable: true
}),
+ tokenRingImg: new fields.FilePathField({
+ initial: 'icons/svg/mystery-man.svg',
+ categories: ['IMAGE'],
+ base64: false
+ }),
tokenSize: new fields.SchemaField({
height: new fields.NumberField({ integer: true, nullable: true }),
width: new fields.NumberField({ integer: true, nullable: true })
@@ -28,6 +33,11 @@ export default class BeastformEffect extends foundry.abstract.TypeDataModel {
width: this.characterTokenData.tokenSize.width,
texture: {
src: this.characterTokenData.tokenImg
+ },
+ ring: {
+ subject: {
+ texture: this.characterTokenData.tokenRingImg
+ }
}
};
diff --git a/module/data/item/beastform.mjs b/module/data/item/beastform.mjs
index 2eb871ec..b7ea5cb9 100644
--- a/module/data/item/beastform.mjs
+++ b/module/data/item/beastform.mjs
@@ -3,7 +3,7 @@ import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayFie
import BaseDataItem from './base.mjs';
export default class DHBeastform extends BaseDataItem {
- static LOCALIZATION_PREFIXES = ['DAGGERHEART.Sheets.Beastform'];
+ static LOCALIZATION_PREFIXES = ['DAGGERHEART.ITEMS.Beastform'];
/** @inheritDoc */
static get metadata() {
@@ -29,12 +29,17 @@ export default class DHBeastform extends BaseDataItem {
categories: ['IMAGE'],
base64: false
}),
+ tokenRingImg: new fields.FilePathField({
+ initial: 'icons/svg/mystery-man.svg',
+ categories: ['IMAGE'],
+ base64: false
+ }),
tokenSize: new fields.SchemaField({
height: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true }),
width: new fields.NumberField({ integer: true, min: 1, initial: null, nullable: true })
}),
examples: new fields.StringField(),
- advantageOn: new fields.ArrayField(new fields.StringField()),
+ advantageOn: new fields.StringField(),
features: new ForeignDocumentUUIDArrayField({ type: 'Item' })
};
}
@@ -56,40 +61,54 @@ export default class DHBeastform extends BaseDataItem {
'Item',
this.features.map(x => x.toObject())
);
- const effects = await this.parent.parent.createEmbeddedDocuments(
+
+ const extraEffects = await this.parent.parent.createEmbeddedDocuments(
'ActiveEffect',
- this.parent.effects.map(x => x.toObject())
+ this.parent.effects.filter(x => x.type !== 'beastform').map(x => x.toObject())
);
- await this.parent.parent.createEmbeddedDocuments('ActiveEffect', [
- {
- type: 'beastform',
- name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'),
- img: 'icons/creatures/abilities/paw-print-pair-purple.webp',
- system: {
- isBeastform: true,
- characterTokenData: {
- tokenImg: this.parent.parent.prototypeToken.texture.src,
- tokenSize: {
- height: this.parent.parent.prototypeToken.height,
- width: this.parent.parent.prototypeToken.width
- }
- },
- advantageOn: this.advantageOn,
- featureIds: features.map(x => x.id),
- effectIds: effects.map(x => x.id)
- }
+ const beastformEffect = this.parent.effects.find(x => x.type === 'beastform');
+ await beastformEffect.updateSource({
+ system: {
+ characterTokenData: {
+ tokenImg: this.parent.parent.prototypeToken.texture.src,
+ tokenRingImg: this.parent.parent.prototypeToken.ring.subject.texture,
+ tokenSize: {
+ height: this.parent.parent.prototypeToken.height,
+ width: this.parent.parent.prototypeToken.width
+ }
+ },
+ advantageOn: this.advantageOn,
+ featureIds: features.map(x => x.id),
+ effectIds: extraEffects.map(x => x.id)
}
- ]);
+ });
+
+ await this.parent.parent.createEmbeddedDocuments('ActiveEffect', [beastformEffect.toObject()]);
await updateActorTokens(this.parent.parent, {
height: this.tokenSize.height,
width: this.tokenSize.width,
texture: {
src: this.tokenImg
+ },
+ ring: {
+ subject: {
+ texture: this.tokenRingImg
+ }
}
});
return false;
}
+
+ _onCreate() {
+ this.parent.createEmbeddedDocuments('ActiveEffect', [
+ {
+ type: 'beastform',
+ name: game.i18n.localize('DAGGERHEART.ITEMS.Beastform.beastformEffect'),
+ img: 'icons/creatures/abilities/paw-print-pair-purple.webp'
+ }
+ ]);
+ }
}
diff --git a/templates/sheets/global/tabs/tab-effects.hbs b/templates/sheets/global/tabs/tab-effects.hbs
index 744ef8e1..a75f1b0b 100644
--- a/templates/sheets/global/tabs/tab-effects.hbs
+++ b/templates/sheets/global/tabs/tab-effects.hbs
@@ -17,7 +17,7 @@
{{effect.name}}
{{/each}}
diff --git a/templates/sheets/items/beastform/settings.hbs b/templates/sheets/items/beastform/settings.hbs
index 78af825f..dec7d134 100644
--- a/templates/sheets/items/beastform/settings.hbs
+++ b/templates/sheets/items/beastform/settings.hbs
@@ -8,11 +8,7 @@
{{formGroup systemFields.examples value=source.system.examples localize=true}}