new roll request via chat card is working

This commit is contained in:
Mike Bloy 2026-02-15 16:21:34 -06:00
parent e3ad4cf852
commit f0ca43b989
4 changed files with 135 additions and 1 deletions

View File

@ -1,4 +1,6 @@
import { moduleHelpers } from './globals.js';
import { templates } from './preloadTemplates.js';
import { log } from './globals.js';
export async function requestFearRollFromTokens(tokens, options = {}) {
// tokens: list of tokens to request the roll from
@ -48,7 +50,113 @@ export function firstGM() {
return game.users?.find((u) => u.isGM && u.active);
}
export function helpersRenderChatMessage(message, html, data) {
const messageId = message._id;
const requestContentDiv = html.querySelector('.mb-requestroll');
if (!requestContentDiv) {
return;
}
const rollType = requestContentDiv.dataset?.rollType;
const rollDesc = requestContentDiv.dataset?.rollDesc;
const targetNumber = requestContentDiv.dataset?.rollTargetNumber;
const flavour = requestContentDiv.dataset?.rollFlavour;
const title = requestContentDiv.dataset?.rollTitle;
const mods = JSON.parse(requestContentDiv.dataset?.rollMods ?? '[]');
const rows = requestContentDiv.querySelectorAll('.mb-rollrequest-results tr');
for (const row of rows) {
const resolved = row.dataset?.resolved === 'true';
const value = row.dataset?.value ?? 'None';
const tokenUuid = row.dataset?.tokenUuid;
const rowMods = JSON.parse(row.dataset?.tokenAdditonalMods ?? '[]');
const token = foundry.utils.fromUuidSync(tokenUuid);
const actor = token?.actor;
const iconSpan = row.querySelector('.mb-roll-result-icon');
const valueSpan = row.querySelector('.mb-roll-result');
const buttonSpan = row.querySelector('.mb-roll-button');
if (resolved) {
buttonSpan.remove();
} else {
iconSpan.remove();
valueSpan.remove();
buttonSpan.addEventListener('click', async () => {
const options = {
title: `${title} - ${token.name}`,
isMbRequestedRoll: true,
mbRequestMessageId: messageId,
targetNumber,
flavour,
additionalMods: [...mods, ...rowMods],
};
let rollFunc = 'rollAttribute';
let rollId = rollDesc.toLowerCase();
if (rollType === 'skill') {
rollFunc = 'rollSkill';
rollId = actor.items
.filter((i) => i.type === 'skill')
.find(
(i) => i.system.swid === rollDesc.toLowerCase() || i.name.toLowerCase() === rollDesc.toLowerCase(),
)?.id;
}
const result = await actor[rollFunc](rollId, options);
});
}
}
}
export function helpersRenderChatLog(app, html, data) {
// log('RENDER CHAT LOG', app, html, data);
}
export async function requestRollFromTokens(tokens, rollType, rollDesc, options = {}) {
// tokens: list of tokens to request a roll from
// rollType: 'attribute' or 'skill
// rollDesc: name of attribute or skill
// options:
// title: title for the roll dialog. Will have "- {{ token name }}"
// appended
// flavour: flavor text for the roll card. Defaults to title
// targetNumber: defaults to 4
// mods: list of modifiers {label: "", value: 0, ignore: false}
// modCallback: callback function that takes a token and returns a list of
// modifiers in the same format as modifiers, above
const requestingUser = game.user;
const title = options?.title || `${requestingUser.name} requests a ${rollDesc} roll`;
const flavour = options?.flavour || options?.flavor || title;
const targetNumber = options?.targetNumber || 4;
const tokenData = [];
for (const token of tokens) {
const additionalMods = [];
if ('modCallback' in options) {
const tokenMods = await options.modCallback(token);
for (const tm of tokenMods) {
additionalMods.push(tm);
}
}
tokenData.push({
name: token.name,
id: token.id,
uuid: token.document.uuid,
additionalMods: JSON.stringify(additionalMods),
});
}
const rollData = {
type: rollType,
desc: rollDesc,
title,
flavour,
targetNumber,
mods: JSON.stringify(options.mods ? options.mods : []),
};
const template = templates['rollRequest/chatcard.html'];
const chatData = {
user: game.user._id,
flavor: flavour,
content: await foundry.applications.handlebars.renderTemplate(template, { roll: rollData, tokens: tokenData }),
};
return ChatMessage.create(chatData);
}
export async function oldRequestRollFromTokens(tokens, rollType, rollDesc, options = {}) {
// tokens: list of tokens to request a roll from
// rollType: 'attribute' or 'skill
// rollDesc: name of attribute or skill

View File

@ -1,4 +1,4 @@
const _templatePaths = ['dialogHeader.html', 'powerDialog.html', 'summonCosts.html'];
const _templatePaths = ['dialogHeader.html', 'powerDialog.html', 'summonCosts.html', 'rollRequest/chatcard.html'];
export async function preloadTemplates() {
return loadTemplates(_templatePaths.map((f) => `modules/swade-mb-helpers/templates/${f}`));

View File

@ -13,6 +13,8 @@ import {
requestTokenRoll,
SwadeVAEbuttons,
updateOwnedToken,
helpersRenderChatMessage,
helpersRenderChatLog,
} from './helpers.js';
import { preAttackRollModifiers, preDamageRollModifiers, preTraitRollModifiers } from './rollHelpers.js';
import { log, moduleHelpers } from './globals.js';
@ -51,6 +53,8 @@ function _checkModule(name) {
}
Hooks.on('preCreateItem', embeddedHelperHook);
Hooks.on('renderChatMessageHTML', helpersRenderChatMessage);
Hooks.on('renderChatLogHTML', helpersRenderChatLog);
Hooks.on('swadePreRollAttribute', preTraitRollModifiers);
Hooks.on('swadePreRollSkill', preTraitRollModifiers);
Hooks.on('swadeCalculateDefaultAttackMods', preAttackRollModifiers);

View File

@ -0,0 +1,22 @@
<div class="mb-chat-card mb-interactive mb-requestroll" data-roll-type="{{roll.type}}" data-roll-desc="{{roll.desc}}"
data-roll-target-number="{{roll.targetNumber}}" data-roll-flavour="{{roll.flavour}}" data-roll-title="{{roll.title}}"
data-roll-mods="{{roll.mods}}">
<div class="mb-card-content">
<p>Click the button to make your roll.</p>
</div>
<div class="mb-card-buttons-results">
<table class="mb-rollrequest-results">
{{#each tokens}}
<tr data-resolved="false" data-value="" data-is-success="" data-token-id="{{id}}" data-token-uuid="{{uuid}}"
data-token-additional-mods="{{additionalMods}}">
<td>{{name}}</td>
<td>
<button class="mb-roll-button">Roll</button>
<span class="mb-roll-result-icon">?</span>
<span class="mb-roll-result">NA</span>
</td>
<td </tr>
{{/each}}
</table>
</div>
</div>