From f4e504296ee12125b4eccd276310f274de72adec Mon Sep 17 00:00:00 2001 From: Chris F Date: Wed, 15 Mar 2023 17:01:30 -0700 Subject: [PATCH 1/3] add basic rsr5e compatibility --- scripts/main.js | 224 +++++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 99 deletions(-) diff --git a/scripts/main.js b/scripts/main.js index b1abeb3..ec5da98 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -16,11 +16,14 @@ Hooks.once('init', () => { game.modules.get(moduleID).api = Multiattack5e; ma5e = game.modules.get(moduleID).api; + // Determine active roller modules + if (game.modules.get("ready-set-roll-5e")?.active) roller = "rsr"; + // Register module settings. game.settings.register(moduleID, 'condenseChatMessagesEnabled', { name: ma5eLocalize('settings.condenseChatMessagesEnabled.name'), scope: 'world', - config: roller === 'core', + config: true, //roller === 'core', type: Boolean, default: true }); @@ -47,7 +50,7 @@ Hooks.once('init', () => { name: ma5eLocalize('settings.extraAttackDSN.name'), hint: ma5eLocalize('settings.extraAttackDSN.hint'), scope: 'world', - config: game.modules.get('dice-so-nice')?.active && roller === 'core', + config: game.modules.get('dice-so-nice')?.active, // && roller === 'core', type: String, choices: { disabled: ma5eLocalize('settings.disabled'), @@ -61,7 +64,7 @@ Hooks.once('init', () => { game.settings.register(moduleID, 'multiattackDSN', { name: ma5eLocalize('settings.multiattackDSN.name'), scope: 'world', - config: game.modules.get('dice-so-nice')?.active && roller === 'core', + config: game.modules.get('dice-so-nice')?.active, // && roller === 'core', type: String, choices: { disabled: ma5eLocalize('settings.disabled'), @@ -72,6 +75,15 @@ Hooks.once('init', () => { default: 'enabled' }); + game.settings.register(moduleID, 'readySetRollDSN', { + name: ma5eLocalize('settings.readySetRollDSN.name'), + hint: ma5eLocalize('settings.readySetRollDSN.hint'), + scope: 'world', + config: game.modules.get('dice-so-nice')?.active && game.modules.get('ready-set-roll-5e')?.active, + type: Boolean, + default: true + }); + }); @@ -131,7 +143,7 @@ Hooks.on('renderDialog', async (dialog, $html, appData) => { }); } - // Prepare to intercept prime roll to create itemIDarray and pass to Multiattack5e.multiattack. + // Prepare to intercept prime roll to pass itemIDarray to Multiattack5e.multiattack. Hooks.once(`dnd5e.${hook}`, async (item, primeRoll, ammoUpdate) => { const itemIDarray = []; for (let i = 1; i < numberOfRolls; i++) itemIDarray.push(item.id); @@ -166,6 +178,7 @@ Hooks.on('renderDialog', async (dialog, $html, appData) => { class Multiattack5e { + static async multiattack({ actor, itemNameArray = [], itemIDarray = [], chatMessage = true, messageData, primeRoll, @@ -179,115 +192,126 @@ class Multiattack5e { const itemArray = isIDs ? itemIDarray : itemNameArray; if (!itemArray.length) return; - // Assume messageData if none provided. - if (!messageData) { - messageData = { - speaker: ChatMessage.getSpeaker({ actor }), - type: CONST.CHAT_MESSAGE_TYPES.ROLL, + if (roller === 'core') { + // Assume messageData if none provided. + if (!messageData) { + messageData = { + speaker: ChatMessage.getSpeaker({ actor }), + type: CONST.CHAT_MESSAGE_TYPES.ROLL, + }; + } + + // Build array of rolls. + const rollMethod = isAttackRoll ? CONFIG.Item.documentClass.prototype.rollAttack : CONFIG.Item.documentClass.prototype.rollDamage; + const condenseChatMessages = game.settings.get(moduleID, 'condenseChatMessagesEnabled'); + let rollOptions; + const commonRollOptions = { + fastForward: true, + chatMessage: !condenseChatMessages // Prevent extra roll chat messages if condenseChatMessages enabled. }; - } + if (isAttackRoll) { + rollOptions = commonRollOptions; + rollOptions.advantage = vantage === 'advantage'; + rollOptions.disadvantage = vantage === 'disadvantage'; + } else { + rollOptions = { + critical: isCritical, + options: commonRollOptions + }; + } + const preHook = isAttackRoll ? 'preRollAttack' : 'preRollDamage'; + const hk = Hooks.on(`dnd5e.${preHook}`, (item, rollConfig) => { + if (sitBonus) rollConfig.parts.push(sitBonus); + }); + let rollOrder = 1; + const rolls = []; + if (primeRoll) rolls.push(primeRoll); + for (const id of itemArray) { + const item = isIDs ? actor.items.get(id) : actor.items.getName(id); + const r = await rollMethod.call(item, rollOptions); + if (r) { + r.id = id; + if (rollMode === 'publicroll' && isExtraAttack) { + r.dice[0].options.rollOrder = rollOrder; + rollOrder++; + } + rolls.push(r); + } - // Build array of rolls. - const rollMethod = isAttackRoll ? CONFIG.Item.documentClass.prototype.rollAttack : CONFIG.Item.documentClass.prototype.rollDamage; - const condenseChatMessages = game.settings.get(moduleID, 'condenseChatMessagesEnabled'); - let rollOptions; - const commonRollOptions = { - fastForward: true, - chatMessage: !condenseChatMessages // Prevent extra roll chat messages if condenseChatMessages enabled. - }; - if (isAttackRoll) { - rollOptions = commonRollOptions; - rollOptions.advantage = vantage === 'advantage'; - rollOptions.disadvantage = vantage === 'disadvantage'; - } else { - rollOptions = { - critical: isCritical, - options: commonRollOptions + await delay(100); // Short delay to allow roll to complete ammoUpdate. + } + Hooks.off(`dnd5e.${preHook}`, hk); + + // Build templateData for rendering custom condensed chat message template. + const templateData = { + items: {} }; - } - const preHook = isAttackRoll ? 'preRollAttack' : 'preRollDamage'; - const hk = Hooks.on(`dnd5e.${preHook}`, (item, rollConfig) => { - if (sitBonus) rollConfig.parts.push(sitBonus); - }); - let rollOrder = 1; - const rolls = []; - if (primeRoll) rolls.push(primeRoll); - for (const id of itemArray) { - const item = isIDs ? actor.items.get(id) : actor.items.getName(id); - await delay(100); // Short delay to allow previous roll to complete ammoUpdate. - const r = await rollMethod.call(item, rollOptions); - if (r) { - r.id = id; - if (rollMode === 'publicroll' && isExtraAttack) { - r.dice[0].options.rollOrder = rollOrder; - rollOrder++; + for (const roll of rolls) { + roll.tooltip = await roll.getTooltip(); + if (isAttackRoll) { + if (roll.isCritical) roll.highlight = 'critical'; + else if (roll.isFumble) roll.highlight = 'fumble'; + else roll.highlight = ''; } - rolls.push(r); + const { id } = roll; + if (!templateData.items[id]) { + templateData.items[id] = { + flavor: roll.options.flavor, + formula: roll.formula, + rolls: [roll] + }; + if (roll.hasAdvantage) templateData.items[id].flavor += ` (${game.i18n.localize("DND5E.Advantage")})`; + if (roll.hasDisadvantage) templateData.items[id].flavor += ` (${game.i18n.localize("DND5E.Disadvantage")})`; + } else templateData.items[id].rolls.push(roll); } - } - Hooks.off(`dnd5e.${preHook}`, hk); + // Subsequent processing only applies to condensed chat messages. + if (!condenseChatMessages) return rolls; - // Build templateData for rendering custom condensed chat message template. - const templateData = { - items: {} - }; - for (const roll of rolls) { - roll.tooltip = await roll.getTooltip(); - if (isAttackRoll) { - if (roll.isCritical) roll.highlight = 'critical'; - else if (roll.isFumble) roll.highlight = 'fumble'; - else roll.highlight = ''; - } - const { id } = roll; - if (!templateData.items[id]) { - templateData.items[id] = { - flavor: roll.options.flavor, - formula: roll.formula, - rolls: [roll] - }; - if (roll.hasAdvantage) templateData.items[id].flavor += ` (${game.i18n.localize("DND5E.Advantage")})`; - if (roll.hasDisadvantage) templateData.items[id].flavor += ` (${game.i18n.localize("DND5E.Disadvantage")})`; - } else templateData.items[id].rolls.push(roll); - } + // Attach rolls array to messageData for DsN integration and total damage application. + messageData.rolls = rolls; - // Subsequent processing only applies to condensed chat messages. - if (!condenseChatMessages) return rolls; + // Calculate total damage if damage roll. + if (!isAttackRoll) templateData.totalDamage = rolls.reduce((acc, current) => { return acc += current.total }, 0); - // Attach rolls array to messageData for DsN integration and total damage application. - messageData.rolls = rolls; + // Render template. + const content = await renderTemplate(`modules/${moduleID}/templates/condensed-chat-message.hbs`, templateData); + messageData.content = content; - // Calculate total damage if damage roll. - if (!isAttackRoll) templateData.totalDamage = rolls.reduce((acc, current) => { return acc += current.total }, 0); + // Compatibility with Semi-Private Rolls. + messageData.flags = { + 'semi-private-rolls': { + flavor: messageData.flavor + } + }; + // Flavor is already included in custom template. + delete messageData.flavor; + + // Conditionally hide DsN based on extraAttackDSN setting. + const dsn = isExtraAttack + ? game.settings.get(moduleID, 'extraAttackDSN') + : game.settings.get(moduleID, 'multiattackDSN'); + if (dsn !== 'enabled' && (extraAttackDSN === 'disabled' || dsn !== rollType)) { + Hooks.once('diceSoNiceRollStart', (id, context) => { context.blind = true }); + } - // Render template. - const content = await renderTemplate(`modules/${moduleID}/templates/condensed-chat-message.hbs`, templateData); - messageData.content = content; + // Create condensed chat message. + if (chatMessage) await ChatMessage.create(messageData, { rollMode }); - messageData.flags = { - [moduleID]: { - isMultiattack: true, - }, - 'semi-private-rolls': { // Compatibility with Semi-Private Rolls. + return rolls; + + } else if (roller === "rsr") { + // Hide DSN based on module setting + let hk; + if (!game.settings.get(moduleID, "readySetRollDSN")) hk = Hooks.on("diceSoNiceRollStart", (messageID, context) => { context.blind = true }); - flavor: messageData.flavor + // Use rsr5e to perform rolls + for (const id of itemArray) { + const item = isIDs ? actor.items.get(id) : actor.items.getName(id); + rsr5e.macro.rollItem(item._id, actor._id); } - }; - // Flavor is already included in custom template. - delete messageData.flavor; - - // Conditionally hide DsN based on extraAttackDSN setting. - const dsn = isExtraAttack - ? game.settings.get(moduleID, 'extraAttackDSN') - : game.settings.get(moduleID, 'multiattackDSN'); - if (dsn !== 'enabled' && (extraAttackDSN === 'disabled' || dsn !== rollType)) { - Hooks.once('diceSoNiceRollStart', (id, context) => { context.blind = true }); + if (hk) Hooks.off("diceSoNiceRollStart", hk); } - - // Create condensed chat message. - if (chatMessage) await ChatMessage.create(messageData, { rollMode }); - - return rolls; } static async multiattackTool() { @@ -376,8 +400,10 @@ class Multiattack5e { close: async ([html]) => { if (!rollType) return; - // Build itemIDarray and send to Multiattack5e.multiattack. + // Build itemIDarray. const itemIDarray = toolDataToItemIDarray(html); + + // Send itemIDarray to Multiattack5e.multiattack. await ma5e.multiattack({ actor, itemIDarray, From 2d458da74e663f6db2191478ef7d9db6cc37458e Mon Sep 17 00:00:00 2001 From: Chris F Date: Wed, 15 Mar 2023 17:10:23 -0700 Subject: [PATCH 2/3] revert test code --- scripts/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/main.js b/scripts/main.js index ec5da98..673cd20 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -23,7 +23,7 @@ Hooks.once('init', () => { game.settings.register(moduleID, 'condenseChatMessagesEnabled', { name: ma5eLocalize('settings.condenseChatMessagesEnabled.name'), scope: 'world', - config: true, //roller === 'core', + config: roller === 'core', type: Boolean, default: true }); @@ -50,7 +50,7 @@ Hooks.once('init', () => { name: ma5eLocalize('settings.extraAttackDSN.name'), hint: ma5eLocalize('settings.extraAttackDSN.hint'), scope: 'world', - config: game.modules.get('dice-so-nice')?.active, // && roller === 'core', + config: game.modules.get('dice-so-nice')?.active && roller === 'core', type: String, choices: { disabled: ma5eLocalize('settings.disabled'), @@ -64,7 +64,7 @@ Hooks.once('init', () => { game.settings.register(moduleID, 'multiattackDSN', { name: ma5eLocalize('settings.multiattackDSN.name'), scope: 'world', - config: game.modules.get('dice-so-nice')?.active, // && roller === 'core', + config: game.modules.get('dice-so-nice')?.active && roller === 'core', type: String, choices: { disabled: ma5eLocalize('settings.disabled'), From 3b35b2cf6a27aa3f5d37c8fcd304e98b5f32f9b1 Mon Sep 17 00:00:00 2001 From: Chris F Date: Wed, 15 Mar 2023 17:17:58 -0700 Subject: [PATCH 3/3] revert test code --- scripts/main.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/main.js b/scripts/main.js index 673cd20..78263c6 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -143,7 +143,7 @@ Hooks.on('renderDialog', async (dialog, $html, appData) => { }); } - // Prepare to intercept prime roll to pass itemIDarray to Multiattack5e.multiattack. + // Prepare to intercept prime roll to create itemIDarray and pass to Multiattack5e.multiattack. Hooks.once(`dnd5e.${hook}`, async (item, primeRoll, ammoUpdate) => { const itemIDarray = []; for (let i = 1; i < numberOfRolls; i++) itemIDarray.push(item.id); @@ -178,7 +178,6 @@ Hooks.on('renderDialog', async (dialog, $html, appData) => { class Multiattack5e { - static async multiattack({ actor, itemNameArray = [], itemIDarray = [], chatMessage = true, messageData, primeRoll, @@ -400,10 +399,8 @@ class Multiattack5e { close: async ([html]) => { if (!rollType) return; - // Build itemIDarray. + // Build itemIDarray and send to Multiattack5e.multiattack. const itemIDarray = toolDataToItemIDarray(html); - - // Send itemIDarray to Multiattack5e.multiattack. await ma5e.multiattack({ actor, itemIDarray,