import { moduleHelpers } from './globals.js'; export async function requestFearRollFromTokens(tokens, options = {}) { // tokens: list of tokens to request the roll from // options: // title: tile for the roll dialog. Will have "- {{ token name }}" appended // flavour: flavor text for the roll card. Defaults to title // fear: value of the fear modifier. Defaults to 0. Positive number. const requestingUser = game.user; const title = options?.title || `${requestingUser.name} requests a Fear check`; const flavour = options?.flavour || options?.flavor || title; const fear = options.fear || 0; const rollOpts = { title, flavour, mods: [{ label: 'Fear Penalty', value: Math.abs(fear) * -1, ignore: false }], }; return requestRollFromTokens(tokens, 'attribute', 'spirit', rollOpts); } export function firstOwner(doc) { // lifted from warpgate // https://github.com/trioderegion/warpgate/blob/master/src/scripts/module.js if (!doc) return undefined; const corrected = doc instanceof TokenDocument ? doc.actor : doc instanceof Token ? doc.document.actor : doc; const permissionObject = foundry.utils.getProperty(corrected ?? {}, 'ownership'); const playerOwners = Object.entries(permissionObject) .filter(([id, level]) => !game.users.get(id)?.isGM && game.users.get(id)?.active && level === 3) .map(([id]) => id); if (playerOwners.length > 0) { return game.users.get(playerOwners[0]); } return firstGM(); } export function firstGM() { // lifted from warpgate // https://github.com/trioderegion/warpgate/blob/master/src/scripts/module.js return game.users?.find((u) => u.isGM && u.active); } 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 promises = []; for (const token of tokens) { const owner = firstOwner(token.document); const rollOpts = { title: `${title} - ${token.name}`, targetNumber, flavour, }; const additionalMods = []; if ('mods' in options) { for (const mod of options.mods) { additionalMods.push(mod); } } if ('modCallback' in options) { const tokenMods = await options.modCallback(token); for (const tm of tokenMods) { additionalMods.push(tm); } } if (additionalMods.length > 0) { rollOpts.additionalMods = additionalMods; } promises.push( moduleHelpers.socket.executeAsUser( requestTokenRoll, owner.id, token.scene.id, token.id, rollType, rollDesc, rollOpts, ), ); } const results = (await Promise.allSettled(promises)).map((r) => r.value); const contentExtra = targetNumber === 4 ? '' : ` vs TN: ${targetNumber}`; const messageData = { flavor: flavour, speaker: { alias: 'Requested Roll Results' }, whisper: [...ChatMessage.getWhisperRecipients('GM'), requestingUser], content: `
Results of ${rollDesc[0].toUpperCase()}${rollDesc.slice(1)} roll${contentExtra}:
| Token | Roll | Result |
|---|---|---|
| ${token.name} | ` + `${roll ? roll.total : 'Canceled'} | ` + `${textResult} | ` + '