Merged with main

This commit is contained in:
WBHarry 2025-07-08 21:20:30 +02:00
commit f679e87a4b
23 changed files with 317 additions and 118 deletions

View file

@ -1,6 +1,6 @@
import { damageKeyToNumber, getDamageLabel } from '../../helpers/utils.mjs';
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
const { DialogV2, ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class DamageReductionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(resolve, reject, actor, damage, damageType) {
@ -223,9 +223,17 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
async close(fromSave) {
if (!fromSave) {
this.reject();
this.resolve();
}
await super.close({});
}
static async armorStackQuery({ actorId, damage, type }) {
return new Promise(async (resolve, reject) => {
const actor = await fromUuid(actorId);
if (!actor || !actor?.isOwner) reject();
new DamageReductionDialog(resolve, reject, actor, damage, type).render({ force: true });
});
}
}

View file

@ -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 });
}

View file

@ -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 });
}

View file

@ -92,9 +92,7 @@ export default class AdversarySheet extends DHBaseActorSheet {
const cls = getDocumentClass('ChatMessage');
const systemData = {
name: game.i18n.localize('DAGGERHEART.GENERAL.Experience.single'),
description: `${experience.name} ${
experience.modifier < 0 ? experience.modifier : `+${experience.modifier}`
}`
description: `${experience.name} ${experience.total.signedString()}`
};
const msg = new cls({
type: 'abilityUse',

View file

@ -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 [
{
@ -249,7 +259,23 @@ export default class CharacterSheet extends DHBaseActorSheet {
{
name: 'CONTROLS.CommonDelete',
icon: '<i class="fa-solid fa-trash"></i>',
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();
}
}
];
}
@ -495,7 +521,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: {

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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

View file

@ -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;
}

View file

@ -215,7 +215,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
if (message.system.onSave && message.system.targets.find(t => t.id === target.id)?.saved?.success === true)
damage = Math.ceil(damage * (CONFIG.DH.ACTIONS.damageOnSave[message.system.onSave]?.mod ?? 1));
await target.actor.takeDamage(damage, message.system.roll.type);
target.actor.takeDamage(damage, message.system.roll.type);
}
};
@ -227,7 +227,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelected'));
for (var target of targets) {
await target.actor.takeHealing([{ value: message.system.roll.total, type: message.system.roll.type }]);
target.actor.takeHealing([{ value: message.system.roll.total, type: message.system.roll.type }]);
}
};