mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-12 03:31:07 +01:00
Partial Fate Roll creation and Fate Roll Enricher (/fr)
This commit is contained in:
parent
04f8793f20
commit
54996e7e12
12 changed files with 257 additions and 7 deletions
|
|
@ -8,8 +8,9 @@ import * as fields from './module/data/fields/_module.mjs';
|
||||||
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs';
|
||||||
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
|
import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs';
|
||||||
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
|
import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs';
|
||||||
import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll } from './module/dice/_module.mjs';
|
import { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } from './module/dice/_module.mjs';
|
||||||
import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs';
|
import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs';
|
||||||
|
import { enrichedFateRoll } from './module/enrichers/FateRollEnricher.mjs';
|
||||||
import {
|
import {
|
||||||
handlebarsRegistration,
|
handlebarsRegistration,
|
||||||
runMigrations,
|
runMigrations,
|
||||||
|
|
@ -24,12 +25,13 @@ import TemplateManager from './module/documents/templateManager.mjs';
|
||||||
CONFIG.DH = SYSTEM;
|
CONFIG.DH = SYSTEM;
|
||||||
CONFIG.TextEditor.enrichers.push(...enricherConfig);
|
CONFIG.TextEditor.enrichers.push(...enricherConfig);
|
||||||
|
|
||||||
CONFIG.Dice.rolls = [BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll];
|
CONFIG.Dice.rolls = [BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll];
|
||||||
CONFIG.Dice.daggerheart = {
|
CONFIG.Dice.daggerheart = {
|
||||||
DHRoll: DHRoll,
|
DHRoll: DHRoll,
|
||||||
DualityRoll: DualityRoll,
|
DualityRoll: DualityRoll,
|
||||||
D20Roll: D20Roll,
|
D20Roll: D20Roll,
|
||||||
DamageRoll: DamageRoll
|
DamageRoll: DamageRoll,
|
||||||
|
FateRoll: FateRoll
|
||||||
};
|
};
|
||||||
|
|
||||||
CONFIG.Actor.documentClass = documents.DhpActor;
|
CONFIG.Actor.documentClass = documents.DhpActor;
|
||||||
|
|
@ -240,6 +242,28 @@ Hooks.on('chatMessage', (_, message) => {
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (message.startsWith('/fr')) {
|
||||||
|
const result =
|
||||||
|
message.trim().toLowerCase() === '/fr' ? { result: {} } : rollCommandToJSON(message.replace(/\/fr\s?/, ''));
|
||||||
|
if (!result) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: rollCommand, flavor } = result;
|
||||||
|
|
||||||
|
const target = getCommandTarget({ allowNull: true });
|
||||||
|
const title = 'Fate';
|
||||||
|
|
||||||
|
enrichedFateRoll({
|
||||||
|
target,
|
||||||
|
title,
|
||||||
|
label: 'test',
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('moveToken', async (movedToken, data) => {
|
Hooks.on('moveToken', async (movedToken, data) => {
|
||||||
|
|
|
||||||
|
|
@ -116,14 +116,14 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
context.isLite = this.config.roll?.lite;
|
context.isLite = this.config.roll?.lite;
|
||||||
context.extraFormula = this.config.extraFormula;
|
context.extraFormula = this.config.extraFormula;
|
||||||
context.formula = this.roll.constructFormula(this.config);
|
context.formula = this.roll.constructFormula(this.config);
|
||||||
if (this.actor.system.traits) context.abilities = this.getTraitModifiers();
|
if (this.actor?.system?.traits) context.abilities = this.getTraitModifiers();
|
||||||
|
|
||||||
context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll';
|
context.showReaction = !this.config.roll?.type && context.rollType === 'DualityRoll';
|
||||||
context.reactionOverride = this.reactionOverride;
|
context.reactionOverride = this.reactionOverride;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tagTeamSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
const tagTeamSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
if (tagTeamSetting.members[this.actor.id] && !this.config.skips?.createMessage) {
|
if (this.actor?.id && tagTeamSetting.members[this.actor.id] && !this.config.skips?.createMessage) {
|
||||||
context.activeTagTeamRoll = true;
|
context.activeTagTeamRoll = true;
|
||||||
context.tagTeamSelected = this.config.tagTeamSelected;
|
context.tagTeamSelected = this.config.tagTeamSelected;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ export const config = {
|
||||||
adversaryRoll: DHActorRoll,
|
adversaryRoll: DHActorRoll,
|
||||||
damageRoll: DHActorRoll,
|
damageRoll: DHActorRoll,
|
||||||
dualityRoll: DHActorRoll,
|
dualityRoll: DHActorRoll,
|
||||||
|
fateRoll: DHActorRoll,
|
||||||
groupRoll: DHGroupRoll,
|
groupRoll: DHGroupRoll,
|
||||||
systemMessage: DHSystemMessage
|
systemMessage: DHSystemMessage
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,4 @@ export { default as D20Roll } from './d20Roll.mjs';
|
||||||
export { default as DamageRoll } from './damageRoll.mjs';
|
export { default as DamageRoll } from './damageRoll.mjs';
|
||||||
export { default as DHRoll } from './dhRoll.mjs';
|
export { default as DHRoll } from './dhRoll.mjs';
|
||||||
export { default as DualityRoll } from './dualityRoll.mjs';
|
export { default as DualityRoll } from './dualityRoll.mjs';
|
||||||
|
export { default as FateRoll } from './fateRoll.mjs';
|
||||||
|
|
|
||||||
127
module/dice/fateRoll.mjs
Normal file
127
module/dice/fateRoll.mjs
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
|
||||||
|
import D20Roll from './d20Roll.mjs';
|
||||||
|
import { setDiceSoNiceForFateRoll } from '../helpers/utils.mjs';
|
||||||
|
|
||||||
|
export default class FateRoll extends D20Roll {
|
||||||
|
constructor(formula, data = {}, options = {}) {
|
||||||
|
super(formula, data, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static messageType = 'fateRoll';
|
||||||
|
|
||||||
|
static DefaultDialog = D20RollDialog;
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return game.i18n.localize(
|
||||||
|
`DAGGERHEART.GENERAL.fateRoll`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get dHope() {
|
||||||
|
// if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) return;
|
||||||
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
|
return this.dice[0];
|
||||||
|
// return this.#hopeDice;
|
||||||
|
}
|
||||||
|
|
||||||
|
set dHope(faces) {
|
||||||
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
|
this.terms[0].faces = this.getFaces(faces);
|
||||||
|
// this.#hopeDice = `d${face}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get isCritical() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static getHooks(hooks) {
|
||||||
|
return [...(hooks ?? []), 'Fate'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
static fromData(data) {
|
||||||
|
data.terms[0].class = foundry.dice.terms.Die.name;
|
||||||
|
return super.fromData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
createBaseDice() {
|
||||||
|
if (this.dice[0] instanceof foundry.dice.terms.Die) {
|
||||||
|
this.terms = [this.terms[0]];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.terms[0] = new foundry.dice.terms.Die({ faces: 12 });
|
||||||
|
}
|
||||||
|
|
||||||
|
static async buildEvaluate(roll, config = {}, message = {}) {
|
||||||
|
await super.buildEvaluate(roll, config, message);
|
||||||
|
|
||||||
|
await setDiceSoNiceForFateRoll(
|
||||||
|
roll,
|
||||||
|
config.roll.hope.dice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static postEvaluate(roll, config = {}) {
|
||||||
|
const data = super.postEvaluate(roll, config);
|
||||||
|
|
||||||
|
data.hope = {
|
||||||
|
dice: roll.dHope.denomination,
|
||||||
|
value: roll.dHope.total,
|
||||||
|
rerolled: {
|
||||||
|
any: roll.dHope.results.some(x => x.rerolled),
|
||||||
|
rerolls: roll.dHope.results.filter(x => x.rerolled)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static async reroll(rollString, target, message) {
|
||||||
|
// let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollString, evaluated: false });
|
||||||
|
// const term = parsedRoll.terms[target.dataset.dieIndex];
|
||||||
|
// await term.reroll(`/r1=${term.total}`);
|
||||||
|
// if (game.modules.get('dice-so-nice')?.active) {
|
||||||
|
// const diceSoNiceRoll = {
|
||||||
|
// _evaluated: true,
|
||||||
|
// dice: [
|
||||||
|
// new foundry.dice.terms.Die({
|
||||||
|
// ...term,
|
||||||
|
// faces: term._faces,
|
||||||
|
// results: term.results.filter(x => !x.rerolled)
|
||||||
|
// })
|
||||||
|
// ],
|
||||||
|
// options: { appearance: {} }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const diceSoNicePresets = await getDiceSoNicePresets(`d${term._faces}`, `d${term._faces}`);
|
||||||
|
// const type = target.dataset.type;
|
||||||
|
// if (diceSoNicePresets[type]) {
|
||||||
|
// diceSoNiceRoll.dice[0].options = diceSoNicePresets[type];
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await parsedRoll.evaluate();
|
||||||
|
|
||||||
|
// const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, {
|
||||||
|
// targets: message.system.targets,
|
||||||
|
// roll: {
|
||||||
|
// advantage: message.system.roll.advantage?.type,
|
||||||
|
// difficulty: message.system.roll.difficulty ? Number(message.system.roll.difficulty) : null
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// newRoll.extra = newRoll.extra.slice(2);
|
||||||
|
|
||||||
|
// const tagTeamSettings = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.TagTeamRoll);
|
||||||
|
// Hooks.call(`${CONFIG.DH.id}.postRollDuality`, {
|
||||||
|
// source: { actor: message.system.source.actor ?? '' },
|
||||||
|
// targets: message.system.targets,
|
||||||
|
// tagTeamSelected: Object.values(tagTeamSettings.members).some(x => x.messageId === message._id),
|
||||||
|
// roll: newRoll,
|
||||||
|
// rerolledRoll:
|
||||||
|
// newRoll.result.duality !== message.system.roll.result.duality ? message.system.roll : undefined
|
||||||
|
// });
|
||||||
|
// return { newRoll, parsedRoll };
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
@ -87,6 +87,10 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (this.type === 'fateRoll') {
|
||||||
|
html.classList.add('fate');
|
||||||
|
html.classList.add('hope');
|
||||||
|
}
|
||||||
|
|
||||||
const autoExpandRoll = game.settings.get(
|
const autoExpandRoll = game.settings.get(
|
||||||
CONFIG.DH.id,
|
CONFIG.DH.id,
|
||||||
|
|
|
||||||
64
module/enrichers/FateRollEnricher.mjs
Normal file
64
module/enrichers/FateRollEnricher.mjs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { abilities } from '../config/actorConfig.mjs';
|
||||||
|
import { getCommandTarget, rollCommandToJSON } from '../helpers/utils.mjs';
|
||||||
|
|
||||||
|
export default function DhFateRollEnricher(match, _options) {
|
||||||
|
const roll = rollCommandToJSON(match[1], match[0]);
|
||||||
|
if (!roll) return match[0];
|
||||||
|
|
||||||
|
return getFateMessage(roll.result, roll.flavor ?? 'FLAVOR');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFateMessage(roll, flavor) {
|
||||||
|
const label = flavor ?? 'fate';
|
||||||
|
|
||||||
|
const dataLabel = game.i18n.localize('DAGGERHEART.GENERAL.fate');
|
||||||
|
|
||||||
|
const fateElement = document.createElement('span');
|
||||||
|
fateElement.innerHTML = `
|
||||||
|
<button type="button" class="fate-roll-button${roll?.inline ? ' inline' : ''}"
|
||||||
|
data-title="${label}"
|
||||||
|
data-label="${dataLabel}"
|
||||||
|
data-hope="${roll?.hope ?? 'd12'}"
|
||||||
|
${label}
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return fateElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const renderFateButton = async event => {
|
||||||
|
const button = event.currentTarget,
|
||||||
|
target = getCommandTarget({ allowNull: true });
|
||||||
|
|
||||||
|
await enrichedFateRoll(
|
||||||
|
{
|
||||||
|
target,
|
||||||
|
title: button.dataset.title,
|
||||||
|
label: button.dataset.label
|
||||||
|
},
|
||||||
|
event
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const enrichedFateRoll = async (
|
||||||
|
{ target, title, label },
|
||||||
|
event
|
||||||
|
) => {
|
||||||
|
const config = {
|
||||||
|
event: event ?? {},
|
||||||
|
title: title,
|
||||||
|
roll: {
|
||||||
|
label: label,
|
||||||
|
},
|
||||||
|
hasRoll: true
|
||||||
|
};
|
||||||
|
|
||||||
|
if (target) {
|
||||||
|
await target.diceRoll(config);
|
||||||
|
} else {
|
||||||
|
// For no target, call FateRoll directly with basic data
|
||||||
|
config.data = { experiences: {}, traits: {} };
|
||||||
|
config.source = { actor: null };
|
||||||
|
await CONFIG.Dice.daggerheart.FateRoll.build(config);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { default as DhDamageEnricher, renderDamageButton } from './DamageEnricher.mjs';
|
import { default as DhDamageEnricher, renderDamageButton } from './DamageEnricher.mjs';
|
||||||
import { default as DhDualityRollEnricher, renderDualityButton } from './DualityRollEnricher.mjs';
|
import { default as DhDualityRollEnricher, renderDualityButton } from './DualityRollEnricher.mjs';
|
||||||
|
import { default as DhFateRollEnricher, renderFateButton } from './FateRollEnricher.mjs';
|
||||||
import { default as DhEffectEnricher } from './EffectEnricher.mjs';
|
import { default as DhEffectEnricher } from './EffectEnricher.mjs';
|
||||||
import { default as DhTemplateEnricher, renderMeasuredTemplate } from './TemplateEnricher.mjs';
|
import { default as DhTemplateEnricher, renderMeasuredTemplate } from './TemplateEnricher.mjs';
|
||||||
import { default as DhLookupEnricher } from './LookupEnricher.mjs';
|
import { default as DhLookupEnricher } from './LookupEnricher.mjs';
|
||||||
|
|
||||||
export { DhDamageEnricher, DhDualityRollEnricher, DhEffectEnricher, DhTemplateEnricher };
|
export { DhDamageEnricher, DhDualityRollEnricher, DhEffectEnricher, DhTemplateEnricher, DhFateRollEnricher };
|
||||||
|
|
||||||
export const enricherConfig = [
|
export const enricherConfig = [
|
||||||
{
|
{
|
||||||
|
|
@ -15,6 +16,10 @@ export const enricherConfig = [
|
||||||
pattern: /\[\[\/dr\s?(.*?)\]\]({[^}]*})?/g,
|
pattern: /\[\[\/dr\s?(.*?)\]\]({[^}]*})?/g,
|
||||||
enricher: DhDualityRollEnricher
|
enricher: DhDualityRollEnricher
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
pattern: /\[\[\/fr\s?(.*?)\]\]({[^}]*})?/g,
|
||||||
|
enricher: DhFateRollEnricher
|
||||||
|
},
|
||||||
{
|
{
|
||||||
pattern: /@Effect\[([^\[\]]*)\]({[^}]*})?/g,
|
pattern: /@Effect\[([^\[\]]*)\]({[^}]*})?/g,
|
||||||
enricher: DhEffectEnricher
|
enricher: DhEffectEnricher
|
||||||
|
|
@ -38,6 +43,10 @@ export const enricherRenderSetup = element => {
|
||||||
.querySelectorAll('.duality-roll-button')
|
.querySelectorAll('.duality-roll-button')
|
||||||
.forEach(element => element.addEventListener('click', renderDualityButton));
|
.forEach(element => element.addEventListener('click', renderDualityButton));
|
||||||
|
|
||||||
|
element
|
||||||
|
.querySelectorAll('.fate-roll-button')
|
||||||
|
.forEach(element => element.addEventListener('click', renderFateButton));
|
||||||
|
|
||||||
element
|
element
|
||||||
.querySelectorAll('.measured-template-button')
|
.querySelectorAll('.measured-template-button')
|
||||||
.forEach(element => element.addEventListener('click', renderMeasuredTemplate));
|
.forEach(element => element.addEventListener('click', renderMeasuredTemplate));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { diceTypes, getDiceSoNicePresets, range } from '../config/generalConfig.mjs';
|
import { diceTypes, getDiceSoNicePresets, getDiceSoNicePreset, range } from '../config/generalConfig.mjs';
|
||||||
import Tagify from '@yaireo/tagify';
|
import Tagify from '@yaireo/tagify';
|
||||||
|
|
||||||
export const capitalize = string => {
|
export const capitalize = string => {
|
||||||
|
|
@ -69,6 +69,13 @@ export const setDiceSoNiceForDualityRoll = async (rollResult, advantageState, ho
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setDiceSoNiceForFateRoll = async (rollResult, hopeFaces) => {
|
||||||
|
if (!game.modules.get('dice-so-nice')?.active) return;
|
||||||
|
const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
||||||
|
const diceSoNicePresets = await getDiceSoNicePreset(diceSoNice.hope, hopeFaces);
|
||||||
|
rollResult.dice[0].options = diceSoNicePresets.hope;
|
||||||
|
};
|
||||||
|
|
||||||
export const chunkify = (array, chunkSize, mappingFunc) => {
|
export const chunkify = (array, chunkSize, mappingFunc) => {
|
||||||
var chunkifiedArray = [];
|
var chunkifiedArray = [];
|
||||||
for (let i = 0; i < array.length; i += chunkSize) {
|
for (let i = 0; i < array.length; i += chunkSize) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
.measured-template-button,
|
.measured-template-button,
|
||||||
.enriched-damage-button,
|
.enriched-damage-button,
|
||||||
|
.fate-roll-button,
|
||||||
.duality-roll-button {
|
.duality-roll-button {
|
||||||
display: inline;
|
display: inline;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,6 +267,7 @@
|
||||||
},
|
},
|
||||||
"ChatMessage": {
|
"ChatMessage": {
|
||||||
"dualityRoll": {},
|
"dualityRoll": {},
|
||||||
|
"fateRoll": {},
|
||||||
"adversaryRoll": {},
|
"adversaryRoll": {},
|
||||||
"damageRoll": {},
|
"damageRoll": {},
|
||||||
"abilityUse": {},
|
"abilityUse": {},
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,17 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
{{#if (eq @root.rollType 'FateRoll')}}
|
||||||
|
<div class="dice-option">
|
||||||
|
<img class="dice-icon" src="{{concat 'systems/daggerheart/assets/icons/dice/hope/' @root.roll.dHope.denomination '.svg'}}" alt="">
|
||||||
|
<div class="dice-select">
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.hope"}}</span>
|
||||||
|
<select name="roll.dice.dHope">
|
||||||
|
{{selectOptions diceOptions selected=@root.roll.dHope.denomination}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<fieldset class="experience-container">
|
<fieldset class="experience-container">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue