mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 11:41:08 +01:00
Added DualityRoll direct rolls in chat
This commit is contained in:
parent
eeede65443
commit
4501edcf4a
5 changed files with 165 additions and 1087 deletions
114
daggerheart.mjs
114
daggerheart.mjs
|
|
@ -10,7 +10,9 @@ import DhpChatLog from './module/ui/chatLog.mjs';
|
||||||
import DhpPlayers from './module/ui/players.mjs';
|
import DhpPlayers from './module/ui/players.mjs';
|
||||||
import DhpRuler from './module/ui/ruler.mjs';
|
import DhpRuler from './module/ui/ruler.mjs';
|
||||||
import DhpTokenRuler from './module/ui/tokenRuler.mjs';
|
import DhpTokenRuler from './module/ui/tokenRuler.mjs';
|
||||||
import { dualityRollEnricher } from './module/enrichers/DualityRollEnricher.mjs';
|
import { dualityRollEnricher, getDualityMessage } from './module/enrichers/DualityRollEnricher.mjs';
|
||||||
|
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
|
||||||
|
import { abilities } from './module/config/actorConfig.mjs';
|
||||||
|
|
||||||
globalThis.SYSTEM = SYSTEM;
|
globalThis.SYSTEM = SYSTEM;
|
||||||
|
|
||||||
|
|
@ -130,26 +132,108 @@ Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
|
||||||
Hooks.on('renderChatMessageHTML', (message, element) => {
|
Hooks.on('renderChatMessageHTML', (message, element) => {
|
||||||
element.querySelectorAll('.duality-roll-button').forEach(element =>
|
element.querySelectorAll('.duality-roll-button').forEach(element =>
|
||||||
element.addEventListener('click', async event => {
|
element.addEventListener('click', async event => {
|
||||||
|
let target = getCommandTarget();
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
const button = event.currentTarget;
|
const button = event.currentTarget;
|
||||||
let target = game.canvas.tokens.controlled.length > 0 ? game.canvas.tokens.controlled[0].actor : null;
|
const rollModifier = button.dataset.attribute
|
||||||
if (!game.user.isGM) {
|
? target.system.attributes[button.dataset.attribute].data.value
|
||||||
target = game.user.character;
|
: null;
|
||||||
if (!target) {
|
const { roll, hope, fear, advantage, disadvantage, modifiers } = await target.diceRoll({
|
||||||
notifications.error('DAGGERHEART.Notification.Error.NoAssignedPlayerCharacter');
|
title: button.dataset.label,
|
||||||
return;
|
value: rollModifier
|
||||||
}
|
});
|
||||||
}
|
const cls = getDocumentClass('ChatMessage');
|
||||||
|
const msgData = {
|
||||||
|
type: 'dualityRoll',
|
||||||
|
sound: CONFIG.sounds.dice,
|
||||||
|
system: {
|
||||||
|
title: button.dataset.label,
|
||||||
|
origin: target.id,
|
||||||
|
roll: roll._formula,
|
||||||
|
modifiers: modifiers,
|
||||||
|
hope: hope,
|
||||||
|
fear: fear,
|
||||||
|
advantage: advantage,
|
||||||
|
disadvantage: disadvantage
|
||||||
|
},
|
||||||
|
user: game.user.id,
|
||||||
|
content: 'systems/daggerheart/templates/chat/duality-roll.hbs',
|
||||||
|
rolls: [roll]
|
||||||
|
};
|
||||||
|
|
||||||
if (!target) {
|
await cls.create(msgData);
|
||||||
notifications.error('DAGGERHEART.Notification.Error.NoSelectedToken');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = await gmTarget.diceRoll(3);
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('chatMessage', (_, message) => {
|
||||||
|
if (message.startsWith('/dr')) {
|
||||||
|
const rollCommand = rollCommandToJSON(message.replace(/\/dr\s?/, ''));
|
||||||
|
if (!rollCommand) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.DualityParsing'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributeValue = rollCommand.attribute?.toLowerCase();
|
||||||
|
|
||||||
|
// Target not required if an attribute is not used.
|
||||||
|
const target = attributeValue ? getCommandTarget() : undefined;
|
||||||
|
if (target || !attributeValue) {
|
||||||
|
new Promise(async (resolve, reject) => {
|
||||||
|
const attribute = target ? target.system.attributes[attributeValue] : undefined;
|
||||||
|
if (attributeValue && !attribute) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.AttributeFaulty'));
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = attributeValue
|
||||||
|
? game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', {
|
||||||
|
ability: game.i18n.localize(abilities[attributeValue].label)
|
||||||
|
})
|
||||||
|
: game.i18n.localize('DAGGERHEART.General.Duality');
|
||||||
|
|
||||||
|
const hopeAndFearRoll = `1${rollCommand.hope ?? 'd12'}+1${rollCommand.fear ?? 'd12'}`;
|
||||||
|
const advantageRoll = `${rollCommand.advantage && !rollCommand.disadvantage ? '+d6' : rollCommand.disadvantage && !rollCommand.advantage ? '-d6' : ''}`;
|
||||||
|
const attributeRoll = `${attribute?.data?.value ? `${attribute.data.value > 0 ? `+${attribute.data.value}` : `${attribute.data.value}`}` : ''}`;
|
||||||
|
const roll = new Roll(`${hopeAndFearRoll}${advantageRoll}${attributeRoll}`);
|
||||||
|
await roll.evaluate();
|
||||||
|
resolve({ roll, attribute, title });
|
||||||
|
}).then(({ roll, attribute, title }) => {
|
||||||
|
const cls = getDocumentClass('ChatMessage');
|
||||||
|
const msgData = {
|
||||||
|
type: 'dualityRoll',
|
||||||
|
sound: CONFIG.sounds.dice,
|
||||||
|
system: {
|
||||||
|
title: title,
|
||||||
|
origin: target?.id,
|
||||||
|
roll: roll._formula,
|
||||||
|
modifiers: attribute ? [{ value: attribute.data.value }] : [],
|
||||||
|
hope: { dice: rollCommand.hope ?? 'd12', value: roll.dice[0].total },
|
||||||
|
fear: { dice: rollCommand.fear ?? 'd12', value: roll.dice[1].total },
|
||||||
|
advantage:
|
||||||
|
rollCommand.advantage && !rollCommand.disadvantage
|
||||||
|
? { dice: 'd6', value: roll.dice[2].total }
|
||||||
|
: undefined,
|
||||||
|
disadvantage:
|
||||||
|
rollCommand.disadvantage && !rollCommand.advantage
|
||||||
|
? { dice: 'd6', value: roll.dice[2].total }
|
||||||
|
: undefined
|
||||||
|
},
|
||||||
|
user: game.user.id,
|
||||||
|
content: 'systems/daggerheart/templates/chat/duality-roll.hbs',
|
||||||
|
rolls: [roll]
|
||||||
|
};
|
||||||
|
|
||||||
|
cls.create(msgData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const preloadHandlebarsTemplates = async function () {
|
const preloadHandlebarsTemplates = async function () {
|
||||||
return foundry.applications.handlebars.loadTemplates([
|
return foundry.applications.handlebars.loadTemplates([
|
||||||
'systems/daggerheart/templates/sheets/parts/attributes.hbs',
|
'systems/daggerheart/templates/sheets/parts/attributes.hbs',
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,10 @@
|
||||||
"DuplicateDomainCard": "You already have a domain card with that name!",
|
"DuplicateDomainCard": "You already have a domain card with that name!",
|
||||||
"ActionRequiresTarget": "The action requires at least one target",
|
"ActionRequiresTarget": "The action requires at least one target",
|
||||||
"NoAssignedPlayerCharacter": "You have no assigned character.",
|
"NoAssignedPlayerCharacter": "You have no assigned character.",
|
||||||
"NoSelectedToken": "You have no selected token"
|
"NoSelectedToken": "You have no selected token",
|
||||||
|
"OnlyUseableByPC": "This can only be used with a PC token",
|
||||||
|
"DualityParsing": "Duality roll not properly formated",
|
||||||
|
"AttributeFaulty": "The supplied Attribute doesn't exist"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"General": {
|
"General": {
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,38 +1,36 @@
|
||||||
import { abilities } from '../config/actorConfig.mjs';
|
import { abilities } from '../config/actorConfig.mjs';
|
||||||
|
import { rollCommandToJSON } from '../helpers/utils.mjs';
|
||||||
|
|
||||||
export async function dualityRollEnricher(match, _options) {
|
export function dualityRollEnricher(match, _options) {
|
||||||
try {
|
const roll = rollCommandToJSON(match[1]);
|
||||||
const {
|
if (!roll) return match[0];
|
||||||
hope = 'd12',
|
|
||||||
fear = 'd12',
|
|
||||||
attribute,
|
|
||||||
advantage,
|
|
||||||
disadvantage
|
|
||||||
} = JSON.parse(`{${match[1].replace(' ', ',').replace(/(\w+(?==))(=)/g, '"$1":')}}`);
|
|
||||||
const dualityElement = document.createElement('span');
|
|
||||||
|
|
||||||
const attributeLabel =
|
return getDualityMessage(roll);
|
||||||
attribute && abilities[attribute]
|
}
|
||||||
? game.i18n.format('DAGGERHEART.General.Check', {
|
|
||||||
check: game.i18n.localize(abilities[attribute].label)
|
export function getDualityMessage(roll) {
|
||||||
})
|
const attributeLabel =
|
||||||
: null;
|
roll.attribute && abilities[roll.attribute]
|
||||||
const label = attributeLabel ?? game.i18n.localize('DAGGERHEART.General.Duality');
|
? game.i18n.format('DAGGERHEART.General.Check', {
|
||||||
dualityElement.innerHTML = `
|
check: game.i18n.localize(abilities[roll.attribute].label)
|
||||||
<button class="duality-roll-button"
|
})
|
||||||
data-hope="${hope}"
|
: null;
|
||||||
data-fear="${fear}"
|
const label = attributeLabel ?? game.i18n.localize('DAGGERHEART.General.Duality');
|
||||||
${attribute ? `data-attribute="${attribute}"` : ''}
|
|
||||||
${advantage ? 'data-advantage="true"' : ''}
|
const dualityElement = document.createElement('span');
|
||||||
${disadvantage ? 'data-disadvantage="true"' : ''}
|
dualityElement.innerHTML = `
|
||||||
>
|
<button class="duality-roll-button"
|
||||||
<i class="fa-solid fa-circle-half-stroke"></i>
|
data-label="${label}"
|
||||||
${label}
|
data-hope="${roll.hope ?? 'd12'}"
|
||||||
</button>
|
data-fear="${roll.fear ?? 'd12'}"
|
||||||
`;
|
${roll.attribute && abilities[roll.attribute] ? `data-attribute="${roll.attribute}"` : ''}
|
||||||
|
${roll.advantage ? 'data-advantage="true"' : ''}
|
||||||
return dualityElement;
|
${roll.disadvantage ? 'data-disadvantage="true"' : ''}
|
||||||
} catch (_) {
|
>
|
||||||
return match[0];
|
<i class="fa-solid fa-circle-half-stroke"></i>
|
||||||
}
|
${label}
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return dualityElement;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,6 @@ const getCompendiumOptions = async compendium => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getWidthOfText = (txt, fontsize, allCaps, bold) => {
|
export const getWidthOfText = (txt, fontsize, allCaps, bold) => {
|
||||||
// if(getWidthOfText.e === undefined){
|
|
||||||
// getWidthOfText.e = document.createElement('span');
|
|
||||||
// getWidthOfText.e.style.display = "none";
|
|
||||||
// document.body.appendChild(getWidthOfText.e);
|
|
||||||
// }
|
|
||||||
// if(getWidthOfText.e.style.fontSize !== fontsize)
|
|
||||||
// getWidthOfText.e.style.fontSize = fontsize;
|
|
||||||
// if(getWidthOfText.e.style.fontFamily !== 'Signika, sans-serif')
|
|
||||||
// getWidthOfText.e.style.fontFamily = 'Signika, sans-serif';
|
|
||||||
// getWidthOfText.e.innerText = txt;
|
|
||||||
// return getWidthOfText.e.offsetWidth;
|
|
||||||
const text = allCaps ? txt.toUpperCase() : txt;
|
const text = allCaps ? txt.toUpperCase() : txt;
|
||||||
if (getWidthOfText.c === undefined) {
|
if (getWidthOfText.c === undefined) {
|
||||||
getWidthOfText.c = document.createElement('canvas');
|
getWidthOfText.c = document.createElement('canvas');
|
||||||
|
|
@ -82,3 +71,32 @@ export const generateId = (title, length) => {
|
||||||
.join('');
|
.join('');
|
||||||
return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, '0') : id;
|
return Number.isNumeric(length) ? id.slice(0, length).padEnd(length, '0') : id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const rollCommandToJSON = text => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(`{${text.replaceAll(' ', ',').replace(/(\w+(?==))(=)/g, '"$1":')}}`);
|
||||||
|
} catch (_) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getCommandTarget = () => {
|
||||||
|
let target = game.canvas.tokens.controlled.length > 0 ? game.canvas.tokens.controlled[0].actor : null;
|
||||||
|
if (!game.user.isGM) {
|
||||||
|
target = game.user.character;
|
||||||
|
if (!target) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.NoAssignedPlayerCharacter'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!target) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.NoSelectedToken'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (target.type !== 'pc') {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.Notification.Error.OnlyUseableByPC'));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue