mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-07-22 02:19:54 +02:00
Merge branch 'main' into rework/chat-message-damage
This commit is contained in:
commit
c90c6afc19
46 changed files with 775 additions and 466 deletions
|
|
@ -185,8 +185,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
|
||||
if (result === undefined) return;
|
||||
|
||||
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||
.expandRollMessage?.desc;
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
|
||||
const msg = {
|
||||
|
|
@ -202,7 +200,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
|
|||
img: this.selectedMove.img,
|
||||
description: game.i18n.localize(this.selectedMove.description),
|
||||
result: result,
|
||||
open: autoExpandDescription ? 'open' : '',
|
||||
showRiskItAllButton: this.showRiskItAllButton,
|
||||
riskItAllButtonLabel: this.riskItAllButtonLabel,
|
||||
riskItAllHope: this.riskItAllHope
|
||||
|
|
|
|||
|
|
@ -196,9 +196,6 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
.filter(x => x.testUserPermission(game.user, 'LIMITED'))
|
||||
.filter(x => x.uuid !== this.actor.uuid);
|
||||
|
||||
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||
.expandRollMessage?.desc;
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = {
|
||||
user: game.user.id,
|
||||
|
|
@ -219,8 +216,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
actor: { name: this.actor.name, img: this.actor.img },
|
||||
moves: moves,
|
||||
characters: characters,
|
||||
selfId: this.actor.uuid,
|
||||
open: autoExpandDescription ? 'open' : ''
|
||||
selfId: this.actor.uuid
|
||||
}
|
||||
),
|
||||
flags: {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
addFeature: DHBaseItemSheet.#addFeature,
|
||||
deleteFeature: DHBaseItemSheet.#deleteFeature,
|
||||
addResource: DHBaseItemSheet.#addResource,
|
||||
removeResource: DHBaseItemSheet.#removeResource
|
||||
removeResource: DHBaseItemSheet.#removeResource,
|
||||
editGMNote: DHBaseItemSheet.#onEditGMNote
|
||||
},
|
||||
dragDrop: [
|
||||
{ dragSelector: null, dropSelector: '.drop-section' },
|
||||
|
|
@ -76,10 +77,16 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
/**@inheritdoc */
|
||||
async _preparePartContext(partId, context, options) {
|
||||
await super._preparePartContext(partId, context, options);
|
||||
const TextEditor = foundry.applications.ux.TextEditor.implementation;
|
||||
|
||||
switch (partId) {
|
||||
case 'description':
|
||||
context.enrichedDescription = await this.document.system.getEnrichedDescription();
|
||||
context.enrichedDescription = await this.document.system.getEnrichedDescription({ gmNotes: false });
|
||||
context.enrichedGMNotes = await TextEditor.implementation.enrichHTML(this.item.system.gmNotes, {
|
||||
relativeTo: this.item,
|
||||
rollData: this.item.getRollData(),
|
||||
secrets: this.item.isOwner
|
||||
})
|
||||
break;
|
||||
case 'effects':
|
||||
await this._prepareEffectsContext(context, options);
|
||||
|
|
@ -331,4 +338,45 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the Add GM Note button being pressed. This is only used when an item has no GM notes.
|
||||
* Later edits to a GM note instead go through the normal editor toggle workflow.
|
||||
* @this DHBaseItemSheet
|
||||
*/
|
||||
static #onEditGMNote() {
|
||||
// Open the editor, which might be hidden. We remove the css class to hide temporarily
|
||||
// so that menu auto resizing functions properly.
|
||||
const editor = this.element.querySelector('prose-mirror[name="system.gmNotes"]');
|
||||
const wasHidden = editor.classList.contains('hide-if-inactive');
|
||||
editor.classList.remove('hide-if-inactive');
|
||||
editor.open = true;
|
||||
window.setTimeout(() => {
|
||||
if (wasHidden) editor.classList.add('hide-if-inactive');
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
// Render an add gmnotes button if there are no set GM notes.
|
||||
// We need to re-render on close since its possible to prosemirror to close *without* triggering a full re-render
|
||||
if (game.user.isGM && !this.item.system.gmNotes) {
|
||||
const description = this.element.querySelector('[name="system.description"]');
|
||||
const addButton = () => {
|
||||
if (description.querySelector('[data-action=editGMNote]')) return;
|
||||
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.classList.add('icon', 'toggle', 'fa-regular', 'fa-note-medical');
|
||||
button.dataset.action = 'editGMNote';
|
||||
button.dataset.tooltip = 'DAGGERHEART.ITEMS.Base.addGMNote';
|
||||
description.appendChild(button);
|
||||
}
|
||||
|
||||
addButton();
|
||||
description.addEventListener('close', () => addButton());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -256,7 +256,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
|
||||
if (Hooks.call(`${CONFIG.DH.id}.postUseAction`, this, config) === false) return;
|
||||
|
||||
if (this.chatDisplay && !config.skips.createMessage && !config.actionChatMessageHandled) await this.toChat();
|
||||
if (this.chatDisplay && !config.skips.createMessage && !config.actionChatMessageHandled)
|
||||
await this.toChat(null, config);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,10 +276,18 @@ export class DHActionDiceData extends foundry.abstract.DataModel {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string} the formula associated with this damage field
|
||||
*/
|
||||
getFormula() {
|
||||
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`,
|
||||
bonus = this.bonus ? (this.bonus < 0 ? ` - ${Math.abs(this.bonus)}` : ` + ${this.bonus}`) : '';
|
||||
return this.custom.enabled ? this.custom.formula : `${multiplier ?? 1}${this.dice}${bonus}`;
|
||||
if (this.custom.enabled) return this.custom.formula;
|
||||
|
||||
const multiplier = this.multiplier === 'flat' ? this.flatMultiplier : `@${this.multiplier}`;
|
||||
if (!multiplier) return String(this.bonus || 0);
|
||||
|
||||
const dice = `${multiplier ?? 1}${this.dice}`;
|
||||
const sign = this.bonus < 0 ? ' - ' : ' + ';
|
||||
return this.bonus ? `${dice} ${sign} ${Math.abs(this.bonus)}` : dice;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default class DHSummonField extends fields.ArrayField {
|
|||
super(summonFields, options, context);
|
||||
}
|
||||
|
||||
static async execute() {
|
||||
static async execute(config) {
|
||||
if (!canvas.scene) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.summon.error'));
|
||||
return;
|
||||
|
|
@ -36,6 +36,7 @@ export default class DHSummonField extends fields.ArrayField {
|
|||
|
||||
const rolls = [];
|
||||
const summonData = [];
|
||||
const chatMessageData = [];
|
||||
for (const summon of this.summon) {
|
||||
const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item));
|
||||
await roll.evaluate();
|
||||
|
|
@ -54,17 +55,18 @@ export default class DHSummonField extends fields.ArrayField {
|
|||
tokenPreviewName: `${actor.prototypeToken.name}${remaining > 1 ? ` (${remaining}x)` : ''}`
|
||||
});
|
||||
}
|
||||
|
||||
chatMessageData.push({
|
||||
data: actor,
|
||||
quantity: countNumber
|
||||
});
|
||||
}
|
||||
|
||||
if (rolls.length) await triggerChatRollFx(rolls);
|
||||
|
||||
this.actor.sheet?.minimize();
|
||||
DHSummonField.handleSummon(summonData, this.actor);
|
||||
}
|
||||
|
||||
static async handleSummon(summonData, actionActor) {
|
||||
await CONFIG.ux.TokenManager.createTokensWithPreview(summonData, { elevation: actionActor.token?.elevation });
|
||||
|
||||
return actionActor.sheet?.maximize();
|
||||
await CONFIG.ux.TokenManager.createTokensWithPreview(summonData, { elevation: this.actor.token?.elevation });
|
||||
this.actor.sheet?.maximize();
|
||||
config.summonData = chatMessageData;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -269,10 +269,7 @@ export function ActionMixin(Base) {
|
|||
return this.delete();
|
||||
}
|
||||
|
||||
async toChat(origin) {
|
||||
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
|
||||
.expandRollMessage?.desc;
|
||||
|
||||
async toChat(origin, config) {
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const systemData = {
|
||||
title: game.i18n.localize('DAGGERHEART.CONFIG.FeatureForm.action'),
|
||||
|
|
@ -282,7 +279,7 @@ export function ActionMixin(Base) {
|
|||
img: this.baseAction ? this.parent.parent.img : this.img,
|
||||
tags: this.tags ? this.tags : ['Spell', 'Arcana', 'Lv 10'],
|
||||
areas: this.areas,
|
||||
summon: this.summon
|
||||
summon: config?.summonData
|
||||
},
|
||||
source: {
|
||||
actor: this.actor.uuid,
|
||||
|
|
@ -307,7 +304,7 @@ export function ActionMixin(Base) {
|
|||
system: systemData,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/action.hbs',
|
||||
{ ...systemData, open: autoExpandDescription ? 'open' : '' }
|
||||
systemData
|
||||
),
|
||||
flags: {
|
||||
daggerheart: {
|
||||
|
|
|
|||
|
|
@ -49,7 +49,10 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
})
|
||||
};
|
||||
|
||||
if (this.metadata.hasDescription) schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
if (this.metadata.hasDescription) {
|
||||
schema.description = new fields.HTMLField({ required: true, nullable: true });
|
||||
schema.gmNotes = new fields.HTMLField({ required: true, nullable: true });
|
||||
}
|
||||
|
||||
if (this.metadata.hasResource) {
|
||||
schema.resource = new fields.SchemaField(
|
||||
|
|
@ -134,7 +137,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
/**
|
||||
* Augments the description for the item with type specific info to display. Implemented in applicable item subtypes.
|
||||
* @param {object} [options] - Options that modify the styling of the rendered template. { headerStyle: undefined|'none'|'large' }
|
||||
* @returns {string}
|
||||
* @returns {Promise<{ prefix: string | null; value: string | null; suffix: string | null }>}
|
||||
*/
|
||||
async getDescriptionData(_options) {
|
||||
return { prefix: null, value: this.description, suffix: null };
|
||||
|
|
@ -143,16 +146,26 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
|
|||
/**
|
||||
* Gets the enriched and augmented description for the item.
|
||||
* @param {object} [options] - Options that modify the styling of the rendered template. { headerStyle: undefined|'none'|'large' }
|
||||
* @returns {string}
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
async getEnrichedDescription() {
|
||||
async getEnrichedDescription({ gmNotes = true } = {}) {
|
||||
if (!this.metadata.hasDescription) return '';
|
||||
|
||||
const { prefix, value, suffix } = await this.getDescriptionData();
|
||||
const fullDescription = [prefix, value, suffix].filter(p => !!p).join('\n<hr>\n');
|
||||
let fullDescription = [prefix, value, suffix].filter(p => !!p).join('\n<hr>\n');
|
||||
if (this.gmNotes && gmNotes) {
|
||||
const gmNotesElement = document.createElement('section');
|
||||
gmNotesElement.classList.add('gm-notes-section');
|
||||
gmNotesElement.dataset.visibility = 'gm';
|
||||
const header = document.createElement('header');
|
||||
header.classList.add('gm-notes');
|
||||
header.textContent = _loc('DAGGERHEART.ITEMS.FIELDS.gmNotes.label');
|
||||
gmNotesElement.innerHTML = header.outerHTML + this.gmNotes;
|
||||
fullDescription += gmNotesElement.outerHTML;
|
||||
}
|
||||
|
||||
return await foundry.applications.ux.TextEditor.implementation.enrichHTML(fullDescription, {
|
||||
relativeTo: this,
|
||||
relativeTo: this.parent,
|
||||
rollData: this.getRollData(),
|
||||
secrets: this.parent.isOwner
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@ import { emitGMUpdate, emitGMCreate, GMUpdateEvent } from '../systemRegistration
|
|||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||
targetHook = null;
|
||||
|
||||
static #EXPAND_SECTIONS = [
|
||||
{ selector: 'roll-section [data-action="expandRoll"]', key: 'roll' },
|
||||
{ selector: 'damage-section', key: 'damage' },
|
||||
{ selector: 'target-section', key: 'target' },
|
||||
{ selector: 'description-section', key: 'desc' }
|
||||
];
|
||||
|
||||
async renderHTML() {
|
||||
const actor = game.actors.get(this.speaker.actor);
|
||||
const actorData =
|
||||
|
|
@ -89,23 +96,26 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
}
|
||||
}
|
||||
|
||||
// Check registered selectors and the main item section for expanding
|
||||
// Preserving during re-render is handled by core foundry on anything with [data-action=expandRoll]
|
||||
const autoExpandRoll = game.settings.get(
|
||||
CONFIG.DH.id,
|
||||
CONFIG.DH.SETTINGS.gameSettings.appearance
|
||||
).expandRollMessage,
|
||||
rollSections = html.querySelectorAll('.roll-part'),
|
||||
itemDesc = html.querySelector('.domain-card-move');
|
||||
rollSections.forEach(s => {
|
||||
if (s.classList.contains('roll-section')) {
|
||||
const toExpand = s.querySelector('[data-action="expandRoll"]');
|
||||
toExpand.classList.toggle('expanded', autoExpandRoll.roll);
|
||||
} else if (s.classList.contains('damage-section'))
|
||||
s.classList.toggle('expanded', autoExpandRoll.damage);
|
||||
else if (s.classList.contains('target-section')) s.classList.toggle('expanded', autoExpandRoll.target);
|
||||
else if (s.classList.contains('description-section'))
|
||||
s.classList.toggle('expanded', autoExpandRoll.desc);
|
||||
});
|
||||
if (itemDesc && autoExpandRoll.desc) itemDesc.setAttribute('open', '');
|
||||
CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance
|
||||
).expandRollMessage;
|
||||
for (const { selector, key } of DhpChatMessage.#EXPAND_SECTIONS) {
|
||||
const elements = html.querySelectorAll(selector);
|
||||
for (const element of elements) {
|
||||
element.classList.toggle('expanded', autoExpandRoll[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto expand the item description. These are not preserved by foundry during re-renders
|
||||
const itemDesc = html.querySelector('details');
|
||||
if (itemDesc) {
|
||||
const existing = document.querySelector(`.chat-message[data-message-id="${this.id}"] details`);
|
||||
if (existing?.hasAttribute('open') ?? autoExpandRoll.desc) {
|
||||
itemDesc.setAttribute('open', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.isAuthor && !this.speakerActor?.isOwner) {
|
||||
|
|
|
|||
|
|
@ -208,10 +208,7 @@ export default class DHItem extends foundry.documents.Item {
|
|||
tags: this._getTags()
|
||||
},
|
||||
actions: item.system.actionsList,
|
||||
description: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.system.description, {
|
||||
relativeTo: this.parent,
|
||||
rollData: this.parent?.getRollData() ?? {}
|
||||
})
|
||||
description: await this.system.getEnrichedDescription()
|
||||
};
|
||||
|
||||
const msg = {
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ export default class DhTokenManager {
|
|||
}
|
||||
}
|
||||
|
||||
return await canvas.tokens.placeTokens(
|
||||
const placedData = await canvas.tokens.placeTokens(
|
||||
[
|
||||
{
|
||||
...actor.prototypeToken.toObject(),
|
||||
...(await actor.getTokenDocument()).toObject(),
|
||||
actorId: actor.id,
|
||||
displayName: 50,
|
||||
...tokenData
|
||||
|
|
@ -30,6 +30,8 @@ export default class DhTokenManager {
|
|||
],
|
||||
{ create: false }
|
||||
);
|
||||
|
||||
return placedData?.[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,22 +48,24 @@ export default class DhTokenManager {
|
|||
|
||||
const createElevation = elevation ?? level.elevation.bottom;
|
||||
for (const tokenData of tokensData) {
|
||||
const previewTokens = await this.createPreview(tokenData.actor, {
|
||||
const previewToken = await this.createPreview(tokenData.actor, {
|
||||
name: tokenData.tokenPreviewName,
|
||||
level: game.user.viewedLevel,
|
||||
elevation: createElevation,
|
||||
flags: { daggerheart: { createPlacement: true } }
|
||||
});
|
||||
if (!previewTokens?.length) return null;
|
||||
if (!previewToken) return null;
|
||||
|
||||
const finalTokenData = {
|
||||
...previewToken.toObject(),
|
||||
name: tokenData.actor.prototypeToken.name,
|
||||
displayName: tokenData.actor.prototypeToken.displayName,
|
||||
flags: tokenData.actor.prototypeToken.flags
|
||||
};
|
||||
|
||||
await canvas.scene.createEmbeddedDocuments(
|
||||
'Token',
|
||||
previewTokens.map(x => ({
|
||||
...x.toObject(),
|
||||
name: tokenData.actor.prototypeToken.name,
|
||||
displayName: tokenData.actor.prototypeToken.displayName,
|
||||
flags: tokenData.actor.prototypeToken.flags
|
||||
})),
|
||||
[finalTokenData],
|
||||
{ controlObject: true, parent: canvas.scene }
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,199 +4,234 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
|||
#wide = false;
|
||||
#bordered = false;
|
||||
|
||||
/** @inheritdoc */
|
||||
async activate(element, options = {}) {
|
||||
const { TextEditor } = foundry.applications.ux;
|
||||
this.#wide = false;
|
||||
this.#bordered = false;
|
||||
|
||||
let html = options.html;
|
||||
if (element.dataset.tooltip?.startsWith('#battlepoints#')) {
|
||||
this.#wide = true;
|
||||
this.#bordered = true;
|
||||
|
||||
html = await this.getBattlepointHTML(element.dataset.combatId);
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
super.activate(element, { ...options, html: html });
|
||||
|
||||
const lockedTooltip = this.lockTooltip();
|
||||
lockedTooltip.querySelectorAll('.battlepoint-toggle-container input').forEach(element => {
|
||||
element.addEventListener('input', this.toggleModifier.bind(this));
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
this.#wide = false;
|
||||
this.#bordered = false;
|
||||
const isMacro = document.getElementById('action-bar').contains(element);
|
||||
const macro = isMacro ? game.macros.get(game.user.hotbar[Number(element.dataset.slot)] ?? null) : null;
|
||||
const macroItemUuid = macro?.type === 'script' ? macro.command.match(/await game\.system\.api\.applications\.ui\.DhHotbar\.useItem\("([^"]+)"\);/)?.[1] : null;
|
||||
if (macroItemUuid && await fromUuid(macroItemUuid, { strict: false })) {
|
||||
element.dataset.tooltip = `#item#${macroItemUuid}`;
|
||||
options.direction = this.constructor.TOOLTIP_DIRECTIONS.UP;
|
||||
}
|
||||
|
||||
if (element.dataset.tooltip === '#effect-display#') {
|
||||
this.#bordered = true;
|
||||
let effect = {};
|
||||
if (element.dataset.uuid) {
|
||||
const effectItem = await foundry.utils.fromUuid(element.dataset.uuid);
|
||||
const effectData = effectItem.toObject();
|
||||
let html = options.html;
|
||||
const key = element.dataset.tooltip?.match(/^#([\w-]+)#/)?.[1];
|
||||
switch (key) {
|
||||
case 'battlepoints':
|
||||
return this.#activateBattlepoints(element, options);
|
||||
case 'effect-display':
|
||||
html = await this.#activateEffectDisplay(element, options);
|
||||
break;
|
||||
case 'item':
|
||||
html = await this.#activateItem(element, options);
|
||||
break;
|
||||
case 'attack':
|
||||
html = await this.#activateAttack(element, options);
|
||||
break;
|
||||
case 'shortRest':
|
||||
case 'longRest':
|
||||
html = await this.#activateRest(element, options);
|
||||
break;
|
||||
case 'advantage':
|
||||
case 'disadvantage':
|
||||
html = await this.#activateAdvantageDisadvantage(element, options);
|
||||
break;
|
||||
case 'deathMove':
|
||||
html = await this.#activateDeathMove(element, options);
|
||||
break;
|
||||
}
|
||||
|
||||
effect = {
|
||||
...effectData,
|
||||
name: game.i18n.localize(effectData.name)
|
||||
this.noOffset = options.noOffset;
|
||||
super.activate(element, { ...options, html });
|
||||
}
|
||||
|
||||
async #activateBattlepoints(element, options) {
|
||||
this.#wide = true;
|
||||
this.#bordered = true;
|
||||
|
||||
const html = await this.getBattlepointHTML(element.dataset.combatId);
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
super.activate(element, { ...options, html: html });
|
||||
|
||||
const lockedTooltip = this.lockTooltip();
|
||||
lockedTooltip.querySelectorAll('.battlepoint-toggle-container input').forEach(element => {
|
||||
element.addEventListener('input', this.toggleModifier.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
async #activateEffectDisplay(element, options) {
|
||||
this.#bordered = true;
|
||||
let effect = {};
|
||||
if (element.dataset.uuid) {
|
||||
const effectItem = await foundry.utils.fromUuid(element.dataset.uuid);
|
||||
const effectData = effectItem.toObject();
|
||||
|
||||
effect = {
|
||||
...effectData,
|
||||
name: game.i18n.localize(effectData.name)
|
||||
};
|
||||
|
||||
if (effectData.type === 'beastform') {
|
||||
const beastformData = {
|
||||
features: [],
|
||||
advantageOn: effectData.system.advantageOn,
|
||||
beastformAttackData: game.system.api.data.items.DHBeastform.getBeastformAttackData(effectItem)
|
||||
};
|
||||
|
||||
if (effectData.type === 'beastform') {
|
||||
const beastformData = {
|
||||
features: [],
|
||||
advantageOn: effectData.system.advantageOn,
|
||||
beastformAttackData: game.system.api.data.items.DHBeastform.getBeastformAttackData(effectItem)
|
||||
};
|
||||
|
||||
const features = effectItem.parent.items.filter(x => effectItem.system.featureIds.includes(x.id));
|
||||
for (const feature of features) {
|
||||
const featureData = feature.toObject();
|
||||
featureData.enrichedDescription = await feature.system.getEnrichedDescription();
|
||||
beastformData.features.push(featureData);
|
||||
}
|
||||
|
||||
effect.description = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs',
|
||||
{
|
||||
item: { system: beastformData }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
effect.description = game.i18n.localize(
|
||||
effectData.description ?? effectData.parent.system.description
|
||||
);
|
||||
const features = effectItem.parent.items.filter(x => effectItem.system.featureIds.includes(x.id));
|
||||
for (const feature of features) {
|
||||
const featureData = feature.toObject();
|
||||
featureData.enrichedDescription = await feature.system.getEnrichedDescription();
|
||||
beastformData.features.push(featureData);
|
||||
}
|
||||
} else {
|
||||
const conditions = CONFIG.DH.GENERAL.conditions();
|
||||
const condition = conditions[element.dataset.condition];
|
||||
effect = {
|
||||
...condition,
|
||||
name: game.i18n.localize(condition.name),
|
||||
description: game.i18n.localize(condition.description),
|
||||
appliedBy: element.dataset.appliedBy,
|
||||
isLockedCondition: true
|
||||
};
|
||||
}
|
||||
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/effect-display.hbs`,
|
||||
effect.description = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/tooltip/parts/beastformData.hbs',
|
||||
{
|
||||
item: { system: beastformData }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
effect.description = game.i18n.localize(
|
||||
effectData.description ?? effectData.parent.system.description
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const conditions = CONFIG.DH.GENERAL.conditions();
|
||||
const condition = conditions[element.dataset.condition];
|
||||
effect = {
|
||||
...condition,
|
||||
name: game.i18n.localize(condition.name),
|
||||
description: game.i18n.localize(condition.description),
|
||||
appliedBy: element.dataset.appliedBy,
|
||||
isLockedCondition: true
|
||||
};
|
||||
}
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/effect-display.hbs`,
|
||||
{
|
||||
effect
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
async #activateItem(element, options) {
|
||||
const itemUuid = element.dataset.tooltip.slice(6);
|
||||
const item = await foundry.utils.fromUuid(itemUuid);
|
||||
if (item) {
|
||||
const isAction = item instanceof game.system.api.models.actions.actionsTypes.base;
|
||||
const isEffect = item instanceof ActiveEffect;
|
||||
await this.enrichText(item);
|
||||
|
||||
const type = isAction ? 'action' : isEffect ? 'effect' : item.type;
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/${type}.hbs`,
|
||||
{
|
||||
effect
|
||||
item: item,
|
||||
description: item.system?.enrichedDescription ?? item.enrichedDescription,
|
||||
config: CONFIG.DH,
|
||||
allDomains: CONFIG.DH.DOMAIN.allDomains()
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
} else {
|
||||
this.#bordered = false;
|
||||
options.direction ??= this._determineItemTooltipDirection(element);
|
||||
return html;
|
||||
}
|
||||
|
||||
if (element.dataset.tooltip?.startsWith('#item#')) {
|
||||
const itemUuid = element.dataset.tooltip.slice(6);
|
||||
const item = await foundry.utils.fromUuid(itemUuid);
|
||||
if (item) {
|
||||
const isAction = item instanceof game.system.api.models.actions.actionsTypes.base;
|
||||
const isEffect = item instanceof ActiveEffect;
|
||||
await this.enrichText(item);
|
||||
return null;
|
||||
}
|
||||
|
||||
const type = isAction ? 'action' : isEffect ? 'effect' : item.type;
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/${type}.hbs`,
|
||||
{
|
||||
item: item,
|
||||
description: item.system?.enrichedDescription ?? item.enrichedDescription,
|
||||
config: CONFIG.DH,
|
||||
allDomains: CONFIG.DH.DOMAIN.allDomains()
|
||||
}
|
||||
);
|
||||
async #activateAttack(element, options) {
|
||||
const actorUuid = element.dataset.tooltip.slice(8);
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
const attack = actor.system.attack;
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(element);
|
||||
const description = await foundry.applications.ux.TextEditor.enrichHTML(attack.description);
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/attack.hbs`,
|
||||
{
|
||||
attack: attack,
|
||||
description: description,
|
||||
parent: actor,
|
||||
config: CONFIG.DH
|
||||
}
|
||||
} else {
|
||||
const attack = element.dataset.tooltip?.startsWith('#attack#');
|
||||
if (attack) {
|
||||
const actorUuid = element.dataset.tooltip.slice(8);
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
const attack = actor.system.attack;
|
||||
);
|
||||
|
||||
const description = await TextEditor.enrichHTML(attack.description);
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/attack.hbs`,
|
||||
{
|
||||
attack: attack,
|
||||
description: description,
|
||||
parent: actor,
|
||||
config: CONFIG.DH
|
||||
}
|
||||
);
|
||||
this.tooltip.innerHTML = html;
|
||||
return html;
|
||||
}
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
}
|
||||
async #activateAdvantageDisadvantage(element, options) {
|
||||
const isAdvantage = element.dataset.tooltip?.startsWith('#advantage#');
|
||||
const actorUuid = element.dataset.tooltip.slice(isAdvantage ? 11 : 14);
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
|
||||
const shortRest = element.dataset.tooltip?.startsWith('#shortRest#');
|
||||
const longRest = element.dataset.tooltip?.startsWith('#longRest#');
|
||||
if (shortRest || longRest) {
|
||||
const key = element.dataset.tooltip.slice(shortRest ? 11 : 10);
|
||||
|
||||
const moves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves[
|
||||
element.dataset.restType
|
||||
].moves;
|
||||
const move = moves[key];
|
||||
const description = await TextEditor.enrichHTML(move.description);
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/downtime.hbs`,
|
||||
{
|
||||
move: move,
|
||||
description: description
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(
|
||||
element,
|
||||
this.constructor.TOOLTIP_DIRECTIONS.RIGHT
|
||||
);
|
||||
}
|
||||
|
||||
const isAdvantage = element.dataset.tooltip?.startsWith('#advantage#');
|
||||
const isDisadvantage = element.dataset.tooltip?.startsWith('#disadvantage#');
|
||||
if (isAdvantage || isDisadvantage) {
|
||||
const actorUuid = element.dataset.tooltip.slice(isAdvantage ? 11 : 14);
|
||||
const actor = await foundry.utils.fromUuid(actorUuid);
|
||||
|
||||
if (actor) {
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/advantage.hbs`,
|
||||
{
|
||||
sources: isAdvantage ? actor.system.advantageSources : actor.system.disadvantageSources
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
if (actor) {
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/advantage.hbs`,
|
||||
{
|
||||
sources: isAdvantage ? actor.system.advantageSources : actor.system.disadvantageSources
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const deathMove = element.dataset.tooltip?.startsWith('#deathMove#');
|
||||
if (deathMove) {
|
||||
const name = element.dataset.deathName;
|
||||
const img = element.dataset.deathImg;
|
||||
const description = element.dataset.deathDescription;
|
||||
|
||||
html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/death-move.hbs`,
|
||||
{
|
||||
move: { name: name, img: img, description: description }
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(
|
||||
element,
|
||||
this.constructor.TOOLTIP_DIRECTIONS.RIGHT
|
||||
);
|
||||
}
|
||||
this.tooltip.innerHTML = html;
|
||||
return html;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
this.noOffset = options.noOffset;
|
||||
super.activate(element, { ...options, html: html });
|
||||
async #activateDeathMove(element, options) {
|
||||
const name = element.dataset.deathName;
|
||||
const img = element.dataset.deathImg;
|
||||
const description = element.dataset.deathDescription;
|
||||
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/death-move.hbs`,
|
||||
{
|
||||
move: { name: name, img: img, description: description }
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(
|
||||
element,
|
||||
this.constructor.TOOLTIP_DIRECTIONS.RIGHT
|
||||
);
|
||||
return html;
|
||||
}
|
||||
|
||||
async #activateRest(element, options) {
|
||||
const isShortRest = element.dataset.tooltip?.startsWith('#shortRest#');
|
||||
const key = element.dataset.tooltip.slice(isShortRest ? 11 : 10);
|
||||
const moves = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves[
|
||||
element.dataset.restType
|
||||
].moves;
|
||||
const move = moves[key];
|
||||
const description = await foundry.applications.ux.TextEditor.enrichHTML(move.description);
|
||||
const html = await foundry.applications.handlebars.renderTemplate(
|
||||
`systems/daggerheart/templates/ui/tooltip/downtime.hbs`,
|
||||
{
|
||||
move: move,
|
||||
description: description
|
||||
}
|
||||
);
|
||||
|
||||
this.tooltip.innerHTML = html;
|
||||
options.direction = this._determineItemTooltipDirection(
|
||||
element,
|
||||
this.constructor.TOOLTIP_DIRECTIONS.RIGHT
|
||||
);
|
||||
return html;
|
||||
}
|
||||
|
||||
_setAnchor(direction) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export class Migration_2_5_2 extends MigrationHandlerBase {
|
|||
const srdEffect = srdItem?.effects.find(x => x.name === effectSource.name);
|
||||
if (change.type === 'custom') {
|
||||
const srdChange = srdEffect ? srdEffect.system.changes[i] : null;
|
||||
if (
|
||||
if (srdChange &&
|
||||
change.key === srdChange.key &&
|
||||
change.value === srdChange.value &&
|
||||
change.type !== srdChange.type
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue