Added triggerChatRollFx

This commit is contained in:
WBHarry 2026-05-28 23:57:34 +02:00
parent 17b9719c09
commit 6cb31ac3b7
13 changed files with 65 additions and 67 deletions

View file

@ -358,8 +358,6 @@ export default class GroupRollDialog extends HandlebarsApplicationMixin(Applicat
}); });
if (!result) return; if (!result) return;
// todo: move logic to actor.rollTrait() or actor.diceRoll()
if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
const rollData = result.messageRoll.toJSON(); const rollData = result.messageRoll.toJSON();
delete rollData.options.messageRoll; delete rollData.options.messageRoll;

View file

@ -1,4 +1,4 @@
import { itemAbleRollParse } from '../../helpers/utils.mjs'; import { itemAbleRollParse, triggerChatRollFx } from '../../helpers/utils.mjs';
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api; const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
@ -69,7 +69,7 @@ export default class ResourceDiceDialog extends HandlebarsApplicationMixin(Appli
const max = itemAbleRollParse(this.item.system.resource.max, this.actor, this.item); const max = itemAbleRollParse(this.item.system.resource.max, this.actor, this.item);
const diceFormula = `${max}${this.item.system.resource.dieFaces}`; const diceFormula = `${max}${this.item.system.resource.dieFaces}`;
const roll = await new Roll(diceFormula).evaluate(); const roll = await new Roll(diceFormula).evaluate();
if (game.modules.get('dice-so-nice')?.active) await game.dice3d.showForRoll(roll, game.user, true); await triggerChatRollFx([roll]);
this.rollValues = roll.terms[0].results.map(x => ({ value: x.result, used: false })); this.rollValues = roll.terms[0].results.map(x => ({ value: x.result, used: false }));
this.resetUsed = true; this.resetUsed = true;

View file

@ -434,8 +434,6 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
if (!result) return; if (!result) return;
if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
const rollData = result.messageRoll.toJSON(); const rollData = result.messageRoll.toJSON();
delete rollData.options.messageRoll; delete rollData.options.messageRoll;
this.updatePartyData( this.updatePartyData(

View file

@ -1,3 +1,5 @@
import { triggerChatRollFx } from '../../helpers/utils.mjs';
const fields = foundry.data.fields; const fields = foundry.data.fields;
const targetsField = () => const targetsField = () =>
@ -154,12 +156,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
partData.roll = rerolled.toJSON(); partData.roll = rerolled.toJSON();
} }
if (game.modules.get('dice-so-nice')?.active) { await triggerChatRollFx(rerolls);
const rerollPromises = rerolls.map(roll => game.dice3d.showForRoll(roll, game.user, true));
await Promise.allSettled(rerollPromises);
} else {
foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
}
return update; return update;
} }

View file

@ -72,9 +72,6 @@ export default class DamageField extends fields.SchemaField {
damageConfig.source.message = messageId; damageConfig.source.message = messageId;
damageConfig.directDamage = !!damageConfig.source?.message; damageConfig.directDamage = !!damageConfig.source?.message;
// if(damageConfig.source?.message && game.modules.get('dice-so-nice')?.active)
// await game.dice3d.waitFor3DAnimationByMessageID(damageConfig.source.message);
const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig); const damageResult = await CONFIG.Dice.daggerheart.DamageRoll.build(damageConfig);
if (!damageResult) return false; if (!damageResult) return false;
if (damageResult.actionChatMessageHandled) config.actionChatMessageHandled = true; if (damageResult.actionChatMessageHandled) config.actionChatMessageHandled = true;

View file

@ -1,4 +1,4 @@
import { itemAbleRollParse } from '../../../helpers/utils.mjs'; import { itemAbleRollParse, triggerChatRollFx } from '../../../helpers/utils.mjs';
import FormulaField from '../formulaField.mjs'; import FormulaField from '../formulaField.mjs';
const fields = foundry.data.fields; const fields = foundry.data.fields;
@ -40,7 +40,7 @@ export default class DHSummonField extends fields.ArrayField {
const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item)); const roll = new Roll(itemAbleRollParse(summon.count, this.actor, this.item));
await roll.evaluate(); await roll.evaluate();
const count = roll.total; const count = roll.total;
if (!roll.isDeterministic && game.modules.get('dice-so-nice')?.active) rolls.push(roll); if (!roll.isDeterministic) rolls.push(roll);
const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID)); const actor = await DHSummonField.getWorldActor(await foundry.utils.fromUuid(summon.actorUUID));
/* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */ /* Extending summon data in memory so it's available in actionField.toChat. Think it's harmless, but ugly. Could maybe find a better way. */
@ -56,7 +56,7 @@ export default class DHSummonField extends fields.ArrayField {
} }
} }
if (rolls.length) await Promise.all(rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true))); if (rolls.length) await triggerChatRollFx(rolls);
this.actor.sheet?.minimize(); this.actor.sheet?.minimize();
DHSummonField.handleSummon(summonData, this.actor); DHSummonField.handleSummon(summonData, this.actor);

View file

@ -1,4 +1,5 @@
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
import { triggerChatRollFx } from '../helpers/utils.mjs';
import DHRoll from './dhRoll.mjs'; import DHRoll from './dhRoll.mjs';
export default class D20Roll extends DHRoll { export default class D20Roll extends DHRoll {
@ -230,11 +231,7 @@ export default class D20Roll extends DHRoll {
if (this instanceof game.system.api.dice.DualityRoll) return result; if (this instanceof game.system.api.dice.DualityRoll) return result;
if (options?.liveRoll) { if (options?.liveRoll) {
if (game.modules.get('dice-so-nice')?.active) { await triggerChatRollFx([result]);
await game.dice3d.showForRoll(result, game.user, true);
} else {
foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
}
} }
return result; return result;

View file

@ -1,5 +1,5 @@
import DamageDialog from '../applications/dialogs/damageDialog.mjs'; import DamageDialog from '../applications/dialogs/damageDialog.mjs';
import { parseRallyDice } from '../helpers/utils.mjs'; import { parseRallyDice, triggerChatRollFx } from '../helpers/utils.mjs';
import DHRoll from './dhRoll.mjs'; import DHRoll from './dhRoll.mjs';
export default class DamageRoll extends DHRoll { export default class DamageRoll extends DHRoll {
@ -43,25 +43,24 @@ export default class DamageRoll extends DHRoll {
const chatMessage = config.source?.message const chatMessage = config.source?.message
? ui.chat.collection.get(config.source.message) ? ui.chat.collection.get(config.source.message)
: getDocumentClass('ChatMessage').applyMode({}, config.rollMode ?? 'public'); : getDocumentClass('ChatMessage').applyMode({}, config.rollMode ?? 'public');
const diceRolls = [];
if (game.modules.get('dice-so-nice')?.active) { if (game.modules.get('dice-so-nice')?.active) {
const pool = foundry.dice.terms.PoolTerm.fromRolls(
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
),
diceRoll = Roll.fromTerms([pool]);
await game.dice3d.showForRoll(
diceRoll,
game.user,
true,
chatMessage.whisper?.length > 0 ? chatMessage.whisper : null,
chatMessage.blind
);
config.mute = true; config.mute = true;
const pool = foundry.dice.terms.PoolTerm.fromRolls(
Object.values(config.damage).flatMap(r => r.parts.map(p => p.roll))
);
diceRolls.push(Roll.fromTerms([pool]));
} }
await triggerChatRollFx(diceRolls, {
whisper: chatMessage.whisper?.length > 0 ? chatMessage.whisper : null,
blind: chatMessage.blind
});
await super.buildPost(roll, config, message); await super.buildPost(roll, config, message);
if (config.source?.message) { if (config.source?.message) {
chatMessage.update({ 'system.damage': config.damage }); chatMessage.update({ 'system.damage': config.damage });
if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
} }
} }
@ -324,9 +323,10 @@ export default class DamageRoll extends DHRoll {
const newIndex = parsedDiceTerms[dice].results.length; const newIndex = parsedDiceTerms[dice].results.length;
await term.reroll(`/r1=${termResult.result}`); await term.reroll(`/r1=${termResult.result}`);
const diceRolls = [];
if (game.modules.get('dice-so-nice')?.active) { if (game.modules.get('dice-so-nice')?.active) {
const newResult = parsedDiceTerms[dice].results[newIndex]; const newResult = parsedDiceTerms[dice].results[newIndex];
const diceSoNiceRoll = { diceRolls.push({
_evaluated: true, _evaluated: true,
dice: [ dice: [
new foundry.dice.terms.Die({ new foundry.dice.terms.Die({
@ -337,11 +337,10 @@ export default class DamageRoll extends DHRoll {
}) })
], ],
options: { appearance: {} } options: { appearance: {} }
}; });
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
} }
await triggerChatRollFx(diceRolls);
await parsedRoll.evaluate(); await parsedRoll.evaluate();
const results = parsedRoll.dice[dice].results.map(result => ({ const results = parsedRoll.dice[dice].results.map(result => ({

View file

@ -1,4 +1,5 @@
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs'; import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
import { triggerChatRollFx } from '../helpers/utils.mjs';
export default class DHRoll extends Roll { export default class DHRoll extends Roll {
baseTerms = []; baseTerms = [];
@ -75,9 +76,7 @@ export default class DHRoll extends Roll {
} }
if (config.skips?.createMessage) { if (config.skips?.createMessage) {
if (game.modules.get('dice-so-nice')?.active) { await triggerChatRollFx([roll]);
await game.dice3d.showForRoll(roll, game.user, true);
}
} else if (!config.source?.message) { } else if (!config.source?.message) {
config.message = await this.toMessage(roll, config); config.message = await this.toMessage(roll, config);
} }

View file

@ -1,5 +1,4 @@
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs'; import { updateResourcesForDualityReroll } from '../helpers.mjs';
import DualityRoll from '../dualityRoll.mjs';
export default class DualityDie extends foundry.dice.terms.Die { export default class DualityDie extends foundry.dice.terms.Die {
constructor(options) { constructor(options) {
@ -40,7 +39,7 @@ export default class DualityDie extends foundry.dice.terms.Die {
if (options.liveRoll.isReaction) return; if (options.liveRoll.isReaction) return;
const newDuality = this.#getDualityState(options.liveRoll.roll); const newDuality = this.#getDualityState(options.liveRoll.roll);
DualityRoll.updateResources(oldDuality, newDuality, options.liveRoll.actor); updateResourcesForDualityReroll(oldDuality, newDuality, options.liveRoll.actor);
} }
} }

View file

@ -2,7 +2,7 @@ import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
import D20Roll from './d20Roll.mjs'; import D20Roll from './d20Roll.mjs';
import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs'; import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
import { getDiceSoNicePresets } from '../config/generalConfig.mjs'; import { getDiceSoNicePresets } from '../config/generalConfig.mjs';
import { ResourceUpdateMap } from '../data/action/baseAction.mjs'; import { updateResourcesForDualityReroll } from './helpers.mjs';
export default class DualityRoll extends D20Roll { export default class DualityRoll extends D20Roll {
_advantageNumber = 1; _advantageNumber = 1;
@ -385,24 +385,6 @@ export default class DualityRoll extends D20Roll {
} }
} }
static updateResources(oldDuality, newDuality, actor) {
const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return;
const updates = [];
const hope = (newDuality >= 0 ? 1 : 0) - (oldDuality >= 0 ? 1 : 0);
const stress = (newDuality === 0 ? 1 : 0) - (oldDuality === 0 ? 1 : 0);
const fear = (newDuality === -1 ? 1 : 0) - (oldDuality === -1 ? 1 : 0);
if (hope !== 0) updates.push({ key: 'hope', value: hope, total: -1 * hope, enabled: true });
if (stress !== 0) updates.push({ key: 'stress', value: -1 * stress, total: stress, enabled: true });
if (fear !== 0) updates.push({ key: 'fear', value: fear, total: -1 * fear, enabled: true });
const resourceUpdates = new ResourceUpdateMap(actor);
resourceUpdates.addResources(updates);
resourceUpdates.updateResources();
}
async reroll(options) { async reroll(options) {
const oldDuality = this.withHope ? 1 : this.withFear ? -1 : 0; const oldDuality = this.withHope ? 1 : this.withFear ? -1 : 0;
const rerolled = DualityRoll.fromData((await super.reroll(options)).toJSON()); const rerolled = DualityRoll.fromData((await super.reroll(options)).toJSON());
@ -429,7 +411,7 @@ export default class DualityRoll extends D20Roll {
const newDuality = rerolled.withHope ? 1 : rerolled.withFear ? -1 : 0; const newDuality = rerolled.withHope ? 1 : rerolled.withFear ? -1 : 0;
const actor = await foundry.utils.fromUuid(this.options.source.actor); const actor = await foundry.utils.fromUuid(this.options.source.actor);
DualityRoll.updateResources(oldDuality, newDuality, actor); updateResourcesForDualityReroll(oldDuality, newDuality, actor);
} }
return rerolled; return rerolled;

17
module/dice/helpers.mjs Normal file
View file

@ -0,0 +1,17 @@
export function updateResourcesForDualityReroll(oldDuality, newDuality, actor) {
const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return;
const updates = [];
const hope = (newDuality >= 0 ? 1 : 0) - (oldDuality >= 0 ? 1 : 0);
const stress = (newDuality === 0 ? 1 : 0) - (oldDuality === 0 ? 1 : 0);
const fear = (newDuality === -1 ? 1 : 0) - (oldDuality === -1 ? 1 : 0);
if (hope !== 0) updates.push({ key: 'hope', value: hope, total: -1 * hope, enabled: true });
if (stress !== 0) updates.push({ key: 'stress', value: -1 * stress, total: stress, enabled: true });
if (fear !== 0) updates.push({ key: 'fear', value: fear, total: -1 * fear, enabled: true });
const resourceUpdates = new ResourceUpdateMap(actor);
resourceUpdates.addResources(updates);
resourceUpdates.updateResources();
}

View file

@ -864,3 +864,18 @@ export function camelize(str) {
}) })
.replace(/\s+/g, ''); .replace(/\s+/g, '');
} }
/**
* Triggers DiceSoNice rolls or dice roll audio for rolls. Not used for duality rolls.
* @param { Roll[] } rolls
* @return { void }
*/
export async function triggerChatRollFx(rolls, options = { whisper: false, blind: false }) {
const { whisper, blind } = options;
if (game.modules.get('dice-so-nice')?.active) {
const rerollPromises = rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true, whisper, blind));
await Promise.allSettled(rerollPromises);
} else {
foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
}
}