roll requests need multiplayer support

This commit is contained in:
Mike Bloy 2026-02-16 00:09:24 -06:00
parent f0ca43b989
commit fcab44f59d
2 changed files with 113 additions and 60 deletions

View File

@ -51,54 +51,82 @@ export function firstGM() {
} }
export function helpersRenderChatMessage(message, html, data) { export function helpersRenderChatMessage(message, html, data) {
const messageId = message._id;
const requestContentDiv = html.querySelector('.mb-requestroll'); const requestContentDiv = html.querySelector('.mb-requestroll');
if (!requestContentDiv) { if (!requestContentDiv) {
return; return;
} }
const rollType = requestContentDiv.dataset?.rollType; const allData = message.getFlag('swade-mb-helpers', 'rollRequest');
const rollDesc = requestContentDiv.dataset?.rollDesc; const rollType = allData.roll.type;
const targetNumber = requestContentDiv.dataset?.rollTargetNumber; const rollDesc = allData.roll.desc;
const flavour = requestContentDiv.dataset?.rollFlavour; const targetNumber = allData.roll.targetNumber;
const title = requestContentDiv.dataset?.rollTitle; const flavour = allData.roll.flavour;
const mods = JSON.parse(requestContentDiv.dataset?.rollMods ?? '[]'); const title = allData.roll.title;
const rows = requestContentDiv.querySelectorAll('.mb-rollrequest-results tr'); const mods = allData.roll.mods;
const rows = requestContentDiv.querySelectorAll('.mb-rollrequest-results tbody tr');
for (const row of rows) { for (const row of rows) {
const resolved = row.dataset?.resolved === 'true';
const value = row.dataset?.value ?? 'None';
const tokenUuid = row.dataset?.tokenUuid; const tokenUuid = row.dataset?.tokenUuid;
const rowMods = JSON.parse(row.dataset?.tokenAdditonalMods ?? '[]');
const token = foundry.utils.fromUuidSync(tokenUuid); const token = foundry.utils.fromUuidSync(tokenUuid);
const tokenId = token.id;
const actor = token?.actor; const actor = token?.actor;
const iconSpan = row.querySelector('.mb-roll-result-icon'); const tokenData = allData.tokens[tokenId];
const valueSpan = row.querySelector('.mb-roll-result'); const resolved = tokenData?.resolved ?? false;
const rowMods = tokenData?.additionalMods ?? [];
const buttonSpan = row.querySelector('.mb-roll-button'); const buttonSpan = row.querySelector('.mb-roll-button');
if (resolved) { const waitingSpan = row.querySelector('.mb-roll-waiting');
buttonSpan.remove(); if (!resolved) {
} else { if (token.isOwner) {
iconSpan.remove(); waitingSpan.remove();
valueSpan.remove(); buttonSpan.addEventListener('click', async () => {
buttonSpan.addEventListener('click', async () => { const options = {
const options = { title: `${title} - ${token.name}`,
title: `${title} - ${token.name}`, targetNumber,
isMbRequestedRoll: true, flavour,
mbRequestMessageId: messageId, additionalMods: [...mods, ...rowMods],
targetNumber, };
flavour, let rollFunc = 'rollAttribute';
additionalMods: [...mods, ...rowMods], let rollId = rollDesc.toLowerCase();
}; if (rollType === 'skill') {
let rollFunc = 'rollAttribute'; rollFunc = 'rollSkill';
let rollId = rollDesc.toLowerCase(); rollId = actor.items
if (rollType === 'skill') { .filter((i) => i.type === 'skill')
rollFunc = 'rollSkill'; .find(
rollId = actor.items (i) => i.system.swid === rollDesc.toLowerCase() || i.name.toLowerCase() === rollDesc.toLowerCase(),
.filter((i) => i.type === 'skill') )?.id;
.find( }
(i) => i.system.swid === rollDesc.toLowerCase() || i.name.toLowerCase() === rollDesc.toLowerCase(), const result = await actor[rollFunc](rollId, options);
)?.id; tokenData.resolved = true;
} tokenData.total = result.total;
const result = await actor[rollFunc](rollId, options); if (result.successes == -1) {
}); tokenData.icon = '⛝';
tokenData.resolveClass = 'critFail';
tokenData.value = 'Critical Failure!';
} else if (result.successes == 0) {
tokenData.icon = '⛒';
tokenData.value = 'Failure';
tokenData.resolveClass = 'failure';
} else if (result.successes == 1) {
tokenData.icon = '✓';
tokenData.value = 'Success';
tokenData.resolveClass = 'success';
} else if (result.successes == 2) {
tokenData.icon = '✓✓';
tokenData.value = `Success and a raise!`;
tokenData.resolveClass = 'raise';
} else {
tokenData.icon = '✓✓';
tokenData.value = `Success and ${result.successes - 1} raises!`;
tokenData.resolveClass = 'raise';
}
await message.setFlag('swade-mb-helpers', `rollRequest.tokens.${tokenId}`, tokenData);
log('result', result);
const newData = message.getFlag('swade-mb-helpers', 'rollRequest');
const template = templates['rollRequest/chatcard.html'];
const newContent = await foundry.applications.handlebars.renderTemplate(template, newData);
await message.update({ content: newContent });
});
} else {
buttonSpan.remove();
}
} }
} }
} }
@ -123,7 +151,7 @@ export async function requestRollFromTokens(tokens, rollType, rollDesc, options
const title = options?.title || `${requestingUser.name} requests a ${rollDesc} roll`; const title = options?.title || `${requestingUser.name} requests a ${rollDesc} roll`;
const flavour = options?.flavour || options?.flavor || title; const flavour = options?.flavour || options?.flavor || title;
const targetNumber = options?.targetNumber || 4; const targetNumber = options?.targetNumber || 4;
const tokenData = []; const tokenData = {};
for (const token of tokens) { for (const token of tokens) {
const additionalMods = []; const additionalMods = [];
if ('modCallback' in options) { if ('modCallback' in options) {
@ -132,12 +160,17 @@ export async function requestRollFromTokens(tokens, rollType, rollDesc, options
additionalMods.push(tm); additionalMods.push(tm);
} }
} }
tokenData.push({ tokenData[token.id] = {
name: token.name, name: token.name,
id: token.id, id: token.id,
resolved: false,
icon: null,
value: null,
total: null,
resolveClass: 'waiting',
uuid: token.document.uuid, uuid: token.document.uuid,
additionalMods: JSON.stringify(additionalMods), additionalMods: additionalMods,
}); };
} }
const rollData = { const rollData = {
type: rollType, type: rollType,
@ -145,15 +178,24 @@ export async function requestRollFromTokens(tokens, rollType, rollDesc, options
title, title,
flavour, flavour,
targetNumber, targetNumber,
mods: JSON.stringify(options.mods ? options.mods : []), mods: options.mods ? options.mods : [],
}; };
const template = templates['rollRequest/chatcard.html']; const template = templates['rollRequest/chatcard.html'];
const chatData = { const chatData = {
user: game.user._id, user: game.user._id,
flavor: flavour, flavor: flavour,
flags: {
'swade-mb-helpers': {
rollRequest: {
tokens: tokenData,
roll: rollData,
},
},
},
content: await foundry.applications.handlebars.renderTemplate(template, { roll: rollData, tokens: tokenData }), content: await foundry.applications.handlebars.renderTemplate(template, { roll: rollData, tokens: tokenData }),
}; };
return ChatMessage.create(chatData); let message = await ChatMessage.create(chatData);
console.log(message);
} }
export async function oldRequestRollFromTokens(tokens, rollType, rollDesc, options = {}) { export async function oldRequestRollFromTokens(tokens, rollType, rollDesc, options = {}) {

View File

@ -1,22 +1,33 @@
<div class="mb-chat-card mb-interactive mb-requestroll" data-roll-type="{{roll.type}}" data-roll-desc="{{roll.desc}}" <div class="mb-chat-card mb-interactive mb-requestroll">
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"> <div class="mb-card-content">
<p>Click the button to make your roll.</p> <p>{{roll.title}}</p>
</div> </div>
<div class="mb-card-buttons-results"> <div class="mb-card-buttons-results">
<table class="mb-rollrequest-results"> <table class="mb-rollrequest-results">
{{#each tokens}} <thead>
<tr data-resolved="false" data-value="" data-is-success="" data-token-id="{{id}}" data-token-uuid="{{uuid}}" <tr>
data-token-additional-mods="{{additionalMods}}"> <th>Token</th>
<td>{{name}}</td> <th>Result</th>
<td> </tr>
<button class="mb-roll-button">Roll</button> </thead>
<span class="mb-roll-result-icon">?</span> <tbody>
<span class="mb-roll-result">NA</span> {{#each tokens}}
</td> <tr data-token-uuid="{{uuid}}" class="mb-roll-{{resolveClass}}">
<td </tr> <td>{{name}}</td>
{{/each}} <td>
{{#unless resolved}}
<button class="mb-roll-button">Roll</button>
<span class="mb-roll-waiting">Waiting...</span>
{{/unless}}
{{#if resolved}}
<span class="mb-roll-total">{{total}}</span>
<span class="mb-roll-result-icon">{{icon}}</span>
<span class="mb-roll-result">{{value}}</span>
{{/if}}
</td>
</tr>
{{/each}}
</tbody>
</table> </table>
</div> </div>
</div> </div>