mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-17 15:39:02 +01:00
Merge branch 'main' of github.com:chrisryan10/daggerheart
This commit is contained in:
commit
3bd497bc21
37 changed files with 358 additions and 614 deletions
|
|
@ -2259,11 +2259,6 @@
|
||||||
"abilityCheckTitle": "{ability} Check"
|
"abilityCheckTitle": "{ability} Check"
|
||||||
},
|
},
|
||||||
"featureTitle": "Class Feature",
|
"featureTitle": "Class Feature",
|
||||||
"foundationCard": {
|
|
||||||
"ancestryTitle": "Ancestry Card",
|
|
||||||
"communityTitle": "Community Card",
|
|
||||||
"subclassFeatureTitle": "Subclass Feature"
|
|
||||||
},
|
|
||||||
"healingRoll": {
|
"healingRoll": {
|
||||||
"title": "Heal - {damage}",
|
"title": "Heal - {damage}",
|
||||||
"heal": "Heal",
|
"heal": "Heal",
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
return this.config.title;
|
return this.config.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get actor() {
|
||||||
|
return this.config?.data?.parent;
|
||||||
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
header: {
|
header: {
|
||||||
|
|
@ -69,9 +73,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
icon
|
icon
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.config.costs ??= [];
|
||||||
if (this.config.costs?.length) {
|
if (this.config.costs?.length) {
|
||||||
const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(
|
const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(
|
||||||
this.action,
|
this.action ?? { actor: this.actor },
|
||||||
this.config.costs
|
this.config.costs
|
||||||
);
|
);
|
||||||
context.costs = updatedCosts.map(x => ({
|
context.costs = updatedCosts.map(x => ({
|
||||||
|
|
@ -80,7 +85,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
? this.action.parent.parent.name
|
? this.action.parent.parent.name
|
||||||
: game.i18n.localize(CONFIG.DH.GENERAL.abilityCosts[x.key].label)
|
: game.i18n.localize(CONFIG.DH.GENERAL.abilityCosts[x.key].label)
|
||||||
}));
|
}));
|
||||||
context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call(this.action, updatedCosts);
|
context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call(
|
||||||
|
this.action ?? { actor: this.actor },
|
||||||
|
updatedCosts
|
||||||
|
);
|
||||||
this.config.data.scale = this.config.costs[0].total;
|
this.config.data.scale = this.config.costs[0].total;
|
||||||
}
|
}
|
||||||
if (this.config.uses?.max) {
|
if (this.config.uses?.max) {
|
||||||
|
|
@ -143,6 +151,12 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
this.config.experiences.indexOf(button.dataset.key) > -1
|
this.config.experiences.indexOf(button.dataset.key) > -1
|
||||||
? this.config.experiences.filter(x => x !== button.dataset.key)
|
? this.config.experiences.filter(x => x !== button.dataset.key)
|
||||||
: [...this.config.experiences, button.dataset.key];
|
: [...this.config.experiences, button.dataset.key];
|
||||||
|
if(this.config?.data?.parent?.type === 'character' || this.config?.data?.parent?.type === 'companion') {
|
||||||
|
this.config.costs =
|
||||||
|
this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1
|
||||||
|
? this.config.costs.filter(x => x.extKey !== button.dataset.key)
|
||||||
|
: [...this.config.costs, { extKey: button.dataset.key, key: 'hope', value: 1, name: this.config.data?.experiences?.[button.dataset.key]?.name }];
|
||||||
|
}
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -631,13 +631,34 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
||||||
},
|
},
|
||||||
hasRoll: true
|
hasRoll: true
|
||||||
};
|
};
|
||||||
this.document.diceRoll({
|
const result = await this.document.diceRoll({
|
||||||
...config,
|
...config,
|
||||||
headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`,
|
headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`,
|
||||||
title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||||
ability: abilityLabel
|
ability: abilityLabel
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.consumeResource(result?.costs);
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
async consumeResource(costs) {
|
||||||
|
if(!costs?.length) return;
|
||||||
|
const usefulResources = foundry.utils.deepClone(this.actor.system.resources);
|
||||||
|
const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(costs)
|
||||||
|
.map(c => {
|
||||||
|
const resource = usefulResources[c.key];
|
||||||
|
return {
|
||||||
|
key: c.key,
|
||||||
|
value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1),
|
||||||
|
target: resource.target,
|
||||||
|
keyIsID: resource.keyIsID
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.actor.modifyResource(resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: redo toggleEquipItem method
|
//TODO: redo toggleEquipItem method
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,8 @@ import { ItemBrowser } from '../../ui/itemBrowser.mjs';
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @template {Constructor<foundry.applications.api.DocumentSheet>} BaseDocumentSheet
|
* @template {new (...args: any[]) => {}} T
|
||||||
* @param {BaseDocumentSheet} Base - The base class to extend.
|
* @arg Base {T}
|
||||||
* @returns {BaseDocumentSheet}
|
|
||||||
*/
|
*/
|
||||||
export default function DHApplicationMixin(Base) {
|
export default function DHApplicationMixin(Base) {
|
||||||
class DHSheetV2 extends HandlebarsApplicationMixin(Base) {
|
class DHSheetV2 extends HandlebarsApplicationMixin(Base) {
|
||||||
|
|
@ -123,12 +122,13 @@ export default function DHApplicationMixin(Base) {
|
||||||
super._attachPartListeners(partId, htmlElement, options);
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
this._dragDrop.forEach(d => d.bind(htmlElement));
|
this._dragDrop.forEach(d => d.bind(htmlElement));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**@inheritdoc */
|
/**@inheritdoc */
|
||||||
async _onFirstRender(context, options) {
|
async _onFirstRender(context, options) {
|
||||||
await super._onFirstRender(context, options);
|
await super._onFirstRender(context, options);
|
||||||
|
|
||||||
const docs = [];
|
const docs = [];
|
||||||
for (var docData of this.relatedDocs) {
|
for (const docData of this.relatedDocs) {
|
||||||
const doc = await foundry.utils.fromUuid(docData.uuid);
|
const doc = await foundry.utils.fromUuid(docData.uuid);
|
||||||
docs.push(doc);
|
docs.push(doc);
|
||||||
}
|
}
|
||||||
|
|
@ -247,6 +247,9 @@ export default function DHApplicationMixin(Base) {
|
||||||
/* Context Menu */
|
/* Context Menu */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create all configured context menus for this application ins tance.
|
||||||
|
*/
|
||||||
_createContextMenus() {
|
_createContextMenus() {
|
||||||
for (const config of this.options.contextMenus) {
|
for (const config of this.options.contextMenus) {
|
||||||
const { handler, selector, options } = config;
|
const { handler, selector, options } = config;
|
||||||
|
|
@ -257,9 +260,9 @@ export default function DHApplicationMixin(Base) {
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options for DomainCards.
|
* Get the set of ContextMenu options for ActiveEffects.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
* @this {CharacterSheet}
|
* @this {DHSheetV2}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
static #getEffectContextOptions() {
|
static #getEffectContextOptions() {
|
||||||
|
|
@ -305,8 +308,13 @@ export default function DHApplicationMixin(Base) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options.
|
* Get the common ContextMenu options for an element.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @param {Object} options
|
||||||
|
* @param {boolean} [options.usable=false] - Whether to include an option to use the item or apply damage.
|
||||||
|
* @param {boolean} [options.toChat=false] - Whether to include an option to send the item to chat.
|
||||||
|
* @param {boolean} [options.deletable=true] - Whether to include an option to delete the item.
|
||||||
|
*
|
||||||
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]}
|
||||||
*/
|
*/
|
||||||
_getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) {
|
_getContextMenuCommonOptions({ usable = false, toChat = false, deletable = true }) {
|
||||||
const options = [
|
const options = [
|
||||||
|
|
@ -333,6 +341,20 @@ export default function DHApplicationMixin(Base) {
|
||||||
const doc = getDocFromElementSync(target);
|
const doc = getDocFromElementSync(target);
|
||||||
return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length;
|
return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length;
|
||||||
},
|
},
|
||||||
|
callback: async (target, event) => {
|
||||||
|
const doc = await getDocFromElement(target),
|
||||||
|
action = doc?.system?.attack ?? doc;
|
||||||
|
return action && action.use(event, { byPassRoll: true })
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
options.unshift({
|
||||||
|
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
||||||
|
icon: 'fa-solid fa-burst',
|
||||||
|
condition: target => {
|
||||||
|
const doc = getDocFromElementSync(target);
|
||||||
|
return doc?.system?.attack?.damage.parts.length || doc?.damage?.parts.length;
|
||||||
|
},
|
||||||
callback: async (target, event) => {
|
callback: async (target, event) => {
|
||||||
const doc = await getDocFromElement(target),
|
const doc = await getDocFromElement(target),
|
||||||
action = doc?.system?.attack ?? doc;
|
action = doc?.system?.attack ?? doc;
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ const { ActorSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base actor sheet extending {@link ActorSheetV2} via {@link DHApplicationMixin}
|
* A base actor sheet extending {@link ActorSheetV2} via {@link DHApplicationMixin}
|
||||||
* @extends ActorSheetV2
|
|
||||||
* @mixes DHSheetV2
|
|
||||||
*/
|
*/
|
||||||
export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -106,7 +104,7 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options for Features.
|
* Get the set of ContextMenu options for Features.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
* @this {DHSheetV2}
|
* @this {DHBaseActorSheet}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
static #getFeatureContextOptions() {
|
static #getFeatureContextOptions() {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ const { ItemSheetV2 } = foundry.applications.sheets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A base item sheet extending {@link ItemSheetV2} via {@link DHApplicationMixin}
|
* A base item sheet extending {@link ItemSheetV2} via {@link DHApplicationMixin}
|
||||||
* @extends ItemSheetV2
|
|
||||||
* @mixes DHSheetV2
|
|
||||||
*/
|
*/
|
||||||
export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -108,7 +106,7 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
/**
|
/**
|
||||||
* Get the set of ContextMenu options for Features.
|
* Get the set of ContextMenu options for Features.
|
||||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} - The Array of context options passed to the ContextMenu instance
|
||||||
* @this {DHSheetV2}
|
* @this {DHBaseItemSheet}
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
static #getFeatureContextOptions() {
|
static #getFeatureContextOptions() {
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
html.querySelectorAll('.simple-roll-button').forEach(element =>
|
html.querySelectorAll('.simple-roll-button').forEach(element =>
|
||||||
element.addEventListener('click', event => this.onRollSimple(event, data.message))
|
element.addEventListener('click', event => this.onRollSimple(event, data.message))
|
||||||
);
|
);
|
||||||
html.querySelectorAll('.target-container').forEach(element => {
|
|
||||||
element.addEventListener('mouseenter', this.hoverTarget);
|
|
||||||
element.addEventListener('mouseleave', this.unhoverTarget);
|
|
||||||
element.addEventListener('click', this.clickTarget);
|
|
||||||
});
|
|
||||||
html.querySelectorAll('.button-target-selection').forEach(element => {
|
|
||||||
element.addEventListener('click', event => this.onTargetSelection(event, data.message));
|
|
||||||
});
|
|
||||||
html.querySelectorAll('.healing-button').forEach(element =>
|
html.querySelectorAll('.healing-button').forEach(element =>
|
||||||
element.addEventListener('click', event => this.onHealing(event, data.message))
|
element.addEventListener('click', event => this.onHealing(event, data.message))
|
||||||
);
|
);
|
||||||
|
|
@ -138,33 +130,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onTargetSelection(event, message) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const msg = ui.chat.collection.get(message._id);
|
|
||||||
msg.system.targetMode = Boolean(event.target.dataset.targetHit);
|
|
||||||
}
|
|
||||||
|
|
||||||
hoverTarget(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
|
||||||
if (!token?.controlled) token._onHoverIn(event, { hoverOutOthers: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
unhoverTarget(event) {
|
|
||||||
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
|
||||||
if (!token?.controlled) token._onHoverOut(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
clickTarget(event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
|
||||||
if (!token) {
|
|
||||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.attackTargetDoesNotExist'));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
game.canvas.pan(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onRollSimple(event, message) {
|
async onRollSimple(event, message) {
|
||||||
const buttonType = event.target.dataset.type ?? 'damage',
|
const buttonType = event.target.dataset.type ?? 'damage',
|
||||||
total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0),
|
total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0),
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
||||||
|
|
||||||
if (this.chatDisplay) await this.toChat();
|
if (this.chatDisplay) await this.toChat();
|
||||||
|
|
||||||
let { byPassRoll } = options,
|
let { byPassRoll } = options,
|
||||||
config = this.prepareConfig(event, byPassRoll);
|
config = this.prepareConfig(event, byPassRoll);
|
||||||
for (let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
for (let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
||||||
|
|
@ -145,9 +144,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
if (this.rollDamage && this.damage.parts.length) await this.rollDamage(event, config);
|
if (this.rollDamage && this.damage.parts.length) await this.rollDamage(event, config);
|
||||||
else if (this.trigger) await this.trigger(event, config);
|
else if (this.trigger) await this.trigger(event, config);
|
||||||
else if (this.hasSave || this.hasEffect) {
|
else if (this.hasSave || this.hasEffect) {
|
||||||
const roll = new Roll('');
|
const roll = new CONFIG.Dice.daggerheart.DHRoll('');
|
||||||
roll._evaluated = true;
|
roll._evaluated = true;
|
||||||
if (this.hasTarget) config.targetSelection = config.targets.length > 0;
|
if(config.hasTarget) config.targetSelection = config.targets.length > 0;
|
||||||
await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
|
await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,7 +179,6 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
hasHealing: this.damage?.parts?.length && this.type === 'healing',
|
hasHealing: this.damage?.parts?.length && this.type === 'healing',
|
||||||
hasEffect: !!this.effects?.length,
|
hasEffect: !!this.effects?.length,
|
||||||
hasSave: this.hasSave,
|
hasSave: this.hasSave,
|
||||||
hasTarget: true,
|
|
||||||
selectedRollMode: game.settings.get('core', 'rollMode'),
|
selectedRollMode: game.settings.get('core', 'rollMode'),
|
||||||
isFastForward: event.shiftKey,
|
isFastForward: event.shiftKey,
|
||||||
data: this.getRollData(),
|
data: this.getRollData(),
|
||||||
|
|
@ -223,12 +221,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resources = config.costs
|
const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(config.costs)
|
||||||
.filter(
|
.filter(
|
||||||
c =>
|
c =>
|
||||||
c.enabled !== false &&
|
(!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
|
||||||
((!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
|
(successCost && c.consumeOnSuccess)
|
||||||
(successCost && c.consumeOnSuccess))
|
|
||||||
)
|
)
|
||||||
.map(c => {
|
.map(c => {
|
||||||
const resource = usefulResources[c.key];
|
const resource = usefulResources[c.key];
|
||||||
|
|
@ -240,7 +237,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.actor.modifyResource(resources);
|
await (this.actor.system.partner ?? this.actor).modifyResource(resources);
|
||||||
if (
|
if (
|
||||||
config.uses?.enabled &&
|
config.uses?.enabled &&
|
||||||
((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) ||
|
((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) ||
|
||||||
|
|
@ -248,8 +245,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
)
|
)
|
||||||
this.update({ 'uses.value': this.uses.value + 1 });
|
this.update({ 'uses.value': this.uses.value + 1 });
|
||||||
|
|
||||||
if (config.roll?.success || successCost)
|
if(config.roll?.success || successCost) {
|
||||||
(config.message ?? config.parent).update({ 'system.successConsumed': true });
|
setTimeout(() => {
|
||||||
|
(config.message ?? config.parent).update({'system.successConsumed': true})
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
|
|
@ -368,15 +368,15 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
|
|
||||||
async updateChatMessage(message, targetId, changes, chain = true) {
|
async updateChatMessage(message, targetId, changes, chain = true) {
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const chatMessage = ui.chat.collection.get(message._id),
|
const chatMessage = ui.chat.collection.get(message._id);
|
||||||
msgTarget =
|
|
||||||
chatMessage.system.targets.find(mt => mt.id === targetId) ??
|
|
||||||
chatMessage.system.oldTargets.find(mt => mt.id === targetId);
|
|
||||||
msgTarget.saved = changes;
|
|
||||||
await chatMessage.update({
|
await chatMessage.update({
|
||||||
system: {
|
flags: {
|
||||||
targets: chatMessage.system.targets,
|
[game.system.id]: {
|
||||||
oldTargets: chatMessage.system.oldTargets
|
"reactionRolls": {
|
||||||
|
[targetId]: changes
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ export default class DHAbilityUse extends foundry.abstract.TypeDataModel {
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: new fields.StringField({}),
|
|
||||||
origin: new fields.StringField({}),
|
origin: new fields.StringField({}),
|
||||||
img: new fields.StringField({}),
|
img: new fields.StringField({}),
|
||||||
name: new fields.StringField({}),
|
name: new fields.StringField({}),
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
title: new fields.StringField(),
|
title: new fields.StringField(),
|
||||||
roll: new fields.ObjectField(),
|
roll: new fields.ObjectField(),
|
||||||
targets: targetsField(),
|
targets: targetsField(),
|
||||||
oldTargets: targetsField(),
|
|
||||||
targetSelection: new fields.BooleanField({ initial: false }),
|
targetSelection: new fields.BooleanField({ initial: false }),
|
||||||
hasRoll: new fields.BooleanField({ initial: false }),
|
hasRoll: new fields.BooleanField({ initial: false }),
|
||||||
hasDamage: new fields.BooleanField({ initial: false }),
|
hasDamage: new fields.BooleanField({ initial: false }),
|
||||||
|
|
@ -63,24 +62,14 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
return actionItem.system.actionsList?.find(a => a.id === this.source.action);
|
return actionItem.system.actionsList?.find(a => a.id === this.source.action);
|
||||||
}
|
}
|
||||||
|
|
||||||
get messageTemplate() {
|
|
||||||
return 'systems/daggerheart/templates/ui/chat/roll.hbs';
|
|
||||||
}
|
|
||||||
|
|
||||||
get targetMode() {
|
get targetMode() {
|
||||||
return this.targetSelection;
|
return this.targetSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
set targetMode(mode) {
|
set targetMode(mode) {
|
||||||
this.targetSelection = mode;
|
this.targetSelection = mode;
|
||||||
this.updateTargets();
|
|
||||||
this.registerTargetHook();
|
this.registerTargetHook();
|
||||||
this.parent.update({
|
this.updateTargets();
|
||||||
system: {
|
|
||||||
targetSelection: this.targetSelection,
|
|
||||||
oldTargets: this.oldTargets
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get hitTargets() {
|
get hitTargets() {
|
||||||
|
|
@ -88,29 +77,25 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateTargets() {
|
async updateTargets() {
|
||||||
this.currentTargets = this.getTargetList();
|
if(!ui.chat.collection.get(this.parent.id)) return;
|
||||||
if (!this.targetSelection) {
|
let targets;
|
||||||
this.currentTargets.forEach(ct => {
|
if(this.targetSelection)
|
||||||
if (this.targets.find(t => t.actorId === ct.actorId)) return;
|
targets = this.targets;
|
||||||
const indexTarget = this.oldTargets.findIndex(ot => ot.actorId === ct.actorId);
|
else
|
||||||
if (indexTarget === -1) this.oldTargets.push(ct);
|
targets = Array.from(game.user.targets).map(t => game.system.api.fields.ActionFields.TargetField.formatTarget(t));
|
||||||
});
|
|
||||||
if (this.hasSave) this.setPendingSaves();
|
this.parent.setFlag(game.system.id, "targets", targets);
|
||||||
if (this.currentTargets.length) {
|
await this.parent.updateSource({
|
||||||
if (!this.parent._id) return;
|
system: {
|
||||||
const updates = await this.parent.update({
|
targetSelection: this.targetSelection
|
||||||
system: {
|
|
||||||
oldTargets: this.oldTargets
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!updates && ui.chat.collection.get(this.parent.id)) ui.chat.updateMessage(this.parent);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
registerTargetHook() {
|
registerTargetHook() {
|
||||||
if (this.targetSelection && this.targetHook !== null) {
|
if(!this.parent.isAuthor) return;
|
||||||
Hooks.off('targetToken', this.targetHook);
|
if(this.targetSelection && this.targetHook !== null) {
|
||||||
|
Hooks.off("targetToken", this.targetHook);
|
||||||
this.targetHook = null;
|
this.targetHook = null;
|
||||||
} else if (!this.targetSelection && this.targetHook === null) {
|
} else if (!this.targetSelection && this.targetHook === null) {
|
||||||
this.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
this.targetHook = Hooks.on('targetToken', foundry.utils.debounce(this.updateTargets.bind(this), 50));
|
||||||
|
|
@ -120,35 +105,35 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
if (this.hasTarget) {
|
if (this.hasTarget) {
|
||||||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||||
this.updateTargets();
|
this.currentTargets = this.getTargetList();
|
||||||
this.registerTargetHook();
|
this. registerTargetHook();
|
||||||
if (this.targetSelection === true) {
|
|
||||||
this.targetShort = this.targets.reduce(
|
if(this.targetSelection === true && this.hasRoll) {
|
||||||
(a, c) => {
|
this.targetShort = this.targets.reduce((a,c) => {
|
||||||
if (c.hit) a.hit += 1;
|
if(c.hit) a.hit += 1;
|
||||||
else a.miss += 1;
|
else a.miss += 1;
|
||||||
return a;
|
return a;
|
||||||
},
|
}, {hit: 0, miss: 0})
|
||||||
{ hit: 0, miss: 0 }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (this.hasSave) this.setPendingSaves();
|
if (this.hasSave) this.setPendingSaves();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.canViewSecret = this.parent.speakerActor?.testUserPermission(game.user, 'OBSERVER');
|
this.canViewSecret = this.parent.speakerActor?.testUserPermission(game.user, 'OBSERVER');
|
||||||
|
this.canButtonApply = game.user.isGM;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetList() {
|
getTargetList() {
|
||||||
return this.targetSelection !== true
|
const targets = this.targetSelection && this.parent.isAuthor ? this.targets : (this.parent.getFlag(game.system.id, "targets") ?? this.targets),
|
||||||
? Array.from(game.user.targets).map(t => {
|
reactionRolls = this.parent.getFlag(game.system.id, "reactionRolls");
|
||||||
const target = game.system.api.fields.ActionFields.TargetField.formatTarget(t),
|
|
||||||
oldTarget =
|
if(reactionRolls) {
|
||||||
this.targets.find(ot => ot.actorId === target.actorId) ??
|
Object.entries(reactionRolls).forEach(([k, r]) => {
|
||||||
this.oldTargets.find(ot => ot.actorId === target.actorId);
|
const target = targets.find(t => t.id === k);
|
||||||
if (oldTarget) return oldTarget;
|
if(target) target.saved = r;
|
||||||
return target;
|
});
|
||||||
})
|
}
|
||||||
: this.targets;
|
|
||||||
|
return targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
setPendingSaves() {
|
setPendingSaves() {
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ export default class CostField extends fields.ArrayField {
|
||||||
static hasCost(costs) {
|
static hasCost(costs) {
|
||||||
const realCosts = CostField.getRealCosts.call(this, costs),
|
const realCosts = CostField.getRealCosts.call(this, costs),
|
||||||
hasFearCost = realCosts.findIndex(c => c.key === 'fear');
|
hasFearCost = realCosts.findIndex(c => c.key === 'fear');
|
||||||
|
|
||||||
if (hasFearCost > -1) {
|
if (hasFearCost > -1) {
|
||||||
const fearCost = realCosts.splice(hasFearCost, 1)[0];
|
const fearCost = realCosts.splice(hasFearCost, 1)[0];
|
||||||
if (
|
if (
|
||||||
|
|
@ -70,7 +71,8 @@ export default class CostField extends fields.ArrayField {
|
||||||
}
|
}
|
||||||
|
|
||||||
static getResources(costs) {
|
static getResources(costs) {
|
||||||
const actorResources = this.actor.system.resources;
|
const actorResources = foundry.utils.deepClone(this.actor.system.resources);
|
||||||
|
if(this.actor.system.partner) actorResources.hope = foundry.utils.deepClone(this.actor.system.partner.system.resources.hope);
|
||||||
const itemResources = {};
|
const itemResources = {};
|
||||||
for (let itemResource of costs) {
|
for (let itemResource of costs) {
|
||||||
if (itemResource.keyIsID) {
|
if (itemResource.keyIsID) {
|
||||||
|
|
@ -89,7 +91,13 @@ export default class CostField extends fields.ArrayField {
|
||||||
|
|
||||||
static getRealCosts(costs) {
|
static getRealCosts(costs) {
|
||||||
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
|
||||||
return realCosts;
|
let mergedCosts = [];
|
||||||
|
realCosts.forEach(c => {
|
||||||
|
const getCost = Object.values(mergedCosts).find(gc => gc.key === c.key);
|
||||||
|
if(getCost) getCost.total += c.total;
|
||||||
|
else mergedCosts.push(c);
|
||||||
|
});
|
||||||
|
return mergedCosts;
|
||||||
}
|
}
|
||||||
|
|
||||||
static formatMax(max) {
|
static formatMax(max) {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ export default class TargetField extends fields.SchemaField {
|
||||||
|
|
||||||
static prepareConfig(config) {
|
static prepareConfig(config) {
|
||||||
if (!this.target?.type) return [];
|
if (!this.target?.type) return [];
|
||||||
|
config.hasTarget = true;
|
||||||
let targets;
|
let targets;
|
||||||
if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id)
|
if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id)
|
||||||
targets = [this.actor.token ?? this.actor.prototypeToken];
|
targets = [this.actor.token ?? this.actor.prototypeToken];
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,7 @@ export function ActionMixin(Base) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ChatMessage.applyRollMode(msg, game.settings.get('core', 'rollMode'));
|
||||||
cls.create(msg);
|
cls.create(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,17 +139,17 @@ export default class D20Roll extends DHRoll {
|
||||||
static postEvaluate(roll, config = {}) {
|
static postEvaluate(roll, config = {}) {
|
||||||
const data = super.postEvaluate(roll, config);
|
const data = super.postEvaluate(roll, config);
|
||||||
data.type = config.roll?.type;
|
data.type = config.roll?.type;
|
||||||
|
data.difficulty = config.roll.difficulty;
|
||||||
if (config.targets?.length) {
|
if (config.targets?.length) {
|
||||||
config.targetSelection = true;
|
config.targetSelection = true;
|
||||||
config.targets.forEach(target => {
|
config.targets.forEach(target => {
|
||||||
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
|
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
|
||||||
target.hit = roll.isCritical || roll.total >= difficulty;
|
target.hit = roll.isCritical || roll.total >= difficulty;
|
||||||
});
|
});
|
||||||
data.success = config.targets.some(target => target.hit);
|
data.success = config.targets.some(target => target.hit)
|
||||||
} else if (config.roll.difficulty) {
|
} else if (config.roll.difficulty)
|
||||||
data.difficulty = config.roll.difficulty;
|
|
||||||
data.success = roll.isCritical || roll.total >= config.roll.difficulty;
|
data.success = roll.isCritical || roll.total >= config.roll.difficulty;
|
||||||
}
|
|
||||||
data.advantage = {
|
data.advantage = {
|
||||||
type: config.roll.advantage,
|
type: config.roll.advantage,
|
||||||
dice: roll.dAdvantage?.denomination,
|
dice: roll.dAdvantage?.denomination,
|
||||||
|
|
|
||||||
|
|
@ -30,16 +30,16 @@ export default class DamageRoll extends DHRoll {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async buildPost(roll, config, message) {
|
static async buildPost(roll, config, message) {
|
||||||
|
const chatMessage = config.source?.message ? ui.chat.collection.get(config.source.message) : getDocumentClass('ChatMessage').applyRollMode({}, config.rollMode);
|
||||||
if (game.modules.get('dice-so-nice')?.active) {
|
if (game.modules.get('dice-so-nice')?.active) {
|
||||||
const pool = foundry.dice.terms.PoolTerm.fromRolls(
|
const pool = foundry.dice.terms.PoolTerm.fromRolls(
|
||||||
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
|
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
|
||||||
),
|
),
|
||||||
diceRoll = Roll.fromTerms([pool]);
|
diceRoll = Roll.fromTerms([pool]);
|
||||||
await game.dice3d.showForRoll(diceRoll, game.user, true);
|
await game.dice3d.showForRoll(diceRoll, game.user, true, chatMessage.whisper, chatMessage.blind);
|
||||||
}
|
}
|
||||||
await super.buildPost(roll, config, message);
|
await super.buildPost(roll, config, message);
|
||||||
if (config.source?.message) {
|
if (config.source?.message) {
|
||||||
const chatMessage = ui.chat.collection.get(config.source.message);
|
|
||||||
chatMessage.update({ 'system.damage': config.damage });
|
chatMessage.update({ 'system.damage': config.damage });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
|
||||||
|
|
||||||
export default class DHRoll extends Roll {
|
export default class DHRoll extends Roll {
|
||||||
baseTerms = [];
|
baseTerms = [];
|
||||||
constructor(formula, data, options) {
|
constructor(formula, data = {}, options = {}) {
|
||||||
super(formula, data, options);
|
super(formula, data, options);
|
||||||
if (!this.data || !Object.keys(this.data).length) this.data = options.data;
|
if (!this.data || !Object.keys(this.data).length) this.data = options.data;
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +15,8 @@ export default class DHRoll extends Roll {
|
||||||
|
|
||||||
static messageType = 'adversaryRoll';
|
static messageType = 'adversaryRoll';
|
||||||
|
|
||||||
|
static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs';
|
||||||
|
|
||||||
static DefaultDialog = D20RollDialog;
|
static DefaultDialog = D20RollDialog;
|
||||||
|
|
||||||
static async build(config = {}, message = {}) {
|
static async build(config = {}, message = {}) {
|
||||||
|
|
@ -92,9 +94,36 @@ export default class DHRoll extends Roll {
|
||||||
system: config,
|
system: config,
|
||||||
rolls: [roll]
|
rolls: [roll]
|
||||||
};
|
};
|
||||||
|
config.selectedRollMode ??= game.settings.get('core', 'rollMode');
|
||||||
if(roll._evaluated) return await cls.create(msg, { rollMode: config.selectedRollMode });
|
if(roll._evaluated) return await cls.create(msg, { rollMode: config.selectedRollMode });
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async render({flavor, template=this.constructor.CHAT_TEMPLATE, isPrivate=false, ...options}={}) {
|
||||||
|
if ( !this._evaluated ) return;
|
||||||
|
const chatData = await this._prepareChatRenderContext({flavor, isPrivate, ...options});
|
||||||
|
return foundry.applications.handlebars.renderTemplate(template, chatData);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
async _prepareChatRenderContext({flavor, isPrivate=false, ...options}={}) {
|
||||||
|
if(isPrivate) {
|
||||||
|
return {
|
||||||
|
user: game.user.id,
|
||||||
|
flavor: null,
|
||||||
|
title: "???",
|
||||||
|
roll: {
|
||||||
|
total: "??"
|
||||||
|
},
|
||||||
|
hasRoll: true,
|
||||||
|
isPrivate
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
options.message.system.user = game.user.id;
|
||||||
|
return options.message.system;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static applyKeybindings(config) {
|
static applyKeybindings(config) {
|
||||||
if (config.event)
|
if (config.event)
|
||||||
|
|
@ -207,7 +236,9 @@ export const registerRollDiceHooks = () => {
|
||||||
if (updates.length) {
|
if (updates.length) {
|
||||||
const target = actor.system.partner ?? actor;
|
const target = actor.system.partner ?? actor;
|
||||||
if (!['dead', 'unconcious'].some(x => actor.statuses.has(x))) {
|
if (!['dead', 'unconcious'].some(x => actor.statuses.has(x))) {
|
||||||
target.modifyResource(updates);
|
setTimeout(() => {
|
||||||
|
target.modifyResource(updates);
|
||||||
|
}, 50);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ export default class DualityRoll extends D20Roll {
|
||||||
}
|
}
|
||||||
if (this.rallyFaces)
|
if (this.rallyFaces)
|
||||||
this.terms.push(
|
this.terms.push(
|
||||||
new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }),
|
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||||
new foundry.dice.terms.Die({ faces: this.rallyFaces })
|
new foundry.dice.terms.Die({ faces: this.rallyFaces })
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,15 +124,20 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ChatMessage to display this document’s data.
|
||||||
|
* @param {String} origin - uuid of a document. TODO: This needs to be reviewed.
|
||||||
|
*/
|
||||||
async toChat(origin) {
|
async toChat(origin) {
|
||||||
|
/**@type {foundry.documents.ChatMessage} */
|
||||||
const cls = getDocumentClass('ChatMessage');
|
const cls = getDocumentClass('ChatMessage');
|
||||||
const actor = game.actors.get(cls.getSpeaker().actor);
|
const speaker = cls.getSpeaker();
|
||||||
|
const actor = cls.getSpeakerActor(speaker);
|
||||||
const systemData = {
|
const systemData = {
|
||||||
action: { img: this.img, name: this.name },
|
action: { img: this.img, name: this.name },
|
||||||
actor: { name: actor.name, img: actor.img },
|
actor: { name: actor?.name, img: actor?.img },
|
||||||
author: this.author,
|
speaker,
|
||||||
speaker: cls.getSpeaker(),
|
origin,
|
||||||
origin: origin,
|
|
||||||
description: this.description,
|
description: this.description,
|
||||||
actions: []
|
actions: []
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,31 @@
|
||||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
async renderHTML() {
|
async renderHTML() {
|
||||||
if (this.system.messageTemplate)
|
|
||||||
this.content = await foundry.applications.handlebars.renderTemplate(this.system.messageTemplate, {
|
|
||||||
...this.system,
|
|
||||||
_source: this.system._source
|
|
||||||
});
|
|
||||||
|
|
||||||
const actor = game.actors.get(this.speaker.actor);
|
const actor = game.actors.get(this.speaker.actor);
|
||||||
const actorData = actor ?? {
|
const actorData = actor && this.isContentVisible ? actor : {
|
||||||
img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg',
|
img: this.author.avatar ? this.author.avatar : 'icons/svg/mystery-man.svg',
|
||||||
name: ''
|
name: ''
|
||||||
};
|
};
|
||||||
/* 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 });
|
||||||
this.applyPermission(html);
|
|
||||||
|
|
||||||
if (this.type === 'dualityRoll') {
|
this.enrichChatMessage(html);
|
||||||
|
this.addChatListeners(html);
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
enrichChatMessage(html) {
|
||||||
|
const elements = html.querySelectorAll('[data-perm-id]');
|
||||||
|
elements.forEach(e => {
|
||||||
|
const uuid = e.dataset.permId,
|
||||||
|
document = fromUuidSync(uuid);
|
||||||
|
if (!document) return;
|
||||||
|
|
||||||
|
e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER'));
|
||||||
|
e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER'));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.isContentVisible && this.type === 'dualityRoll') {
|
||||||
html.classList.add('duality');
|
html.classList.add('duality');
|
||||||
switch (this.system.roll?.result?.duality) {
|
switch (this.system.roll?.result?.duality) {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
@ -29,36 +39,9 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.enrichChatMessage(html);
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPermission(html) {
|
addChatListeners(html) {
|
||||||
const elements = html.querySelectorAll('[data-perm-id]');
|
|
||||||
elements.forEach(e => {
|
|
||||||
const uuid = e.dataset.permId,
|
|
||||||
document = fromUuidSync(uuid);
|
|
||||||
if (!document) return;
|
|
||||||
|
|
||||||
e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER'));
|
|
||||||
e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER'));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
|
||||||
options.speaker = ChatMessage.getSpeaker();
|
|
||||||
const rollActorOwner = data.rolls?.[0]?.data?.parent?.owner;
|
|
||||||
if (rollActorOwner) {
|
|
||||||
data.author = rollActorOwner ? rollActorOwner.id : data.author;
|
|
||||||
await this.updateSource({ author: rollActorOwner ?? user });
|
|
||||||
}
|
|
||||||
|
|
||||||
return super._preCreate(data, options, rollActorOwner ?? user);
|
|
||||||
}
|
|
||||||
|
|
||||||
enrichChatMessage(html) {
|
|
||||||
html.querySelectorAll('.damage-button').forEach(element =>
|
html.querySelectorAll('.damage-button').forEach(element =>
|
||||||
element.addEventListener('click', this.onDamage.bind(this))
|
element.addEventListener('click', this.onDamage.bind(this))
|
||||||
);
|
);
|
||||||
|
|
@ -66,6 +49,16 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
html.querySelectorAll('.duality-action-effect').forEach(element =>
|
html.querySelectorAll('.duality-action-effect').forEach(element =>
|
||||||
element.addEventListener('click', this.onApplyEffect.bind(this))
|
element.addEventListener('click', this.onApplyEffect.bind(this))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
html.querySelectorAll('.roll-target').forEach(element => {
|
||||||
|
element.addEventListener('mouseenter', this.hoverTarget);
|
||||||
|
element.addEventListener('mouseleave', this.unhoverTarget);
|
||||||
|
element.addEventListener('click', this.clickTarget);
|
||||||
|
});
|
||||||
|
|
||||||
|
html.querySelectorAll('.button-target-selection').forEach(element => {
|
||||||
|
element.addEventListener('click', this.onTargetSelection.bind(this));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getTargetList() {
|
getTargetList() {
|
||||||
|
|
@ -146,4 +139,30 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
if (action) action.consume(this.system, true);
|
if (action) action.consume(this.system, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hoverTarget(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
||||||
|
if (!token?.controlled) token._onHoverIn(event, { hoverOutOthers: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
unhoverTarget(event) {
|
||||||
|
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
||||||
|
if (!token?.controlled) token._onHoverOut(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
clickTarget(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const token = canvas.tokens.get(event.currentTarget.dataset.token);
|
||||||
|
if (!token) {
|
||||||
|
ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.attackTargetDoesNotExist'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
game.canvas.pan(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
onTargetSelection(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.system.targetMode = Boolean(event.target.dataset.targetHit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -142,19 +142,16 @@ export default class DHItem extends foundry.documents.Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new ChatMessage to display this document’s data
|
||||||
|
* @param {String} origin - uuid of a document. TODO: This needs to be reviewed.
|
||||||
|
*/
|
||||||
async toChat(origin) {
|
async toChat(origin) {
|
||||||
|
/**@type {foundry.documents.ChatMessage} */
|
||||||
const cls = getDocumentClass('ChatMessage');
|
const cls = getDocumentClass('ChatMessage');
|
||||||
const item = await foundry.utils.fromUuid(origin);
|
const item = await foundry.utils.fromUuid(origin);
|
||||||
|
|
||||||
const systemData = {
|
const systemData = {
|
||||||
title:
|
|
||||||
this.type === 'ancestry'
|
|
||||||
? game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.ancestryTitle')
|
|
||||||
: this.type === 'community'
|
|
||||||
? game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.communityTitle')
|
|
||||||
: this.type === 'feature'
|
|
||||||
? game.i18n.localize('TYPES.Item.feature')
|
|
||||||
: game.i18n.localize('DAGGERHEART.UI.Chat.foundationCard.subclassFeatureTitle'),
|
|
||||||
origin: origin,
|
origin: origin,
|
||||||
img: this.img,
|
img: this.img,
|
||||||
item: {
|
item: {
|
||||||
|
|
@ -170,7 +167,6 @@ export default class DHItem extends foundry.documents.Item {
|
||||||
type: 'abilityUse',
|
type: 'abilityUse',
|
||||||
user: game.user.id,
|
user: game.user.id,
|
||||||
actor: item.parent,
|
actor: item.parent,
|
||||||
author: this.author,
|
|
||||||
speaker: cls.getSpeaker(),
|
speaker: cls.getSpeaker(),
|
||||||
system: systemData,
|
system: systemData,
|
||||||
title: game.i18n.localize('DAGGERHEART.ACTIONS.Config.displayInChat'),
|
title: game.i18n.localize('DAGGERHEART.ACTIONS.Config.displayInChat'),
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,7 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"chatDisplay": false,
|
"chatDisplay": false,
|
||||||
"actionType": "action",
|
"actionType": "action",
|
||||||
"cost": [
|
"cost": [],
|
||||||
{
|
|
||||||
"scalable": false,
|
|
||||||
"key": "hitPoints",
|
|
||||||
"value": 1,
|
|
||||||
"keyIsID": false,
|
|
||||||
"step": null,
|
|
||||||
"consumeOnSuccess": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"uses": {
|
"uses": {
|
||||||
"value": null,
|
"value": null,
|
||||||
"max": "1",
|
"max": "1",
|
||||||
|
|
@ -67,7 +58,7 @@
|
||||||
{
|
{
|
||||||
"key": "system.bonuses.rally",
|
"key": "system.bonuses.rally",
|
||||||
"mode": 2,
|
"mode": 2,
|
||||||
"value": "1d6",
|
"value": "d6",
|
||||||
"priority": null
|
"priority": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,7 @@
|
||||||
"description": "",
|
"description": "",
|
||||||
"chatDisplay": true,
|
"chatDisplay": true,
|
||||||
"actionType": "action",
|
"actionType": "action",
|
||||||
"cost": [
|
"cost": [],
|
||||||
{
|
|
||||||
"scalable": false,
|
|
||||||
"key": "hitPoints",
|
|
||||||
"value": 1,
|
|
||||||
"keyIsID": false,
|
|
||||||
"step": null,
|
|
||||||
"consumeOnSuccess": false
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"uses": {
|
"uses": {
|
||||||
"value": null,
|
"value": null,
|
||||||
"max": "1",
|
"max": "1",
|
||||||
|
|
@ -67,7 +58,7 @@
|
||||||
{
|
{
|
||||||
"key": "system.bonuses.rally",
|
"key": "system.bonuses.rally",
|
||||||
"mode": 2,
|
"mode": 2,
|
||||||
"value": "1d8",
|
"value": "d8",
|
||||||
"priority": null
|
"priority": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
"effects": [
|
"effects": [
|
||||||
{
|
{
|
||||||
"name": "Gifted Tracker",
|
"name": "Gifted Tracker",
|
||||||
"img": "icons/svg/item-bag.svg",
|
"img": "systems/daggerheart/assets/icons/domains/domain-card/sage.png",
|
||||||
"origin": "Compendium.daggerheart.domains.Item.VZ2b4zfRzV73XTuT",
|
"origin": "Compendium.daggerheart.domains.Item.VZ2b4zfRzV73XTuT",
|
||||||
"transfer": false,
|
"transfer": false,
|
||||||
"_id": "47Oh2weCdmuvKHM9",
|
"_id": "47Oh2weCdmuvKHM9",
|
||||||
|
|
@ -104,12 +104,12 @@
|
||||||
"compendiumSource": null,
|
"compendiumSource": null,
|
||||||
"duplicateSource": null,
|
"duplicateSource": null,
|
||||||
"exportSource": null,
|
"exportSource": null,
|
||||||
"coreVersion": "13.346",
|
"coreVersion": "13.347",
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"createdTime": 1754114056078,
|
"createdTime": 1754114056078,
|
||||||
"modifiedTime": 1754114073478,
|
"modifiedTime": 1754670410126,
|
||||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||||
},
|
},
|
||||||
"_key": "!items.effects!VZ2b4zfRzV73XTuT.47Oh2weCdmuvKHM9"
|
"_key": "!items.effects!VZ2b4zfRzV73XTuT.47Oh2weCdmuvKHM9"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -389,7 +389,7 @@
|
||||||
"effects": [
|
"effects": [
|
||||||
{
|
{
|
||||||
"name": "Healed by Healing Hands",
|
"name": "Healed by Healing Hands",
|
||||||
"img": "icons/svg/item-bag.svg",
|
"img": "systems/daggerheart/assets/icons/domains/domain-card/splendor.png",
|
||||||
"origin": "Compendium.daggerheart.domains.Item.WTlhnQMajc1r8i50",
|
"origin": "Compendium.daggerheart.domains.Item.WTlhnQMajc1r8i50",
|
||||||
"transfer": false,
|
"transfer": false,
|
||||||
"_id": "sd5liP4ZcVeTMAoW",
|
"_id": "sd5liP4ZcVeTMAoW",
|
||||||
|
|
@ -422,12 +422,12 @@
|
||||||
"compendiumSource": null,
|
"compendiumSource": null,
|
||||||
"duplicateSource": null,
|
"duplicateSource": null,
|
||||||
"exportSource": null,
|
"exportSource": null,
|
||||||
"coreVersion": "13.346",
|
"coreVersion": "13.347",
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"createdTime": 1754263407455,
|
"createdTime": 1754263407455,
|
||||||
"modifiedTime": 1754263727114,
|
"modifiedTime": 1754670504951,
|
||||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||||
},
|
},
|
||||||
"_key": "!items.effects!WTlhnQMajc1r8i50.sd5liP4ZcVeTMAoW"
|
"_key": "!items.effects!WTlhnQMajc1r8i50.sd5liP4ZcVeTMAoW"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@
|
||||||
"effects": [
|
"effects": [
|
||||||
{
|
{
|
||||||
"name": "Life Ward",
|
"name": "Life Ward",
|
||||||
"img": "icons/svg/item-bag.svg",
|
"img": "systems/daggerheart/assets/icons/domains/domain-card/splendor.png",
|
||||||
"origin": "Compendium.daggerheart.domains.Item.OszbCj0jTqq2ADx9",
|
"origin": "Compendium.daggerheart.domains.Item.OszbCj0jTqq2ADx9",
|
||||||
"transfer": false,
|
"transfer": false,
|
||||||
"_id": "E7Ou4OMEy3TeK1Gf",
|
"_id": "E7Ou4OMEy3TeK1Gf",
|
||||||
|
|
@ -99,12 +99,12 @@
|
||||||
"compendiumSource": null,
|
"compendiumSource": null,
|
||||||
"duplicateSource": null,
|
"duplicateSource": null,
|
||||||
"exportSource": null,
|
"exportSource": null,
|
||||||
"coreVersion": "13.346",
|
"coreVersion": "13.347",
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"createdTime": 1754264687962,
|
"createdTime": 1754264687962,
|
||||||
"modifiedTime": 1754264717646,
|
"modifiedTime": 1754670535710,
|
||||||
"lastModifiedBy": "Q9NoTaEarn3VMS6Z"
|
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||||
},
|
},
|
||||||
"_key": "!items.effects!OszbCj0jTqq2ADx9.E7Ou4OMEy3TeK1Gf"
|
"_key": "!items.effects!OszbCj0jTqq2ADx9.E7Ou4OMEy3TeK1Gf"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"_id": "UJTsJlnhi5Zi0XQ2",
|
"_id": "UJTsJlnhi5Zi0XQ2",
|
||||||
"img": "icons/magic/life/heart-cross-blue.webp",
|
"img": "systems/daggerheart/assets/icons/domains/domain-card/bone.png",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"key": "system.rules.damageReduction.thresholdImmunities.minor",
|
"key": "system.rules.damageReduction.thresholdImmunities.minor",
|
||||||
|
|
@ -67,12 +67,12 @@
|
||||||
"compendiumSource": null,
|
"compendiumSource": null,
|
||||||
"duplicateSource": null,
|
"duplicateSource": null,
|
||||||
"exportSource": null,
|
"exportSource": null,
|
||||||
"coreVersion": "13.346",
|
"coreVersion": "13.347",
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"createdTime": 1754303484332,
|
"createdTime": 1754303484332,
|
||||||
"modifiedTime": 1754303570504,
|
"modifiedTime": 1754670012467,
|
||||||
"lastModifiedBy": "MQSznptE5yLT7kj8"
|
"lastModifiedBy": "49DaecTcBSc5d0DA"
|
||||||
},
|
},
|
||||||
"_key": "!items.effects!zbxPl81kbWEegKQN.UJTsJlnhi5Zi0XQ2"
|
"_key": "!items.effects!zbxPl81kbWEegKQN.UJTsJlnhi5Zi0XQ2"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@
|
||||||
"image": {},
|
"image": {},
|
||||||
"text": {
|
"text": {
|
||||||
"format": 1,
|
"format": 1,
|
||||||
"content": "<blockquote><p>This product includes materials from the Daggerheart System Reference Document 1.0, © Critical Role, LLC. under the terms of the Darrington Press Community Gaming (DPCGL) License. More information can be found at <a href=\"https://www.daggerheart.com/\" title=\"Daggerheart Official Website\">https://www.daggerheart.com</a>. There are no previous modifications by others.</p><p></p></blockquote><h1>The Foundryborne Team</h1><p></p><p>The Foundryborne Team consists of:</p><p></p><ul><li><p><strong>@harryfuralle</strong></p></li><li><p><strong>@cptn_cosmo</strong></p></li><li><p><strong>@molilo</strong></p></li><li><p><strong>@joaquinp98</strong></p></li><li><p><strong>@dapoulp</strong></p></li><li><p>@ikraik</p></li><li><p>@irktheimp</p></li><li><p>@jacobwojo</p></li><li><p>@vyrth</p></li><li><p>@.ontaro</p></li><li><p>@saatsin</p></li><li><p>@david.xyz</p></li></ul><p></p><p>With Art from:</p><p></p><ul><li><p>UsernameIsInUse</p></li></ul><p></p><p>We would also like to thank the FoundryVTT team for their support in publishing this system.</p><p>And, of course, special thanks to the teams at Critical Role and Darrington Press for making such a wonderful game and updating the license to allow a FoundryVTT version of the system.</p><p></p><h1>The Foundryborne Community</h1><p></p><p>Without our amazing community this project would not have been possible.</p><p>You kept us going with both direct contributions and just endless support!</p><p>We thank you with all our hearts.</p><p><a href=\"https://foundryborne.online/\" title=\"Foundryborne official website\">Come join us!</a></p>"
|
"content": "<blockquote><p>This product includes materials from the Daggerheart System Reference Document 1.0, © Critical Role, LLC. under the terms of the Darrington Press Community Gaming (DPCGL) License. More information can be found at <a href=\"https://www.daggerheart.com/\" title=\"Daggerheart Official Website\">https://www.daggerheart.com</a>. There are no previous modifications by others.</p><p></p></blockquote><h1>The Foundryborne Team</h1><p></p><p>The Foundryborne Team consists of:</p><p></p><ul><li><p><strong>@harryfuralle</strong></p></li><li><p><strong>@cptn_cosmo</strong></p></li><li><p><strong>@molilo</strong></p></li><li><p><strong>@joaquinp98</strong></p></li><li><p><strong>@dapoulp</strong></p></li><li><p>@ikraik</p></li><li><p>@irktheimp</p></li><li><p>@jacobwojo</p></li><li><p>@vyrth</p></li><li><p>@.ontaro</p></li><li><p>@saatsin</p></li><li><p>@david.xyz</p></li><li><p>@<span style=\"color:oklab(0.988044 0.0000450313 0.0000197887);font-family:'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:oklab(0.262384 0.00252247 -0.00889932);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">lazjen</span></p></li></ul><p></p><p>With Art from:</p><p></p><ul><li><p>UsernameIsInUse</p></li></ul><p></p><p>And special thanks to our hard working community testers:<br /></p><ul><li><p><span style=\"color:oklab(0.988044 0.0000450313 0.0000197887);font-family:'gg sans', 'Noto Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:14px;font-style:normal;font-variant-ligatures:normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;orphans:2;text-align:start;text-indent:0px;text-transform:none;widows:2;word-spacing:0px;-webkit-text-stroke-width:0px;white-space:normal;background-color:oklab(0.262384 0.00252247 -0.00889932);text-decoration-thickness:initial;text-decoration-style:initial;text-decoration-color:initial;display:inline !important;float:none\">@lazjen</span></p></li></ul><p></p><p>We would also like to thank the FoundryVTT team for their support in publishing this system.</p><p>And, of course, special thanks to the teams at Critical Role and Darrington Press for making such a wonderful game and updating the license to allow a FoundryVTT version of the system.</p><p></p><h1>The Foundryborne Community</h1><p></p><p>Without our amazing community this project would not have been possible.</p><p>You kept us going with both direct contributions and just endless support!</p><p>We thank you with all our hearts.</p><p><a href=\"https://foundryborne.online/\" title=\"Foundryborne official website\">Come join us!</a></p>"
|
||||||
},
|
},
|
||||||
"video": {
|
"video": {
|
||||||
"controls": true,
|
"controls": true,
|
||||||
|
|
@ -153,8 +153,8 @@
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"createdTime": 1754225939902,
|
"createdTime": 1754225939902,
|
||||||
"modifiedTime": 1754226994508,
|
"modifiedTime": 1754668980876,
|
||||||
"lastModifiedBy": "l5jB3XmcVXOTQpRZ"
|
"lastModifiedBy": "Cf0YKwnZ1OHBZWl8"
|
||||||
},
|
},
|
||||||
"_key": "!journal.pages!g7NhKvwltwafmMyR.dP6xSKEld4TSqHhK"
|
"_key": "!journal.pages!g7NhKvwltwafmMyR.dP6xSKEld4TSqHhK"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"_id": "RSmscgGyuHJucF6C",
|
"_id": "RSmscgGyuHJucF6C",
|
||||||
"img": "icons/magic/life/heart-cross-blue.webp",
|
"img": "icons/sundries/documents/document-letter-blue.webp",
|
||||||
"changes": [
|
"changes": [
|
||||||
{
|
{
|
||||||
"key": "system.bonuses.rally",
|
"key": "system.bonuses.rally",
|
||||||
|
|
@ -53,10 +53,11 @@
|
||||||
"compendiumSource": null,
|
"compendiumSource": null,
|
||||||
"duplicateSource": null,
|
"duplicateSource": null,
|
||||||
"exportSource": null,
|
"exportSource": null,
|
||||||
"coreVersion": "13.346",
|
"coreVersion": "13.347",
|
||||||
"systemId": "daggerheart",
|
"systemId": "daggerheart",
|
||||||
"systemVersion": "0.0.1",
|
"systemVersion": "0.0.1",
|
||||||
"lastModifiedBy": null
|
"lastModifiedBy": "49DaecTcBSc5d0DA",
|
||||||
|
"modifiedTime": 1754669077252
|
||||||
},
|
},
|
||||||
"_key": "!items.effects!eCoEWkWuZPMZ9C6a.RSmscgGyuHJucF6C"
|
"_key": "!items.effects!eCoEWkWuZPMZ9C6a.RSmscgGyuHJucF6C"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
.message-header-metadata {
|
.message-header-metadata {
|
||||||
flex: none;
|
flex: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
.message-metadata {
|
.message-metadata {
|
||||||
font-family: @font-body;
|
font-family: @font-body;
|
||||||
|
|
@ -73,6 +74,13 @@
|
||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
|
.flavor-text {
|
||||||
|
font-size: var(--font-size-12);
|
||||||
|
line-height: 20px;
|
||||||
|
color: var(--color-dark-4);
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,333 +11,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* &.roll {
|
|
||||||
.dice-flavor {
|
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
.dice-tooltip {
|
|
||||||
.dice-rolls {
|
|
||||||
&.duality {
|
|
||||||
display: flex;
|
|
||||||
gap: 0.25rem;
|
|
||||||
|
|
||||||
> .roll {
|
|
||||||
background-image: none;
|
|
||||||
|
|
||||||
.reroll-button {
|
|
||||||
border: none;
|
|
||||||
background: initial;
|
|
||||||
width: 42px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--button-background-color);
|
|
||||||
border: 1px solid var(--button-border-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.rerollable {
|
|
||||||
position: relative;
|
|
||||||
flex: none;
|
|
||||||
|
|
||||||
.dice-rerolled {
|
|
||||||
z-index: 2;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reroll-button {
|
|
||||||
border: none;
|
|
||||||
background: initial;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--button-background-color);
|
|
||||||
border: 1px solid var(--button-border-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// margin: 0;
|
|
||||||
> .roll {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 4px;
|
|
||||||
margin-bottom: 4px;
|
|
||||||
|
|
||||||
.dice-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 2px;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.dice-title {
|
|
||||||
color: var(--color-light-1);
|
|
||||||
text-shadow: 0 0 1px black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-rerolled {
|
|
||||||
z-index: 2;
|
|
||||||
position: absolute;
|
|
||||||
right: -2px;
|
|
||||||
font-size: 12px;
|
|
||||||
cursor: help;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-inner-container {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: relative;
|
|
||||||
&.hope,
|
|
||||||
&.fear {
|
|
||||||
.dice-wrapper {
|
|
||||||
clip-path: polygon(
|
|
||||||
50% 0%,
|
|
||||||
80% 10%,
|
|
||||||
100% 35%,
|
|
||||||
100% 70%,
|
|
||||||
80% 90%,
|
|
||||||
50% 100%,
|
|
||||||
20% 90%,
|
|
||||||
0% 70%,
|
|
||||||
0% 35%,
|
|
||||||
20% 10%
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.dice-wrapper {
|
|
||||||
height: 24px;
|
|
||||||
width: 24px;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
.dice {
|
|
||||||
height: 26px;
|
|
||||||
width: 26px;
|
|
||||||
max-width: unset;
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-value {
|
|
||||||
position: absolute;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hope {
|
|
||||||
.dice-wrapper {
|
|
||||||
background: black;
|
|
||||||
|
|
||||||
.dice {
|
|
||||||
filter: brightness(0) saturate(100%) invert(79%) sepia(79%) saturate(333%)
|
|
||||||
hue-rotate(352deg) brightness(102%) contrast(103%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-value {
|
|
||||||
color: var(--color-dark-1);
|
|
||||||
text-shadow: 0 0 4px white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.fear {
|
|
||||||
.dice-wrapper {
|
|
||||||
background: white;
|
|
||||||
|
|
||||||
.dice {
|
|
||||||
filter: brightness(0) saturate(100%) invert(12%) sepia(88%) saturate(4321%)
|
|
||||||
hue-rotate(221deg) brightness(92%) contrast(110%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-value {
|
|
||||||
color: var(--color-light-1);
|
|
||||||
text-shadow: 0 0 4px black;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.advantage {
|
|
||||||
.dice-wrapper {
|
|
||||||
.dice {
|
|
||||||
filter: brightness(0) saturate(100%) invert(18%) sepia(92%) saturate(4133%)
|
|
||||||
hue-rotate(96deg) brightness(104%) contrast(107%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.disadvantage {
|
|
||||||
.dice-wrapper {
|
|
||||||
.dice {
|
|
||||||
filter: brightness(0) saturate(100%) invert(9%) sepia(78%) saturate(6903%)
|
|
||||||
hue-rotate(11deg) brightness(93%) contrast(117%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.damage-resource {
|
|
||||||
font-weight: 600;
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-total {
|
|
||||||
&.duality {
|
|
||||||
&.hope {
|
|
||||||
border-color: @hope;
|
|
||||||
border-width: 3px;
|
|
||||||
background: rgba(@hope, 0.5);
|
|
||||||
}
|
|
||||||
&.fear {
|
|
||||||
border-color: @fear;
|
|
||||||
border-width: 3px;
|
|
||||||
background: rgba(@fear, 0.5);
|
|
||||||
}
|
|
||||||
&.critical {
|
|
||||||
border-color: @critical;
|
|
||||||
border-width: 3px;
|
|
||||||
background: rgba(@critical, 0.5);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-total-value {
|
|
||||||
.hope {
|
|
||||||
color: @hope;
|
|
||||||
}
|
|
||||||
.fear {
|
|
||||||
color: @fear;
|
|
||||||
}
|
|
||||||
.critical {
|
|
||||||
color: @critical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-total-label {
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-variant: all-small-caps;
|
|
||||||
margin: -@fullMargin 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.target-selection {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-around;
|
|
||||||
input[type='radio'] {
|
|
||||||
display: none;
|
|
||||||
&:checked + label {
|
|
||||||
text-shadow: 0px 0px 4px #ce5937;
|
|
||||||
}
|
|
||||||
&:not(:checked) + label {
|
|
||||||
opacity: 0.75;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.75;
|
|
||||||
&.target-selected {
|
|
||||||
text-shadow: 0px 0px 4px #ce5937;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.target-section {
|
|
||||||
margin-top: 5px;
|
|
||||||
|
|
||||||
.target-container {
|
|
||||||
display: flex;
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
filter: drop-shadow(0 0 3px @secondaryShadow);
|
|
||||||
border-color: gold;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hidden {
|
|
||||||
display: none;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hit {
|
|
||||||
background: @hit;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.miss {
|
|
||||||
background: @miss;
|
|
||||||
}
|
|
||||||
|
|
||||||
img,
|
|
||||||
.target-save-container {
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
align-self: center;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
flex: 0;
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.target-save-container {
|
|
||||||
margin-right: 8px;
|
|
||||||
justify-content: center;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
min-height: unset;
|
|
||||||
border: 1px solid black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.target-inner-container {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: var(--font-size-16);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:has(.target-save-container)) .target-inner-container {
|
|
||||||
margin-right: @hugeMargin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-actions {
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
|
|
||||||
button {
|
|
||||||
flex: 1;
|
|
||||||
height: 40px;
|
|
||||||
font-family: @font-body;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dice-result {
|
|
||||||
.roll-damage-button,
|
|
||||||
.damage-button,
|
|
||||||
.duality-action {
|
|
||||||
margin-top: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.expanded) .dice-tooltip {
|
|
||||||
grid-template-rows: 0fr;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
button {
|
button {
|
||||||
&.inner-button {
|
&.inner-button {
|
||||||
--button-size: 1.25rem;
|
--button-size: 1.25rem;
|
||||||
|
|
@ -349,19 +22,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-use-perm='false'] {
|
|
||||||
pointer-events: none;
|
|
||||||
border-color: transparent;
|
|
||||||
}
|
|
||||||
[data-view-perm='false'] {
|
|
||||||
> * {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
&::after {
|
|
||||||
content: '??';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.daggerheart,
|
.daggerheart,
|
||||||
|
|
@ -370,6 +30,19 @@
|
||||||
--text-color: light-dark(@dark-blue, @golden);
|
--text-color: light-dark(@dark-blue, @golden);
|
||||||
--bg-color: light-dark(@dark-blue-40, @golden-40);
|
--bg-color: light-dark(@dark-blue-40, @golden-40);
|
||||||
|
|
||||||
|
[data-use-perm='false'] {
|
||||||
|
pointer-events: none;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
[data-view-perm='false'] {
|
||||||
|
&[data-perm-hidden='true'], > * {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
content: '??';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.duality {
|
&.duality {
|
||||||
&.hope {
|
&.hope {
|
||||||
--text-color: @golden;
|
--text-color: @golden;
|
||||||
|
|
@ -412,7 +85,7 @@
|
||||||
grid-template-columns: 1fr auto 1fr;
|
grid-template-columns: 1fr auto 1fr;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: light-dark(@dark, @beige);
|
color: light-dark(@dark, @beige);
|
||||||
margin: 5px 0;
|
margin: 10px 0;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -450,7 +123,6 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
padding: 5px 0;
|
|
||||||
|
|
||||||
.dice-tooltip {
|
.dice-tooltip {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -489,6 +161,7 @@
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
font-family: 'Cinzel', sans-serif;
|
font-family: 'Cinzel', sans-serif;
|
||||||
|
line-height: .75;
|
||||||
|
|
||||||
.roll-result-value {
|
.roll-result-value {
|
||||||
font-size: var(--font-size-24);
|
font-size: var(--font-size-24);
|
||||||
|
|
@ -503,10 +176,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.roll-difficulty {
|
|
||||||
margin-top: -5px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,7 +249,7 @@
|
||||||
.button-target-selection {
|
.button-target-selection {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 5px 0;
|
margin: -5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-target-selection:hover,
|
.button-target-selection:hover,
|
||||||
|
|
@ -600,6 +269,11 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255,255,255,.1);
|
||||||
|
}
|
||||||
|
|
||||||
.target-img {
|
.target-img {
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|
@ -640,6 +314,7 @@
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.roll-difficulty,
|
.roll-difficulty,
|
||||||
|
|
@ -706,6 +381,19 @@
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.damage-section[data-action='expandRoll'] {
|
||||||
|
.on-reduced {
|
||||||
|
.wrapper {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.roll-formula {
|
||||||
|
font-size: var(--font-size-16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.target-section {
|
.target-section {
|
||||||
.roll-part-content {
|
.roll-part-content {
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,29 @@
|
||||||
<li class="scalable-input">
|
<li class="scalable-input">
|
||||||
<div class="form-group span-2">
|
<div class="form-group span-2">
|
||||||
<div class="form-fields nest-inputs">
|
<div class="form-fields nest-inputs">
|
||||||
<input name="uses.enabled" type="checkbox"{{#if uses.enabled}} checked{{/if}}>
|
<input id="action-uses" name="uses.enabled" type="checkbox"{{#if uses.enabled}} checked{{/if}}>
|
||||||
<label for="uses.enabled">Uses{{#if uses.consumeOnSuccess}}<span class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.short"}}{{/if}}</span></label>
|
<label for="action-uses">Uses{{#if uses.consumeOnSuccess}}<span class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.short"}}{{/if}}</span></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<label class="modifier-label">1/{{uses.remaining}}</label>
|
<label class="modifier-label" for="action-uses">1/{{uses.remaining}}</label>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#each costs as | cost index |}}
|
{{#each costs as | cost index |}}
|
||||||
<li class="scalable-input">
|
<li class="scalable-input">
|
||||||
<div class="form-group{{#unless (and scalable maxStep)}} span-2{{/unless}}">
|
<div class="form-group{{#unless (and scalable maxStep)}} span-2{{/unless}}">
|
||||||
<div class="form-fields nest-inputs">
|
<div class="form-fields nest-inputs">
|
||||||
<input name="costs.{{index}}.enabled" type="checkbox"{{#if enabled}} checked{{/if}}>
|
<input id="action-costs-{{index}}" name="costs.{{index}}.enabled" type="checkbox"{{#if enabled}} checked{{/if}}>
|
||||||
<label>{{label}}{{#if cost.consumeOnSuccess}}<span class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.short"}}</span>{{/if}}</label>
|
<label for="action-costs-{{index}}">
|
||||||
|
{{label}}
|
||||||
|
{{#if cost.consumeOnSuccess}}<span class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.short"}}</span>{{/if}}
|
||||||
|
{{#if cost.extKey}}<span class="hint">{{name}}</span>{{/if}}
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if (and scalable maxStep)}}
|
{{#if (and scalable maxStep)}}
|
||||||
<input type="range" value="{{scale}}" min="0" max="{{maxStep}}" step="1" name="costs.{{index}}.scale" data-tooltip="{{localize "DAGGERHEART.ACTIONS.Settings.cost.stepTooltip" step=step}}" data-tooltip-direction="UP">
|
<input type="range" value="{{scale}}" min="0" max="{{maxStep}}" step="1" name="costs.{{index}}.scale" data-tooltip="{{localize "DAGGERHEART.ACTIONS.Settings.cost.stepTooltip" step=step}}" data-tooltip-direction="UP">
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<label class="modifier-label">{{total}}/{{max}}</label>
|
<label class="modifier-label" for="action-costs-{{index}}">{{total}}/{{max}}</label>
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ Parameters:
|
||||||
<legend>
|
<legend>
|
||||||
{{localize title}}
|
{{localize title}}
|
||||||
{{#if canCreate}}
|
{{#if canCreate}}
|
||||||
<a data-action="{{ifThen (or (eq type 'effect') (eq type 'feature')) 'createDoc' 'addNewItem' }}" data-document-class="{{ifThen (eq type 'effect') 'ActiveEffect' 'Item' }}"
|
<a data-action="{{ifThen (or (eq type 'effect') (eq type 'feature') (eq type 'action')) 'createDoc' 'addNewItem' }}" data-document-class="{{ifThen (eq type 'effect') 'ActiveEffect' 'Item' }}"
|
||||||
data-type="{{ifThen (eq type 'effect') 'base' type}}"
|
data-type="{{ifThen (eq type 'effect') 'base' type}}"
|
||||||
{{#if inVault}}data-in-vault="{{inVault}}"{{/if}}
|
{{#if inVault}}data-in-vault="{{inVault}}"{{/if}}
|
||||||
{{#if disabled}} data-disabled="{{disabled}}"{{/if}}
|
{{#if disabled}} data-disabled="{{disabled}}"{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,19 @@
|
||||||
<header class="message-header flexrow">
|
<header class="message-header flexrow">
|
||||||
<div class="message-header-main">
|
<div class="message-header-main">
|
||||||
<img class="actor-img" src="{{actor.img}}" />
|
<img class="actor-img" src="{{actor.img}}" />
|
||||||
{{#if (eq message.type 'base')}}
|
<div class="message-sub-header-container">
|
||||||
<div class="message-sub-header-container">
|
{{#unless actor.name}}
|
||||||
<h4>{{actor.name}}</h4>
|
<h4>{{author.name}}</h4>
|
||||||
<div>{{author.name}}</div>
|
{{else}}
|
||||||
</div>
|
{{#if (eq message.type 'base')}}
|
||||||
{{else}}
|
<h4>{{actor.name}}</h4>
|
||||||
<div class="message-sub-header-container">
|
<div>{{author.name}}</div>
|
||||||
<h4>{{ifThen message.title message.title alias}}</h4>
|
{{else}}
|
||||||
<div>{{actor.name}} {{#if author.isGM}}(GM){{/if}}</div>
|
<h4>{{ifThen message.title message.title alias}}</h4>
|
||||||
</div>
|
<div>{{actor.name}} {{#if author.isGM}}(GM){{/if}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-header-metadata">
|
<div class="message-header-metadata">
|
||||||
<span class="message-metadata">
|
<span class="message-metadata">
|
||||||
|
|
@ -33,13 +35,12 @@
|
||||||
{{#if isWhisper}}
|
{{#if isWhisper}}
|
||||||
<span class="whisper-to">{{localize 'CHAT.To'}}: {{whisperTo}}</span>
|
<span class="whisper-to">{{localize 'CHAT.To'}}: {{whisperTo}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if message.flavor}}
|
|
||||||
<span class="flavor-text">{{{message.flavor}}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
{{{message.content}}}
|
{{{message.content}}}
|
||||||
|
{{#if message.flavor}}
|
||||||
|
<span class="flavor-text">{{{message.flavor}}}</span>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
<div class="roll-buttons">
|
<div class="roll-buttons">
|
||||||
{{#if hasDamage}}
|
{{#if hasDamage}}
|
||||||
{{#unless (empty damage)}}
|
{{#unless (empty damage)}}
|
||||||
<button class="duality-action damage-button">{{localize "DAGGERHEART.UI.Chat.damageRoll.dealDamage"}}</button>
|
{{#if canButtonApply}}<button class="duality-action damage-button">{{localize "DAGGERHEART.UI.Chat.damageRoll.dealDamage"}}</button>{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<button class="duality-action duality-action-damage">{{localize "DAGGERHEART.UI.Chat.attackRoll.rollDamage"}}</button>
|
<button class="duality-action duality-action-damage">{{localize "DAGGERHEART.UI.Chat.attackRoll.rollDamage"}}</button>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if hasHealing}}
|
{{#if hasHealing}}
|
||||||
{{#unless (empty damage)}}
|
{{#unless (empty damage)}}
|
||||||
<button class="duality-action damage-button">{{localize "DAGGERHEART.UI.Chat.healingRoll.applyHealing"}}</button>
|
{{#if canButtonApply}}<button class="duality-action damage-button">{{localize "DAGGERHEART.UI.Chat.healingRoll.applyHealing"}}</button>{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<button class="duality-action duality-action-damage">{{localize "DAGGERHEART.UI.Chat.attackRoll.rollHealing"}}</button>
|
<button class="duality-action duality-action-damage">{{localize "DAGGERHEART.UI.Chat.attackRoll.rollHealing"}}</button>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if hasEffect}}<button class="duality-action-effect">{{localize "DAGGERHEART.UI.Chat.attackRoll.applyEffect"}}</button>{{/if}}
|
{{#if (and hasEffect canButtonApply)}}<button class="duality-action-effect">{{localize "DAGGERHEART.UI.Chat.attackRoll.applyEffect"}}</button>{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -14,14 +14,15 @@
|
||||||
</div>
|
</div>
|
||||||
{{#if roll.difficulty}}
|
{{#if roll.difficulty}}
|
||||||
<span class="roll-difficulty{{#unless roll.success}} is-miss{{/unless}}">
|
<span class="roll-difficulty{{#unless roll.success}} is-miss{{/unless}}">
|
||||||
{{#if canViewSecret}}
|
{{!-- {{#if canViewSecret}} --}}
|
||||||
difficulty {{roll.difficulty}}
|
difficulty {{roll.difficulty}}
|
||||||
{{else}}
|
{{!-- {{else}}
|
||||||
{{localize (ifThen roll.success "DAGGERHEART.GENERAL.success" "DAGGERHEART.GENERAL.failure")}}
|
{{localize (ifThen roll.success "DAGGERHEART.GENERAL.success" "DAGGERHEART.GENERAL.failure")}}
|
||||||
{{/if}}
|
{{/if}} --}}
|
||||||
</span>
|
</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
{{#unless isPrivate}}
|
||||||
<div class="dice-roll" data-action="expandRoll">
|
<div class="dice-roll" data-action="expandRoll">
|
||||||
<div class="roll-part-header"><div><span>{{localize "DAGGERHEART.GENERAL.formula"}}</span></div></div>
|
<div class="roll-part-header"><div><span>{{localize "DAGGERHEART.GENERAL.formula"}}</span></div></div>
|
||||||
<div class="roll-part-content dice-result">
|
<div class="roll-part-content dice-result">
|
||||||
|
|
@ -87,4 +88,5 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<div class="roll-part-content dice-result">
|
<div class="roll-part-content dice-result">
|
||||||
<div class="dice-tooltip">
|
<div class="dice-tooltip">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
{{#if targets.length}}
|
{{#if (and parent.isAuthor targets.length)}}
|
||||||
<div class="target-selector">
|
<div class="target-selector">
|
||||||
<div class="roll-part-header"><div></div></div>
|
<div class="roll-part-header"><div></div></div>
|
||||||
<div class="target-choice">
|
<div class="target-choice">
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
<div class="roll-target" data-token="{{id}}">
|
<div class="roll-target" data-token="{{id}}">
|
||||||
<img class="target-img" src="{{img}}">
|
<img class="target-img" src="{{img}}">
|
||||||
<div class="target-data">
|
<div class="target-data">
|
||||||
<div class="target-name" data-perm-id="{{actorId}}">{{name}}</div>
|
<div class="target-name" data-perm-id="{{actorId}}"><span>{{name}}</span></div>
|
||||||
{{#if (and ../targetSelection ../hasRoll)}}
|
{{#if (and ../targetSelection ../hasRoll)}}
|
||||||
<div class="target-hit-status {{#if hit}}is-hit{{else}}is-miss{{/if}}">
|
<div class="target-hit-status {{#if hit}}is-hit{{else}}is-miss{{/if}}">
|
||||||
{{#if hit}}
|
{{#if hit}}
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{#if (and ../hasSave (or hit (not @root.targetSelection)))}}
|
{{#if (and ../hasSave (or hit (not @root.hasRoll)))}}
|
||||||
<div class="target-save{{#if saved.result includeZero=true}} is-rolled{{/if}}" data-perm-id="{{actorId}}">
|
<div class="target-save{{#if saved.result includeZero=true}} is-rolled{{/if}}" data-perm-id="{{actorId}}">
|
||||||
<i class="fa-solid {{#if saved.result includeZero=true}}{{#if saved.success}}fa-check{{else}}fa-xmark{{/if}}{{else}}fa-shield{{/if}} fa-lg"></i>
|
<i class="fa-solid {{#if saved.result includeZero=true}}{{#if saved.success}}fa-check{{else}}fa-xmark{{/if}}{{else}}fa-shield{{/if}} fa-lg"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@
|
||||||
{{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
|
{{#if hasTarget}}{{> 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs'}}{{/if}}
|
||||||
<div class="roll-part-header"><div></div></div>
|
<div class="roll-part-header"><div></div></div>
|
||||||
</div>
|
</div>
|
||||||
{{> 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs'}}
|
{{#if (or parent.isAuthor canButtonApply)}}{{> 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs'}}{{/if}}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue