Merge branch 'main' into development

This commit is contained in:
WBHarry 2025-08-19 20:58:13 +02:00
commit fa8bd63614
16 changed files with 77 additions and 30 deletions

View file

@ -8,7 +8,7 @@ import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs'; import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs'; import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs';
import { DHRoll, DualityRoll, D20Roll, DamageRoll } from './module/dice/_module.mjs'; import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll } from './module/dice/_module.mjs';
import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'; import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs';
import { registerCountdownHooks } from './module/data/countdowns.mjs'; import { registerCountdownHooks } from './module/data/countdowns.mjs';
import { import {
@ -49,9 +49,7 @@ Hooks.once('init', () => {
DamageRoll: DamageRoll DamageRoll: DamageRoll
}; };
CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, DHRoll, DualityRoll, D20Roll, DamageRoll]; CONFIG.Dice.rolls = [BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll];
Roll.CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRoll.hbs';
Roll.TOOLTIP_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs';
CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate; CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate;
const { DocumentSheetConfig } = foundry.applications.apps; const { DocumentSheetConfig } = foundry.applications.apps;

View file

@ -68,6 +68,7 @@ export default class AdversarySheet extends DHBaseActorSheet {
htmlElement.querySelectorAll('.inventory-item-resource').forEach(element => { htmlElement.querySelectorAll('.inventory-item-resource').forEach(element => {
element.addEventListener('change', this.updateItemResource.bind(this)); element.addEventListener('change', this.updateItemResource.bind(this));
element.addEventListener('click', e => e.stopPropagation());
}); });
} }

View file

@ -122,6 +122,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
htmlElement.querySelectorAll('.inventory-item-resource').forEach(element => { htmlElement.querySelectorAll('.inventory-item-resource').forEach(element => {
element.addEventListener('change', this.updateItemResource.bind(this)); element.addEventListener('change', this.updateItemResource.bind(this));
element.addEventListener('click', e => e.stopPropagation());
}); });
htmlElement.querySelectorAll('.inventory-item-quantity').forEach(element => { htmlElement.querySelectorAll('.inventory-item-quantity').forEach(element => {
element.addEventListener('change', this.updateItemQuantity.bind(this)); element.addEventListener('change', this.updateItemQuantity.bind(this));

View file

@ -124,7 +124,7 @@ export default function DHApplicationMixin(Base) {
} }
} }
], ],
dragDrop: [], dragDrop: [{ dragSelector: '.inventory-item[data-type="effect"]', dropSelector: null }],
tagifyConfigs: [] tagifyConfigs: []
}; };
@ -289,14 +289,37 @@ export default function DHApplicationMixin(Base) {
* @param {DragEvent} event * @param {DragEvent} event
* @protected * @protected
*/ */
_onDragStart(event) {} async _onDragStart(event) {
const inventoryItem = event.currentTarget.closest('.inventory-item');
if (inventoryItem) {
const { type, itemUuid } = inventoryItem.dataset;
if (type === 'effect') {
const effect = await foundry.utils.fromUuid(itemUuid);
const effectData = {
type: 'ActiveEffect',
data: { ...effect.toObject(), _id: null },
fromInternal: this.document.uuid
};
event.dataTransfer.setData('text/plain', JSON.stringify(effectData));
event.dataTransfer.setDragImage(inventoryItem.querySelector('img'), 60, 0);
}
}
}
/** /**
* Handle drop event. * Handle drop event.
* @param {DragEvent} event * @param {DragEvent} event
* @protected * @protected
*/ */
_onDrop(event) {} _onDrop(event) {
event.stopPropagation();
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
if (data.fromInternal === this.document.uuid) return;
if (data.type === 'ActiveEffect') {
this.document.createEmbeddedDocuments('ActiveEffect', [data.data]);
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Context Menu */ /* Context Menu */

View file

@ -198,6 +198,8 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
}; };
event.dataTransfer.setData('text/plain', JSON.stringify(attackData)); event.dataTransfer.setData('text/plain', JSON.stringify(attackData));
event.dataTransfer.setDragImage(attackItem.querySelector('img'), 60, 0); event.dataTransfer.setDragImage(attackItem.querySelector('img'), 60, 0);
} else if (this.document.type !== 'environment') {
super._onDragStart(event);
} }
} }
} }

View file

@ -270,6 +270,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
}; };
event.dataTransfer.setData('text/plain', JSON.stringify(actionData)); event.dataTransfer.setData('text/plain', JSON.stringify(actionData));
event.dataTransfer.setDragImage(actionItem.querySelector('img'), 60, 0); event.dataTransfer.setDragImage(actionItem.querySelector('img'), 60, 0);
} else {
super._onDragStart(event);
} }
} }
} }
@ -279,6 +281,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
* @param {DragEvent} event - The drag event * @param {DragEvent} event - The drag event
*/ */
async _onDrop(event) { async _onDrop(event) {
super._onDrop(event);
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
if (data.fromInternal) return; if (data.fromInternal) return;

View file

@ -41,7 +41,7 @@ export default function ItemAttachmentSheet(Base) {
} }
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
const attachmentsSection = event.target.closest('.attachments-section'); const attachmentsSection = event.target.closest('.attachments-section');
if (!attachmentsSection) return super._onDrop(event); if (!attachmentsSection) return super._onDrop(event);

View file

@ -27,6 +27,9 @@ export default class AncestrySheet extends DHHeritageSheet {
* @param {DragEvent} event - The drag event * @param {DragEvent} event - The drag event
*/ */
async _onDrop(event) { async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
if (data.type === 'ActiveEffect') return super._onDrop(event);
const target = event.target.closest('fieldset.drop-section'); const target = event.target.closest('fieldset.drop-section');
const typeField = const typeField =
this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature']; this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature'];

View file

@ -115,16 +115,17 @@ export default class ClassSheet extends DHBaseItemSheet {
async _onDrop(event) { async _onDrop(event) {
event.stopPropagation(); event.stopPropagation();
const data = TextEditor.getDragEventData(event); const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid); const item = data.data ?? (await fromUuid(data.uuid));
const itemType = data.data ? data.type : item.type;
const target = event.target.closest('fieldset.drop-section'); const target = event.target.closest('fieldset.drop-section');
if (item.type === 'subclass') { if (itemType === 'subclass') {
await this.document.update({ await this.document.update({
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
}); });
} else if (item.type === 'feature') { } else if (['feature', 'ActiveEffect'].includes(itemType)) {
super._onDrop(event); super._onDrop(event);
} else if (this.document.parent?.type !== 'character') { } else if (this.document.parent?.type !== 'character') {
if (item.type === 'weapon') { if (itemType === 'weapon') {
if (target.classList.contains('primary-weapon-section')) { if (target.classList.contains('primary-weapon-section')) {
if (!item.system.secondary) if (!item.system.secondary)
await this.document.update({ await this.document.update({
@ -136,21 +137,21 @@ export default class ClassSheet extends DHBaseItemSheet {
'system.characterGuide.suggestedSecondaryWeapon': item.uuid 'system.characterGuide.suggestedSecondaryWeapon': item.uuid
}); });
} }
} else if (item.type === 'armor') { } else if (itemType === 'armor') {
if (target.classList.contains('armor-section')) { if (target.classList.contains('armor-section')) {
await this.document.update({ await this.document.update({
'system.characterGuide.suggestedArmor': item.uuid 'system.characterGuide.suggestedArmor': item.uuid
}); });
} }
} else if (target.classList.contains('choice-a-section')) { } else if (target.classList.contains('choice-a-section')) {
if (item.type === 'loot' || item.type === 'consumable') { if (itemType === 'loot' || itemType === 'consumable') {
const filteredChoiceA = this.document.system.inventory.choiceA; const filteredChoiceA = this.document.system.inventory.choiceA;
if (filteredChoiceA.length < 2) if (filteredChoiceA.length < 2)
await this.document.update({ await this.document.update({
'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid] 'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid]
}); });
} }
} else if (item.type === 'loot') { } else if (itemType === 'loot') {
if (target.classList.contains('take-section')) { if (target.classList.contains('take-section')) {
const filteredTake = this.document.system.inventory.take.filter(x => x); const filteredTake = this.document.system.inventory.take.filter(x => x);
if (filteredTake.length < 3) if (filteredTake.length < 3)

View file

@ -163,7 +163,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
const hasRoll = this.getUseHasRoll(byPass); const hasRoll = this.getUseHasRoll(byPass);
return { return {
event, event,
title: `${this.item.name}: ${this.name}`, title: `${this.item.name}: ${game.i18n.localize(this.name)}`,
source: { source: {
item: this.item._id, item: this.item._id,
action: this._id, action: this._id,
@ -209,15 +209,15 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
} }
async consume(config, successCost = false) { async consume(config, successCost = false) {
const actor= this.actor.system.partner ?? this.actor, const actor = this.actor.system.partner ?? this.actor,
usefulResources = { usefulResources = {
...foundry.utils.deepClone(actor.system.resources), ...foundry.utils.deepClone(actor.system.resources),
fear: { fear: {
value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), value: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear, max: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear,
reversed: false reversed: false
} }
}; };
for (var cost of config.costs) { for (var cost of config.costs) {
if (cost.keyIsID) { if (cost.keyIsID) {

View file

@ -1,3 +1,4 @@
export { default as BaseRoll } from './baseRoll.mjs';
export { default as D20Roll } from './d20Roll.mjs'; export { default as D20Roll } from './d20Roll.mjs';
export { default as DamageRoll } from './damageRoll.mjs'; export { default as DamageRoll } from './damageRoll.mjs';
export { default as DHRoll } from './dhRoll.mjs'; export { default as DHRoll } from './dhRoll.mjs';

7
module/dice/baseRoll.mjs Normal file
View file

@ -0,0 +1,7 @@
export default class BaseRoll extends Roll {
/** @inheritdoc */
static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRoll.hbs';
/** @inheritdoc */
static TOOLTIP_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs';
}

View file

@ -13,6 +13,10 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */ /* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
const html = await super.renderHTML({ actor: actorData, author: this.author }); const html = await super.renderHTML({ actor: actorData, author: this.author });
if (this.flags.core?.RollTable) {
html.querySelector('.roll-buttons.apply-buttons').remove();
}
this.enrichChatMessage(html); this.enrichChatMessage(html);
this.addChatListeners(html); this.addChatListeners(html);

View file

@ -2,7 +2,7 @@
"id": "daggerheart", "id": "daggerheart",
"title": "Daggerheart", "title": "Daggerheart",
"description": "An unofficial implementation of the Daggerheart system", "description": "An unofficial implementation of the Daggerheart system",
"version": "1.0.5", "version": "1.0.6",
"compatibility": { "compatibility": {
"minimum": "13", "minimum": "13",
"verified": "13.347", "verified": "13.347",

View file

@ -8,7 +8,9 @@
<h4 class="dice-total">{{total}}</h4> <h4 class="dice-total">{{total}}</h4>
</div> </div>
</div> </div>
<div class="roll-buttons apply-buttons"> {{#unless flags.core.RollTable}}
<button class="simple-roll-button">{{localize "DAGGERHEART.UI.Chat.damageRoll.dealDamage"}}</button> <div class="roll-buttons apply-buttons">
<button class="simple-roll-button" data-type="healing">{{localize "DAGGERHEART.UI.Chat.healingRoll.applyHealing"}}</button> <button class="simple-roll-button">{{localize "DAGGERHEART.UI.Chat.damageRoll.dealDamage"}}</button>
</div> <button class="simple-roll-button" data-type="healing">{{localize "DAGGERHEART.UI.Chat.healingRoll.applyHealing"}}</button>
</div>
{{/unless}}

View file

@ -1,5 +1,5 @@
<div class="daggerheart dh-style tooltip"> <div class="daggerheart dh-style tooltip">
<h2 class="tooltip-title">{{item.name}}</h2> <h2 class="tooltip-title">{{localize item.name}}</h2>
<img class="tooltip-image" src="{{item.img}}" /> <img class="tooltip-image" src="{{item.img}}" />
<div class="tooltip-description">{{{description}}}</div> <div class="tooltip-description">{{{description}}}</div>
{{#if item.uses.max}} {{#if item.uses.max}}