mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-25 00:43:38 +02:00
Compare commits
No commits in common. "25264c26e91833a7665544f754e9aa24cd0f950d" and "dbd5ef8bb0b689510589b5de6348f5a981210bed" have entirely different histories.
25264c26e9
...
dbd5ef8bb0
24 changed files with 336 additions and 368 deletions
|
|
@ -1,3 +1,3 @@
|
||||||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M 7.12 0.5 H 52.88 C 56.29 0.5 58.88 3.57 58.3 6.93 L 51.46 46.68 C 51.16 48.44 50.02 49.95 48.4 50.71 L 32.36 58.33 C 30.87 59.04 29.13 59.04 27.64 58.33 L 11.6 50.71 C 9.98 49.95 8.84 48.44 8.54 46.68 L 1.7 6.93 C 1.12 3.57 3.71 0.5 7.12 0.5 Z" fill="transparent" stroke="#18162e"/>
|
<path d="M6.12012 0.5H51.8799C55.2901 0.500041 57.8779 3.57175 57.2998 6.93262L50.4639 46.6777C50.1604 48.4411 49.0179 49.9467 47.4014 50.7139L31.3584 58.3271C29.8661 59.0354 28.1339 59.0354 26.6416 58.3271L10.5986 50.7139C8.98214 49.9467 7.83959 48.4411 7.53613 46.6777L0.700195 6.93262C0.122088 3.57175 2.7099 0.500042 6.12012 0.5Z" fill="transparent" stroke="#18162e"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 476 B |
|
|
@ -1,3 +1,3 @@
|
||||||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M 7.12 0.5 H 52.88 C 56.29 0.5 58.88 3.57 58.3 6.93 L 51.46 46.68 C 51.16 48.44 50.02 49.95 48.4 50.71 L 32.36 58.33 C 30.87 59.04 29.13 59.04 27.64 58.33 L 11.6 50.71 C 9.98 49.95 8.84 48.44 8.54 46.68 L 1.7 6.93 C 1.12 3.57 3.71 0.5 7.12 0.5 Z" fill="#18152E" stroke="#F3C267"/>
|
<path d="M6.12012 0.5H51.8799C55.2901 0.500041 57.8779 3.57175 57.2998 6.93262L50.4639 46.6777C50.1604 48.4411 49.0179 49.9467 47.4014 50.7139L31.3584 58.3271C29.8661 59.0354 28.1339 59.0354 26.6416 58.3271L10.5986 50.7139C8.98214 49.9467 7.83959 48.4411 7.53613 46.6777L0.700195 6.93262C0.122088 3.57175 2.7099 0.500042 6.12012 0.5Z" fill="#18152E" stroke="#F3C267"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 472 B |
|
|
@ -9,7 +9,10 @@ import * as dice from './module/dice/_module.mjs';
|
||||||
import * as fields from './module/data/fields/_module.mjs';
|
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 { BaseRoll, DHRoll, DualityRoll, D20Roll, DamageRoll, FateRoll } 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 { enrichedFateRoll, getFateTypeData } from './module/enrichers/FateRollEnricher.mjs';
|
||||||
import {
|
import {
|
||||||
handlebarsRegistration,
|
handlebarsRegistration,
|
||||||
runMigrations,
|
runMigrations,
|
||||||
|
|
@ -32,8 +35,6 @@ CONFIG.Dice.daggerheart = {
|
||||||
FateRoll: FateRoll
|
FateRoll: FateRoll
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(CONFIG.Dice.termTypes, dice.diceTypes);
|
|
||||||
|
|
||||||
CONFIG.Actor.documentClass = documents.DhpActor;
|
CONFIG.Actor.documentClass = documents.DhpActor;
|
||||||
CONFIG.Actor.dataModels = models.actors.config;
|
CONFIG.Actor.dataModels = models.actors.config;
|
||||||
CONFIG.Actor.collection = collections.DhActorCollection;
|
CONFIG.Actor.collection = collections.DhActorCollection;
|
||||||
|
|
@ -332,6 +333,78 @@ Hooks.on('renderHandlebarsApplication', (_, element) => {
|
||||||
enricherRenderSetup(element);
|
enricherRenderSetup(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('chatMessage', (_, message) => {
|
||||||
|
if (message.startsWith('/dr')) {
|
||||||
|
const result =
|
||||||
|
message.trim().toLowerCase() === '/dr' ? { result: {} } : rollCommandToJSON(message.replace(/\/dr\s?/, ''));
|
||||||
|
if (!result) {
|
||||||
|
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.dualityParsing'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { result: rollCommand, flavor } = result;
|
||||||
|
|
||||||
|
const reaction = rollCommand.reaction;
|
||||||
|
const traitValue = rollCommand.trait?.toLowerCase();
|
||||||
|
const advantage = rollCommand.advantage
|
||||||
|
? CONFIG.DH.ACTIONS.advantageState.advantage.value
|
||||||
|
: rollCommand.disadvantage
|
||||||
|
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
|
||||||
|
: undefined;
|
||||||
|
const difficulty = rollCommand.difficulty;
|
||||||
|
const grantResources = rollCommand.grantResources;
|
||||||
|
|
||||||
|
const target = getCommandTarget({ allowNull: true });
|
||||||
|
const title =
|
||||||
|
(flavor ?? traitValue)
|
||||||
|
? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
||||||
|
ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label)
|
||||||
|
})
|
||||||
|
: game.i18n.localize('DAGGERHEART.GENERAL.duality');
|
||||||
|
|
||||||
|
enrichedDualityRoll({
|
||||||
|
reaction,
|
||||||
|
traitValue,
|
||||||
|
target,
|
||||||
|
difficulty,
|
||||||
|
title,
|
||||||
|
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'),
|
||||||
|
actionType: null,
|
||||||
|
advantage,
|
||||||
|
grantResources
|
||||||
|
});
|
||||||
|
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 fateTypeData = getFateTypeData(rollCommand?.type);
|
||||||
|
|
||||||
|
if (!fateTypeData)
|
||||||
|
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
|
||||||
|
|
||||||
|
const { value: fateType, label: fateTypeLabel } = fateTypeData;
|
||||||
|
const target = getCommandTarget({ allowNull: true });
|
||||||
|
const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll');
|
||||||
|
|
||||||
|
enrichedFateRoll({
|
||||||
|
target,
|
||||||
|
title,
|
||||||
|
label: fateTypeLabel,
|
||||||
|
fateType
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Hooks.on(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, async data => {
|
Hooks.on(CONFIG.DH.HOOKS.hooksConfig.tagTeamStart, async data => {
|
||||||
if (data.openForAllPlayers && data.partyId) {
|
if (data.openForAllPlayers && data.partyId) {
|
||||||
const party = game.actors.get(data.partyId);
|
const party = game.actors.get(data.partyId);
|
||||||
|
|
|
||||||
|
|
@ -200,7 +200,6 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
|
|
||||||
partContext.members[partId] = {
|
partContext.members[partId] = {
|
||||||
...data,
|
...data,
|
||||||
roll: data.roll,
|
|
||||||
isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER),
|
isEditable: actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER),
|
||||||
key: partId,
|
key: partId,
|
||||||
readyToRoll: Boolean(data.rollChoice),
|
readyToRoll: Boolean(data.rollChoice),
|
||||||
|
|
@ -449,19 +448,24 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
const { member, diceType } = button.dataset;
|
const { member, diceType } = button.dataset;
|
||||||
const memberData = this.party.system.tagTeam.members[member];
|
const memberData = this.party.system.tagTeam.members[member];
|
||||||
|
|
||||||
const dieIndex = diceType === 'hope' ? 0 : diceType === 'fear' ? 1 : 2;
|
const dieIndex = diceType === 'hope' ? 0 : diceType === 'fear' ? 2 : 4;
|
||||||
const newRoll = game.system.api.dice.DualityRoll.fromData(memberData.rollData);
|
|
||||||
const dice = newRoll.dice[dieIndex];
|
const { parsedRoll, newRoll } = await game.system.api.dice.DualityRoll.reroll(
|
||||||
await dice.reroll(`/r1=${dice.total}`, {
|
memberData.rollData,
|
||||||
liveRoll: {
|
dieIndex,
|
||||||
roll: newRoll,
|
diceType,
|
||||||
isReaction: true
|
false
|
||||||
}
|
);
|
||||||
});
|
const rollData = parsedRoll.toJSON();
|
||||||
const rollData = newRoll.toJSON();
|
|
||||||
this.updatePartyData(
|
this.updatePartyData(
|
||||||
{
|
{
|
||||||
[`system.tagTeam.members.${member}.rollData`]: rollData
|
[`system.tagTeam.members.${member}.rollData`]: {
|
||||||
|
...rollData,
|
||||||
|
options: {
|
||||||
|
...rollData.options,
|
||||||
|
roll: newRoll
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
this.getUpdatingParts(button)
|
this.getUpdatingParts(button)
|
||||||
);
|
);
|
||||||
|
|
@ -696,9 +700,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
const error = this.checkInitiatorHopeError(this.party.system.tagTeam.initiator);
|
const error = this.checkInitiatorHopeError(this.party.system.tagTeam.initiator);
|
||||||
if (error) return error;
|
if (error) return error;
|
||||||
|
|
||||||
const joinedRoll = await this.getJoinedRoll();
|
const mainRoll = (await this.getJoinedRoll()).rollData;
|
||||||
const mainRoll = joinedRoll.rollData;
|
|
||||||
const finalRoll = foundry.utils.deepClone(joinedRoll.roll);
|
|
||||||
|
|
||||||
const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor);
|
const mainActor = this.party.system.partyMembers.find(x => x.uuid === mainRoll.options.source.actor);
|
||||||
mainRoll.options.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle');
|
mainRoll.options.title = game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.chatMessageRollTitle');
|
||||||
|
|
@ -709,7 +711,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'),
|
title: game.i18n.localize('DAGGERHEART.APPLICATIONS.TagTeamSelect.title'),
|
||||||
speaker: cls.getSpeaker({ actor: mainActor }),
|
speaker: cls.getSpeaker({ actor: mainActor }),
|
||||||
system: mainRoll.options,
|
system: mainRoll.options,
|
||||||
rolls: [JSON.stringify(joinedRoll.roll)],
|
rolls: [mainRoll],
|
||||||
sound: null,
|
sound: null,
|
||||||
flags: { core: { RollTable: true } }
|
flags: { core: { RollTable: true } }
|
||||||
};
|
};
|
||||||
|
|
@ -721,7 +723,7 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
const fearUpdate = { key: 'fear', value: null, total: null, enabled: true };
|
const fearUpdate = { key: 'fear', value: null, total: null, enabled: true };
|
||||||
for (let memberId in tagTeamData.members) {
|
for (let memberId in tagTeamData.members) {
|
||||||
const resourceUpdates = [];
|
const resourceUpdates = [];
|
||||||
const rollGivesHope = finalRoll.isCritical || finalRoll.withHope;
|
const rollGivesHope = mainRoll.options.roll.isCritical || mainRoll.options.roll.result.duality === 1;
|
||||||
if (memberId === tagTeamData.initiator.memberId) {
|
if (memberId === tagTeamData.initiator.memberId) {
|
||||||
const value = tagTeamData.initiator.cost
|
const value = tagTeamData.initiator.cost
|
||||||
? rollGivesHope
|
? rollGivesHope
|
||||||
|
|
@ -732,8 +734,9 @@ export default class TagTeamDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
} else if (rollGivesHope) {
|
} else if (rollGivesHope) {
|
||||||
resourceUpdates.push({ key: 'hope', value: 1, total: -1, enabled: true });
|
resourceUpdates.push({ key: 'hope', value: 1, total: -1, enabled: true });
|
||||||
}
|
}
|
||||||
if (finalRoll.isCritical) resourceUpdates.push({ key: 'stress', value: -1, total: 1, enabled: true });
|
if (mainRoll.options.roll.isCritical)
|
||||||
if (finalRoll.withFear) {
|
resourceUpdates.push({ key: 'stress', value: -1, total: 1, enabled: true });
|
||||||
|
if (mainRoll.options.roll.result.duality === -1) {
|
||||||
fearUpdate.value = fearUpdate.value === null ? 1 : fearUpdate.value + 1;
|
fearUpdate.value = fearUpdate.value === null ? 1 : fearUpdate.value + 1;
|
||||||
fearUpdate.total = fearUpdate.total === null ? -1 : fearUpdate.total - 1;
|
fearUpdate.total = fearUpdate.total === null ? -1 : fearUpdate.total - 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
import { abilities } from '../../config/actorConfig.mjs';
|
import { abilities } from '../../config/actorConfig.mjs';
|
||||||
import { enrichedDualityRoll } from '../../enrichers/DualityRollEnricher.mjs';
|
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||||
import { enrichedFateRoll, getFateTypeData } from '../../enrichers/FateRollEnricher.mjs';
|
|
||||||
import { getCommandTarget, rollCommandToJSON } from '../../helpers/utils.mjs';
|
|
||||||
import { emitAsGM, GMUpdateEvent } from '../../systemRegistration/socket.mjs';
|
|
||||||
|
|
||||||
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
|
|
@ -24,84 +21,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
classes: ['daggerheart']
|
classes: ['daggerheart']
|
||||||
};
|
};
|
||||||
|
|
||||||
static CHAT_COMMANDS = {
|
|
||||||
...super.CHAT_COMMANDS,
|
|
||||||
dr: {
|
|
||||||
rgx: /^(?:\/dr)((?:\s)[^]*)?/,
|
|
||||||
fn: (_, match) => {
|
|
||||||
const argString = match[1]?.trim();
|
|
||||||
const result = argString ? rollCommandToJSON(argString) : { result: {} };
|
|
||||||
if (!result) {
|
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.dualityParsing'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: rollCommand, flavor } = result;
|
|
||||||
|
|
||||||
const reaction = rollCommand.reaction;
|
|
||||||
const traitValue = rollCommand.trait?.toLowerCase();
|
|
||||||
const advantage = rollCommand.advantage
|
|
||||||
? CONFIG.DH.ACTIONS.advantageState.advantage.value
|
|
||||||
: rollCommand.disadvantage
|
|
||||||
? CONFIG.DH.ACTIONS.advantageState.disadvantage.value
|
|
||||||
: undefined;
|
|
||||||
const difficulty = rollCommand.difficulty;
|
|
||||||
const grantResources = rollCommand.grantResources;
|
|
||||||
|
|
||||||
const target = getCommandTarget({ allowNull: true });
|
|
||||||
const title =
|
|
||||||
(flavor ?? traitValue)
|
|
||||||
? game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
|
|
||||||
ability: game.i18n.localize(SYSTEM.ACTOR.abilities[traitValue].label)
|
|
||||||
})
|
|
||||||
: game.i18n.localize('DAGGERHEART.GENERAL.duality');
|
|
||||||
|
|
||||||
enrichedDualityRoll({
|
|
||||||
reaction,
|
|
||||||
traitValue,
|
|
||||||
target,
|
|
||||||
difficulty,
|
|
||||||
title,
|
|
||||||
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'),
|
|
||||||
actionType: null,
|
|
||||||
advantage,
|
|
||||||
grantResources
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fr: {
|
|
||||||
rgx: /^(?:\/fr)((?:\s)[^]*)?/,
|
|
||||||
fn: (_, match) => {
|
|
||||||
const argString = match[1]?.trim();
|
|
||||||
const result = argString ? rollCommandToJSON(argString) : { result: {} };
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateParsing'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result: rollCommand, flavor } = result;
|
|
||||||
const fateTypeData = getFateTypeData(rollCommand?.type);
|
|
||||||
|
|
||||||
if (!fateTypeData)
|
|
||||||
return ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
|
|
||||||
|
|
||||||
const { value: fateType, label: fateTypeLabel } = fateTypeData;
|
|
||||||
const target = getCommandTarget({ allowNull: true });
|
|
||||||
const title = flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fateRoll');
|
|
||||||
|
|
||||||
enrichedFateRoll({
|
|
||||||
target,
|
|
||||||
title,
|
|
||||||
label: fateTypeLabel,
|
|
||||||
fateType
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_getEntryContextOptions() {
|
_getEntryContextOptions() {
|
||||||
return [
|
return [
|
||||||
...super._getEntryContextOptions(),
|
...super._getEntryContextOptions(),
|
||||||
|
|
@ -256,7 +175,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
action.use(event);
|
action.use(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
async rerollEvent(event, messageData) {
|
async rerollEvent(event, message) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (!event.shiftKey) {
|
if (!event.shiftKey) {
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
|
@ -268,7 +187,6 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
if (!confirmed) return;
|
if (!confirmed) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const message = game.messages.get(messageData._id);
|
|
||||||
const target = event.target.closest('[data-die-index]');
|
const target = event.target.closest('[data-die-index]');
|
||||||
|
|
||||||
if (target.dataset.type === 'damage') {
|
if (target.dataset.type === 'damage') {
|
||||||
|
|
@ -291,16 +209,27 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const rerollDice = message.system.roll.dice[target.dataset.dieIndex];
|
let originalRoll_parsed = message.rolls.map(roll => JSON.parse(roll))[0];
|
||||||
await rerollDice.reroll(`/r1=${rerollDice.total}`, {
|
const rollClass =
|
||||||
liveRoll: {
|
game.system.api.dice[
|
||||||
roll: message.system.roll,
|
message.type === 'dualityRoll'
|
||||||
actor: message.system.actionActor,
|
? 'DualityRoll'
|
||||||
isReaction: message.system.roll.options.actionType === 'reaction'
|
: target.dataset.type === 'damage'
|
||||||
}
|
? 'DHRoll'
|
||||||
});
|
: 'D20Roll'
|
||||||
await message.update({
|
];
|
||||||
rolls: [message.system.roll.toJSON()]
|
|
||||||
|
if (!game.modules.get('dice-so-nice')?.active) foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
|
||||||
|
|
||||||
|
const { newRoll, parsedRoll } = await rollClass.reroll(
|
||||||
|
originalRoll_parsed,
|
||||||
|
target.dataset.dieIndex,
|
||||||
|
target.dataset.type
|
||||||
|
);
|
||||||
|
|
||||||
|
await game.messages.get(message._id).update({
|
||||||
|
'system.roll': newRoll,
|
||||||
|
'rolls': [parsedRoll]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
return {
|
return {
|
||||||
title: new fields.StringField(),
|
title: new fields.StringField(),
|
||||||
actionDescription: new fields.HTMLField(),
|
actionDescription: new fields.HTMLField(),
|
||||||
|
roll: new fields.ObjectField(),
|
||||||
targets: targetsField(),
|
targets: targetsField(),
|
||||||
hasRoll: new fields.BooleanField({ initial: false }),
|
hasRoll: new fields.BooleanField({ initial: false }),
|
||||||
hasDamage: new fields.BooleanField({ initial: false }),
|
hasDamage: new fields.BooleanField({ initial: false }),
|
||||||
|
|
@ -54,16 +55,6 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
get roll() {
|
|
||||||
if (this.parent.type === 'dualityRoll')
|
|
||||||
return this.parent.rolls.find(x => x instanceof game.system.api.dice.DualityRoll);
|
|
||||||
|
|
||||||
if (this.parent.type === 'fateRoll')
|
|
||||||
return this.parent.rolls.find(x => x instanceof game.system.api.dice.FateRoll);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get actionActor() {
|
get actionActor() {
|
||||||
if (!this.source.actor) return null;
|
if (!this.source.actor) return null;
|
||||||
return fromUuidSync(this.source.actor);
|
return fromUuidSync(this.source.actor);
|
||||||
|
|
|
||||||
|
|
@ -4,4 +4,3 @@ 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';
|
export { default as FateRoll } from './fateRoll.mjs';
|
||||||
export { diceTypes } from './die/_module.mjs';
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export default class D20Roll extends DHRoll {
|
||||||
get isCritical() {
|
get isCritical() {
|
||||||
if (!this.d20._evaluated) return;
|
if (!this.d20._evaluated) return;
|
||||||
|
|
||||||
const criticalThreshold = this.options.actionType === 'reaction' ? 20 : this.data.criticalThreshold;
|
const criticalThreshold = this.options.actionType === 'reaction' ? 20 : this.data.system.criticalThreshold;
|
||||||
return this.d20.total >= criticalThreshold;
|
return this.d20.total >= criticalThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -217,11 +217,49 @@ export default class D20Roll extends DHRoll {
|
||||||
results: d.results
|
results: d.results
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
data.modifierTotal = roll.modifierTotal;
|
data.modifierTotal = this.calculateTotalModifiers(roll);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
resetFormula() {
|
resetFormula() {
|
||||||
return (this._formula = this.constructor.getFormula(this.terms));
|
return (this._formula = this.constructor.getFormula(this.terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async reroll(rollString, _target, message) {
|
||||||
|
let parsedRoll = game.system.api.dice.D20Roll.fromData(rollString);
|
||||||
|
parsedRoll = await parsedRoll.reroll();
|
||||||
|
const newRoll = game.system.api.dice.D20Roll.postEvaluate(parsedRoll, {
|
||||||
|
targets: message.system.targets,
|
||||||
|
roll: {
|
||||||
|
advantage: message.system.roll.advantage?.type,
|
||||||
|
difficulty: message.system.roll.difficulty ? Number(message.system.roll.difficulty) : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (game.modules.get('dice-so-nice')?.active) {
|
||||||
|
await game.dice3d.showForRoll(parsedRoll, game.user, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const rerolled = {
|
||||||
|
any: true,
|
||||||
|
rerolls: [
|
||||||
|
...(message.system.roll.dice[0].rerolled?.rerolls?.length > 0
|
||||||
|
? [message.system.roll.dice[0].rerolled?.rerolls]
|
||||||
|
: []),
|
||||||
|
rollString.terms[0].results
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
newRoll: {
|
||||||
|
...newRoll,
|
||||||
|
dice: [
|
||||||
|
{
|
||||||
|
...newRoll.dice[0],
|
||||||
|
rerolled: rerolled
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
parsedRoll
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,6 @@ export default class DHRoll extends Roll {
|
||||||
return game.i18n.localize('DAGGERHEART.GENERAL.Roll.basic');
|
return game.i18n.localize('DAGGERHEART.GENERAL.Roll.basic');
|
||||||
}
|
}
|
||||||
|
|
||||||
get modifierTotal() {
|
|
||||||
return this.constructor.calculateTotalModifiers(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static messageType = 'adversaryRoll';
|
static messageType = 'adversaryRoll';
|
||||||
|
|
||||||
static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs';
|
static CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/roll.hbs';
|
||||||
|
|
@ -142,7 +138,6 @@ export default class DHRoll extends Roll {
|
||||||
const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options });
|
const chatData = await this._prepareChatRenderContext({ flavor, isPrivate, ...options });
|
||||||
return foundry.applications.handlebars.renderTemplate(template, {
|
return foundry.applications.handlebars.renderTemplate(template, {
|
||||||
...chatData,
|
...chatData,
|
||||||
roll: this,
|
|
||||||
parent: chatData.parent,
|
parent: chatData.parent,
|
||||||
targetMode: chatData.targetMode,
|
targetMode: chatData.targetMode,
|
||||||
metagamingSettings
|
metagamingSettings
|
||||||
|
|
@ -246,21 +241,16 @@ export default class DHRoll extends Roll {
|
||||||
return (this._formula = this.constructor.getFormula(this.terms));
|
return (this._formula = this.constructor.getFormula(this.terms));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate total modifiers of any rolls, including non-dh rolls.
|
|
||||||
* This exists because damage rolls still may receive base roll classes
|
|
||||||
*/
|
|
||||||
static calculateTotalModifiers(roll) {
|
static calculateTotalModifiers(roll) {
|
||||||
let modifierTotal = 0;
|
let modifierTotal = 0;
|
||||||
for (let i = 0; i < roll.terms.length; i++) {
|
for (let i = 0; i < roll.terms.length; i++) {
|
||||||
if (!roll.terms[i].isDeterministic) continue;
|
if (
|
||||||
const termTotal = roll.terms[i].total;
|
roll.terms[i] instanceof foundry.dice.terms.NumericTerm &&
|
||||||
if (typeof termTotal === 'number') {
|
!!roll.terms[i - 1] &&
|
||||||
const multiplier = roll.terms[i - 1]?.operator === " - " ? -1 : 1;
|
roll.terms[i - 1] instanceof foundry.dice.terms.OperatorTerm
|
||||||
modifierTotal += multiplier * termTotal;
|
)
|
||||||
}
|
modifierTotal += Number(`${roll.terms[i - 1].operator}${roll.terms[i].total}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modifierTotal;
|
return modifierTotal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import DualityDie from './dualityDie.mjs';
|
|
||||||
import AdvantageDie from './advantageDie.mjs';
|
|
||||||
import DisadvantageDie from './disadvantageDie.mjs';
|
|
||||||
|
|
||||||
export const diceTypes = {
|
|
||||||
DualityDie,
|
|
||||||
AdvantageDie,
|
|
||||||
DisadvantageDie
|
|
||||||
};
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
export default class AdvantageDie extends foundry.dice.terms.Die {
|
|
||||||
constructor(options) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this.modifiers = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
export default class DisadvantageDie extends foundry.dice.terms.Die {
|
|
||||||
constructor(options) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this.modifiers = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
import { ResourceUpdateMap } from '../../data/action/baseAction.mjs';
|
|
||||||
|
|
||||||
export default class DualityDie extends foundry.dice.terms.Die {
|
|
||||||
constructor(options) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this.modifiers = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
#getDualityState(roll) {
|
|
||||||
if (!roll) return null;
|
|
||||||
return roll.withHope ? 1 : roll.withFear ? -1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#updateResources(oldDuality, newDuality, actor) {
|
|
||||||
const { hopeFear } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation);
|
|
||||||
if (game.user.isGM ? !hopeFear.gm : !hopeFear.players) return;
|
|
||||||
|
|
||||||
const updates = [];
|
|
||||||
const hope = (newDuality >= 0 ? 1 : 0) - (oldDuality >= 0 ? 1 : 0);
|
|
||||||
const stress = (newDuality === 0 ? 1 : 0) - (oldDuality === 0 ? 1 : 0);
|
|
||||||
const fear = (newDuality === -1 ? 1 : 0) - (oldDuality === -1 ? 1 : 0);
|
|
||||||
|
|
||||||
if (hope !== 0) updates.push({ key: 'hope', value: hope, total: -1 * hope, enabled: true });
|
|
||||||
if (stress !== 0) updates.push({ key: 'stress', value: -1 * stress, total: stress, enabled: true });
|
|
||||||
if (fear !== 0) updates.push({ key: 'fear', value: fear, total: -1 * fear, enabled: true });
|
|
||||||
|
|
||||||
const resourceUpdates = new ResourceUpdateMap(actor);
|
|
||||||
resourceUpdates.addResources(updates);
|
|
||||||
resourceUpdates.updateResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
async reroll(modifier, options) {
|
|
||||||
const oldDuality = this.#getDualityState(options.liveRoll.roll);
|
|
||||||
await super.reroll(modifier, options);
|
|
||||||
|
|
||||||
if (options?.liveRoll) {
|
|
||||||
/* Can't currently test since DiceSoNice is not v14. Might need to set the appearance earlier if a roll is triggered by super.reroll */
|
|
||||||
if (game.modules.get('dice-so-nice')?.active) {
|
|
||||||
const diceSoNiceRoll = {
|
|
||||||
_evaluated: true,
|
|
||||||
dice: [this],
|
|
||||||
options: { appearance: {} }
|
|
||||||
};
|
|
||||||
|
|
||||||
const preset = await getDiceSoNicePreset(diceSoNice[key], faces);
|
|
||||||
diceSoNiceRoll.dice[0].options.appearance = preset.appearance;
|
|
||||||
diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile;
|
|
||||||
|
|
||||||
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
|
||||||
} else {
|
|
||||||
foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
|
|
||||||
}
|
|
||||||
|
|
||||||
await options.liveRoll.roll._evaluate();
|
|
||||||
if (options.liveRoll.isReaction) return;
|
|
||||||
|
|
||||||
const newDuality = this.#getDualityState(options.liveRoll.roll);
|
|
||||||
this.#updateResources(oldDuality, newDuality, options.liveRoll.actor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
|
import D20RollDialog from '../applications/dialogs/d20RollDialog.mjs';
|
||||||
import D20Roll from './d20Roll.mjs';
|
import D20Roll from './d20Roll.mjs';
|
||||||
import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
import { parseRallyDice, setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
|
||||||
|
import { getDiceSoNicePresets } from '../config/generalConfig.mjs';
|
||||||
|
import { ResourceUpdateMap } from '../data/action/baseAction.mjs';
|
||||||
|
|
||||||
export default class DualityRoll extends D20Roll {
|
export default class DualityRoll extends D20Roll {
|
||||||
_advantageFaces = 6;
|
_advantageFaces = 6;
|
||||||
|
|
@ -24,31 +26,27 @@ export default class DualityRoll extends D20Roll {
|
||||||
}
|
}
|
||||||
|
|
||||||
get dHope() {
|
get dHope() {
|
||||||
if (!(this.dice[0] instanceof game.system.api.dice.diceTypes.DualityDie)) this.createBaseDice();
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
return this.dice[0];
|
return this.dice[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
set dHope(faces) {
|
set dHope(faces) {
|
||||||
// TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dHope.faces
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
this.dHope.faces = this.getFaces(faces);
|
this.dice[0].faces = this.getFaces(faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dFear() {
|
get dFear() {
|
||||||
if (!(this.dice[1] instanceof game.system.api.dice.diceTypes.DualityDie)) this.createBaseDice();
|
if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
return this.dice[1];
|
return this.dice[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
set dFear(faces) {
|
set dFear(faces) {
|
||||||
// TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dFear.faces
|
if (!(this.dice[1] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
this.dFear.faces = this.getFaces(faces);
|
this.dice[1].faces = this.getFaces(faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dAdvantage() {
|
get dAdvantage() {
|
||||||
return this.dice[2] instanceof game.system.api.dice.diceTypes.AdvantageDie ? this.dice[2] : null;
|
return this.dice[2];
|
||||||
}
|
|
||||||
|
|
||||||
get dDisadvantage() {
|
|
||||||
return this.dice[2] instanceof game.system.api.dice.diceTypes.DisadvantageDie ? this.dice[2] : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get advantageFaces() {
|
get advantageFaces() {
|
||||||
|
|
@ -67,11 +65,6 @@ export default class DualityRoll extends D20Roll {
|
||||||
this._advantageNumber = Number(value);
|
this._advantageNumber = Number(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
get extraDice() {
|
|
||||||
const { DualityDie, AdvantageDie, DisadvantageDie } = game.system.api.dice.diceTypes;
|
|
||||||
return this.dice.filter(x => ![DualityDie, AdvantageDie, DisadvantageDie].some(die => x instanceof die));
|
|
||||||
}
|
|
||||||
|
|
||||||
setRallyChoices() {
|
setRallyChoices() {
|
||||||
return this.data?.parent?.appliedEffects.reduce((a, c) => {
|
return this.data?.parent?.appliedEffects.reduce((a, c) => {
|
||||||
const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally');
|
const change = c.system.changes.find(ch => ch.key === 'system.bonuses.rally');
|
||||||
|
|
@ -125,28 +118,22 @@ export default class DualityRoll extends D20Roll {
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static fromData(data) {
|
static fromData(data) {
|
||||||
data.terms[0].class = 'DualityDie';
|
data.terms[0].class = foundry.dice.terms.Die.name;
|
||||||
data.terms[2].class = 'DualityDie';
|
data.terms[2].class = foundry.dice.terms.Die.name;
|
||||||
if (data.options.roll.advantage?.type && data.terms[4]?.faces) {
|
|
||||||
data.terms[4].class = data.options.roll.advantage.type === 1 ? 'AdvantageDie' : 'DisadvantageDie';
|
|
||||||
}
|
|
||||||
return super.fromData(data);
|
return super.fromData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
createBaseDice() {
|
createBaseDice() {
|
||||||
if (
|
if (this.dice[0] instanceof foundry.dice.terms.Die && this.dice[1] instanceof foundry.dice.terms.Die) {
|
||||||
this.dice[0] instanceof game.system.api.dice.diceTypes.DualityDie &&
|
|
||||||
this.dice[1] instanceof game.system.api.dice.diceTypes.DualityDie
|
|
||||||
) {
|
|
||||||
this.terms = [this.terms[0], this.terms[1], this.terms[2]];
|
this.terms = [this.terms[0], this.terms[1], this.terms[2]];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.terms[0] = new game.system.api.dice.diceTypes.DualityDie({
|
this.terms[0] = new foundry.dice.terms.Die({
|
||||||
faces: this.data.rules.dualityRoll?.defaultHopeDice ?? 12
|
faces: this.data.rules.dualityRoll?.defaultHopeDice ?? 12
|
||||||
});
|
});
|
||||||
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
|
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
|
||||||
this.terms[2] = new game.system.api.dice.diceTypes.DualityDie({
|
this.terms[2] = new foundry.dice.terms.Die({
|
||||||
faces: this.data.rules.dualityRoll?.defaultFearDice ?? 12
|
faces: this.data.rules.dualityRoll?.defaultFearDice ?? 12
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -384,4 +371,63 @@ export default class DualityRoll extends D20Roll {
|
||||||
if (currentCombatant?.actorId == config.data.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
if (currentCombatant?.actorId == config.data.id) ui.combat.setCombatantSpotlight(currentCombatant.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async reroll(rollBase, dieIndex, diceType, updateResources = true) {
|
||||||
|
let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollBase, evaluated: false });
|
||||||
|
const term = parsedRoll.terms[dieIndex];
|
||||||
|
await term.reroll(`/r1=${term.total}`);
|
||||||
|
const result = await parsedRoll.evaluate();
|
||||||
|
|
||||||
|
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}`);
|
||||||
|
if (diceSoNicePresets[diceType]) {
|
||||||
|
diceSoNiceRoll.dice[0].options = diceSoNicePresets[diceType];
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true);
|
||||||
|
} else {
|
||||||
|
foundry.audio.AudioHelper.play({ src: CONFIG.sounds.dice });
|
||||||
|
}
|
||||||
|
|
||||||
|
const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, {
|
||||||
|
targets: parsedRoll.options.targets ?? [],
|
||||||
|
roll: {
|
||||||
|
advantage: parsedRoll.options.roll.advantage?.type,
|
||||||
|
difficulty: parsedRoll.options.roll.difficulty ? Number(parsedRoll.options.roll.difficulty) : null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const extraIndex = newRoll.advantage ? 3 : 2;
|
||||||
|
newRoll.extra = newRoll.extra.slice(extraIndex);
|
||||||
|
|
||||||
|
const actor = parsedRoll.options.source.actor
|
||||||
|
? await foundry.utils.fromUuid(parsedRoll.options.source.actor)
|
||||||
|
: null;
|
||||||
|
const config = {
|
||||||
|
source: { actor: parsedRoll.options.source.actor ?? '' },
|
||||||
|
targets: parsedRoll.targets,
|
||||||
|
roll: newRoll,
|
||||||
|
rerolledRoll: parsedRoll.options.roll,
|
||||||
|
resourceUpdates: new ResourceUpdateMap(actor)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (updateResources) {
|
||||||
|
await DualityRoll.addDualityResourceUpdates(config);
|
||||||
|
await config.resourceUpdates.updateResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
return { newRoll, parsedRoll };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ export default class FateRoll extends D20Roll {
|
||||||
}
|
}
|
||||||
|
|
||||||
set dHope(faces) {
|
set dHope(faces) {
|
||||||
// TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dHope.faces
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
this.dHope.faces = this.getFaces(faces);
|
this.dice[0].faces = this.getFaces(faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dFear() {
|
get dFear() {
|
||||||
|
|
@ -31,8 +31,8 @@ export default class FateRoll extends D20Roll {
|
||||||
}
|
}
|
||||||
|
|
||||||
set dFear(faces) {
|
set dFear(faces) {
|
||||||
// TODO this should not be asymmetrical with the getter. updateRollConfiguration() should use dFear.faces
|
if (!(this.dice[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
|
||||||
this.dFear.faces = this.getFaces(faces);
|
this.dice[0].faces = this.getFaces(faces);
|
||||||
}
|
}
|
||||||
|
|
||||||
get isCritical() {
|
get isCritical() {
|
||||||
|
|
@ -43,20 +43,6 @@ export default class FateRoll extends D20Roll {
|
||||||
return this.data.fateType;
|
return this.data.fateType;
|
||||||
}
|
}
|
||||||
|
|
||||||
get withHope() {
|
|
||||||
return this.data.fateType === 'Hope';
|
|
||||||
}
|
|
||||||
|
|
||||||
get withFear() {
|
|
||||||
return this.data.fateType === 'Fear';
|
|
||||||
}
|
|
||||||
|
|
||||||
get totalLabel() {
|
|
||||||
const label = this.withHope ? 'DAGGERHEART.GENERAL.hope' : 'DAGGERHEART.GENERAL.fear';
|
|
||||||
|
|
||||||
return game.i18n.localize(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
static getHooks(hooks) {
|
static getHooks(hooks) {
|
||||||
return [...(hooks ?? []), 'Fate'];
|
return [...(hooks ?? []), 'Fate'];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
import { emitAsGM, GMUpdateEvent, RefreshType, socketEvent } from '../systemRegistration/socket.mjs';
|
||||||
|
|
||||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
targetHook = null;
|
targetHook = null;
|
||||||
|
|
@ -78,14 +78,25 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||||
if (this.isContentVisible) {
|
if (this.isContentVisible) {
|
||||||
if (this.type === 'dualityRoll') {
|
if (this.type === 'dualityRoll') {
|
||||||
html.classList.add('duality');
|
html.classList.add('duality');
|
||||||
if (this.system.roll.withHope) html.classList.add('hope');
|
switch (this.system.roll?.result?.duality) {
|
||||||
else if (this.system.roll.withFear) html.classList.add('fear');
|
case 1:
|
||||||
else html.classList.add('critical');
|
html.classList.add('hope');
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
html.classList.add('fear');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
html.classList.add('critical');
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (this.type === 'fateRoll') {
|
if (this.type === 'fateRoll') {
|
||||||
html.classList.add('fate');
|
html.classList.add('fate');
|
||||||
if (this.system.roll?.fateDie) {
|
if (this.system.roll?.fate.fateDie == 'Hope') {
|
||||||
html.classList.add(this.system.roll.fateDie.toLowerCase());
|
html.classList.add('hope');
|
||||||
|
}
|
||||||
|
if (this.system.roll?.fate.fateDie == 'Fear') {
|
||||||
|
html.classList.add('fear');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -240,16 +240,12 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
gap: 2px;
|
gap: 8px;
|
||||||
|
|
||||||
.trait-container {
|
.trait-container {
|
||||||
span {
|
width: 60px;
|
||||||
font-size: var(--font-size-10);
|
height: 60px;
|
||||||
}
|
|
||||||
width: 65px;
|
|
||||||
height: 65px;
|
|
||||||
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
||||||
background-size: 100%;
|
|
||||||
|
|
||||||
div {
|
div {
|
||||||
filter: drop-shadow(0 0 3px black);
|
filter: drop-shadow(0 0 3px black);
|
||||||
|
|
|
||||||
|
|
@ -20,22 +20,16 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
gap: 2px;
|
gap: 8px;
|
||||||
|
|
||||||
.trait-container {
|
.trait-container {
|
||||||
width: 65px;
|
width: 60px;
|
||||||
height: 65px;
|
height: 60px;
|
||||||
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
background: url(../assets/svg/trait-shield.svg) no-repeat;
|
||||||
background-size: 100%;
|
|
||||||
padding-top: 4px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
span {
|
|
||||||
font-size: var(--font-size-10);
|
|
||||||
}
|
|
||||||
|
|
||||||
div {
|
div {
|
||||||
filter: drop-shadow(0 0 3px black);
|
filter: drop-shadow(0 0 3px black);
|
||||||
text-shadow: 0 0 3px black;
|
text-shadow: 0 0 3px black;
|
||||||
|
|
|
||||||
|
|
@ -384,15 +384,6 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
}
|
}
|
||||||
&.has-minus:before {
|
|
||||||
content: '-';
|
|
||||||
font-size: var(--font-size-20);
|
|
||||||
grid-area: c;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 15px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,14 +53,14 @@
|
||||||
{{#if @root.advantage}}
|
{{#if @root.advantage}}
|
||||||
{{#if (eq @root.advantage 1)}}
|
{{#if (eq @root.advantage 1)}}
|
||||||
<div class="dice-option">
|
<div class="dice-option">
|
||||||
<img class="dice-icon" src="{{concat 'systems/daggerheart/assets/icons/dice/adv/d' @root.roll.advantageFaces '.svg'}}" alt="">
|
<img class="dice-icon" src="{{concat 'systems/daggerheart/assets/icons/dice/adv/' @root.roll.dAdvantage.denomination '.svg'}}" alt="">
|
||||||
<div class="dice-select">
|
<div class="dice-select">
|
||||||
<span class="label">{{localize "DAGGERHEART.GENERAL.Advantage.full"}}</span>
|
<span class="label">{{localize "DAGGERHEART.GENERAL.Advantage.full"}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{else if (eq @root.advantage -1)}}
|
{{else if (eq @root.advantage -1)}}
|
||||||
<div class="dice-option">
|
<div class="dice-option">
|
||||||
<img class="dice-icon" src="{{concat 'systems/daggerheart/assets/icons/dice/disadv/d' @root.roll.advantageFaces '.svg'}}" alt="">
|
<img class="dice-icon" src="{{concat 'systems/daggerheart/assets/icons/dice/disadv/' @root.roll.dAdvantage.denomination '.svg'}}" alt="">
|
||||||
<div class="dice-select">
|
<div class="dice-select">
|
||||||
<span class="label">{{localize "DAGGERHEART.GENERAL.Disadvantage.full"}}</span>
|
<span class="label">{{localize "DAGGERHEART.GENERAL.Disadvantage.full"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -158,7 +158,7 @@
|
||||||
{{/times}}
|
{{/times}}
|
||||||
</select>
|
</select>
|
||||||
<select name="roll.dice.advantageFaces"{{#unless advantage}} disabled{{/unless}}>
|
<select name="roll.dice.advantageFaces"{{#unless advantage}} disabled{{/unless}}>
|
||||||
{{selectOptions diceOptions selected=(concat 'd' @root.roll.advantageFaces)}}
|
{{selectOptions diceOptions selected=@root.roll.dAdvantage.denomination}}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{{#if abilities}}
|
{{#if abilities}}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
{{#each damage.parts as |part|}}
|
{{#each damage.parts as |part|}}
|
||||||
<div class="roll-dice-container">
|
<div class="roll-dice-container">
|
||||||
{{#each part.dice as |dice index|}}
|
{{#each part.dice as |dice index|}}
|
||||||
<a class="roll-dice" data-action="rerollDamageDice" data-member-key="{{../../../key}}" data-damage-key="{{@../../key}}" data-part="{{@../index}}" data-dice="{{index}}">
|
<a class="roll-dice" data-action="rerollDamageDice" data-member-key="{{@../../../key}}" data-damage-key="{{@../../key}}" data-part="{{@../index}}" data-dice="{{index}}">
|
||||||
<span class="dice-label">{{dice.total}}</span>
|
<span class="dice-label">{{dice.total}}</span>
|
||||||
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" dice.dice ".svg"}}" />
|
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" dice.dice ".svg"}}" />
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -62,30 +62,32 @@
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
{{#if roll}}
|
{{#if rollData}}
|
||||||
<div class="roll-data {{#if roll.withHope}}hope{{else if roll.withFear}}fear{{else}}critical{{/if}}">
|
{{#with rollData.options.roll}}
|
||||||
<div class="duality-label">{{roll.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=roll.totalLabel}}</div>
|
<div class="roll-data {{#if this.isCritical}}critical{{else}}{{#if (eq this.result.duality 1)}}hope{{else}}fear{{/if}}{{/if}}">
|
||||||
<div class="roll-dice-container">
|
<div class="duality-label">{{this.total}} {{localize "DAGGERHEART.GENERAL.withThing" thing=this.result.label}}</div>
|
||||||
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="hope">
|
<div class="roll-dice-container">
|
||||||
<span class="dice-label">{{roll.dHope.total}}</span>
|
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="hope">
|
||||||
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" roll.dHope.denomination ".svg"}}" />
|
<span class="dice-label">{{this.hope.value}}</span>
|
||||||
</a>
|
<img src="{{concat "systems/daggerheart/assets/icons/dice/hope/" this.hope.dice ".svg"}}" />
|
||||||
<span class="roll-operator">+</span>
|
</a>
|
||||||
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="fear">
|
<span class="roll-operator">+</span>
|
||||||
<span class="dice-label">{{roll.dFear.total}}</span>
|
<a class="roll-dice" data-action="rerollDice" data-member="{{@root.partId}}" data-dice-type="fear">
|
||||||
<img src="{{concat "systems/daggerheart/assets/icons/dice/fear/" roll.dFear.denomination ".svg"}}" />
|
<span class="dice-label">{{this.fear.value}}</span>
|
||||||
</a>
|
<img src="{{concat "systems/daggerheart/assets/icons/dice/fear/" this.fear.dice ".svg"}}" />
|
||||||
{{#if roll.advantage.type}}
|
</a>
|
||||||
<span class="roll-operator">{{#if (eq roll.advantage.type 1)}}+{{else}}-{{/if}}</span>
|
{{#if this.advantage.type}}
|
||||||
<span class="roll-dice">
|
<span class="roll-operator">{{#if (eq this.advantage.type 1)}}+{{else}}-{{/if}}</span>
|
||||||
<span class="dice-label">{{roll.advantage.value}}</span>
|
<span class="roll-dice">
|
||||||
<img src="{{concat "systems/daggerheart/assets/icons/dice/" (ifThen (eq roll.advantage.type 1) "adv/" "disadv/") roll.advantage.dice ".svg"}}" />
|
<span class="dice-label">{{this.advantage.value}}</span>
|
||||||
</span>
|
<img src="{{concat "systems/daggerheart/assets/icons/dice/" (ifThen (eq this.advantage.type 1) "adv/" "disadv/") this.advantage.dice ".svg"}}" />
|
||||||
{{/if}}
|
</span>
|
||||||
<span class="roll-operator">{{#if (gte roll.modifierTotal 0)}}+{{else}}-{{/if}}</span>
|
{{/if}}
|
||||||
<span class="roll-value">{{positive roll.modifierTotal}}</span>
|
<span class="roll-operator">{{#if (gte this.modifierTotal 0)}}+{{else}}-{{/if}}</span>
|
||||||
|
<span class="roll-value">{{positive this.modifierTotal}}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/with}}
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
|
<span class="hint">{{localize "DAGGERHEART.APPLICATIONS.TagTeamSelect.makeYourRoll"}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@
|
||||||
{{#if hintText}}
|
{{#if hintText}}
|
||||||
<div class="hint">{{localize hintText}}</div>
|
<div class="hint">{{localize hintText}}</div>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if joinedRoll.roll}}
|
{{#if joinedRoll.rollData}}
|
||||||
<div class="result-container">
|
<div class="result-container">
|
||||||
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.dualityRoll"}}</span>
|
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.dualityRoll"}}</span>
|
||||||
<div class="result-info">
|
<div class="result-info">
|
||||||
<div class="damage-info">{{joinedRoll.roll.total}}</div>
|
<div class="damage-info">{{joinedRoll.rollData.options.roll.total}}</div>
|
||||||
<div>{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.roll.totalLabel}}</div>
|
<div>{{localize "DAGGERHEART.GENERAL.withThing" thing=joinedRoll.rollData.options.roll.result.label}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if joinedRoll.rollData.options.hasDamage}}
|
{{#if hasDamage}}
|
||||||
<div class="result-container">
|
<div class="result-container">
|
||||||
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.damage"}}</span>
|
<span class="result-section-label">{{localize "DAGGERHEART.GENERAL.damage"}}</span>
|
||||||
{{#each joinedRoll.rollData.options.damage as |damage key|}}
|
{{#each joinedRoll.rollData.options.damage as |damage key|}}
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
{{#if roll.isCritical}}
|
{{#if roll.isCritical}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.criticalShort"}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.criticalShort"}}</span>
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if (and roll.dHope (not (eq roll.type "reaction")))}}
|
{{#if (and roll.result (not (eq roll.type "reaction")))}}
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.withThing" thing=roll.totalLabel}}</span>
|
<span>{{localize "DAGGERHEART.GENERAL.withThing" thing=roll.result.label}}</span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -29,48 +29,48 @@
|
||||||
<div class="dice-tooltip">
|
<div class="dice-tooltip">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="roll-dice">
|
<div class="roll-dice">
|
||||||
{{#if roll.fateDie}}
|
{{#if roll.fate}}
|
||||||
{{#if (eq roll.fateDie "Hope")}}
|
{{#if (eq roll.fate.fateDie "Hope")}}
|
||||||
<div class="roll-die">
|
<div class="roll-die">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.hope"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.hope"}}</label>
|
||||||
<div class="dice {{roll.dHope.denomination}} color-hope" data-die-index="0" data-type="hope">
|
<div class="dice {{roll.fate.dice}} color-hope" data-die-index="0" data-type="hope">
|
||||||
{{roll.dHope.total}}
|
{{roll.fate.value}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if (eq roll.fateDie "Fear")}}
|
{{#if (eq roll.fate.fateDie "Fear")}}
|
||||||
<div class="roll-die">
|
<div class="roll-die">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.fear"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.fear"}}</label>
|
||||||
<div class="dice {{roll.dFear.denomination}} color-fear" data-die-index="0" data-type="fear">
|
<div class="dice {{roll.fate.dice}} color-fear" data-die-index="0" data-type="fear">
|
||||||
{{roll.dFear.total}}
|
{{roll.fate.value}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#if roll.dHope}}
|
{{#if roll.hope}}
|
||||||
<div class="roll-die">
|
<div class="roll-die">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.hope"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.hope"}}</label>
|
||||||
<div class="dice {{roll.dHope.denomination}} color-hope reroll-button" data-die-index="0" data-type="hope" data-tooltip="{{localize "DAGGERHEART.GENERAL.rerollThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}">
|
<div class="dice {{roll.hope.dice}} color-hope reroll-button" data-die-index="0" data-type="hope" data-tooltip="{{localize "DAGGERHEART.GENERAL.rerollThing" thing=(localize "DAGGERHEART.GENERAL.hope")}}">
|
||||||
{{#if roll.dHopehope.rerolled.any}}<i class="fa-solid fa-dice dice-rerolled" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.diceIsRerolled" times=roll.dHope.rerolled.rerolls.length}}"></i>{{/if}}
|
{{#if roll.hope.rerolled.any}}<i class="fa-solid fa-dice dice-rerolled" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.diceIsRerolled" times=roll.hope.rerolled.rerolls.length}}"></i>{{/if}}
|
||||||
{{roll.dHope.total}}
|
{{roll.hope.value}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="roll-die has-plus">
|
<div class="roll-die has-plus">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.fear"}}</label>
|
<label>{{localize "DAGGERHEART.GENERAL.fear"}}</label>
|
||||||
<div class="dice {{roll.dFear.denomination}} color-fear reroll-button" data-die-index="1" data-type="fear" style="--svg-folder: 'fear';" data-tooltip="{{localize "DAGGERHEART.GENERAL.rerollThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}">
|
<div class="dice {{roll.fear.dice}} color-fear reroll-button" data-die-index="2" data-type="fear" style="--svg-folder: 'fear';" data-tooltip="{{localize "DAGGERHEART.GENERAL.rerollThing" thing=(localize "DAGGERHEART.GENERAL.fear")}}">
|
||||||
{{#if roll.dFear.rerolled.any}}<i class="fa-solid fa-dice dice-rerolled" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.diceIsRerolled" times=roll.dFear.rerolled.rerolls.length}}"></i>{{/if}}
|
{{#if roll.fear.rerolled.any}}<i class="fa-solid fa-dice dice-rerolled" data-tooltip="{{localize "DAGGERHEART.UI.Tooltip.diceIsRerolled" times=roll.fear.rerolled.rerolls.length}}"></i>{{/if}}
|
||||||
{{roll.dFear.total}}
|
{{roll.fear.value}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{#if roll.dAdvantage}}
|
{{#if roll.advantage.type}}
|
||||||
<div class="roll-die has-plus">
|
<div class="roll-die has-plus">
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.Advantage.short"}}</label>
|
{{#if (eq roll.advantage.type 1)}}
|
||||||
<div class="dice {{roll.dAdvantage.denomination}} color-adv">{{roll.dAdvantage.total}}</div>
|
<label>{{localize "DAGGERHEART.GENERAL.Advantage.short"}}</label>
|
||||||
</div>
|
<div class="dice {{roll.advantage.dice}} color-adv">{{roll.advantage.value}}</div>
|
||||||
{{else if roll.dDisadvantage}}
|
{{else}}
|
||||||
<div class="roll-die has-minus">
|
<label>{{localize "DAGGERHEART.GENERAL.Disadvantage.short"}}</label>
|
||||||
<label>{{localize "DAGGERHEART.GENERAL.Disadvantage.short"}}</label>
|
<div class="dice {{roll.advantage.dice}} color-dis">{{roll.advantage.value}}</div>
|
||||||
<div class="dice {{roll.dDisadvantage.denomination}} color-dis">{{roll.dDisadvantage.total}}</div>
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#if roll.rally.dice}}
|
{{#if roll.rally.dice}}
|
||||||
|
|
@ -79,17 +79,21 @@
|
||||||
<div class="dice {{roll.rally.dice}}">{{roll.rally.value}}</div>
|
<div class="dice {{roll.rally.dice}}">{{roll.rally.value}}</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#each roll.extraDice}}
|
{{#each roll.extra}}
|
||||||
<div class="roll-die has-plus">
|
{{#each results}}
|
||||||
<label></label>
|
{{#unless discarded}}
|
||||||
<div class="dice {{this.denomination}}">{{this.total}}</div>
|
<div class="roll-die has-plus">
|
||||||
</div>
|
<label></label>
|
||||||
|
<div class="dice {{../dice}}">{{result}}</div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
{{/each}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#each roll.dice}}
|
{{#each roll.dice}}
|
||||||
{{#each results}}
|
{{#each results}}
|
||||||
<div class="roll-die {{#unless (or @../first discarded)}} has-plus{{/unless}}">
|
<div class="roll-die {{#unless (or @../first discarded)}} has-plus{{/unless}}">
|
||||||
<div class="dice {{../denomination}}{{#if discarded}} discarded{{else}}{{#if (and @../first ../../roll.advantage.type)}}{{#if (eq ../../roll.advantage.type 1)}} color-adv{{else}} color-dis{{/if}}{{/if}}{{#if success}} color-adv{{/if}}{{/if}}">
|
<div class="dice {{../dice}}{{#if discarded}} discarded{{else}}{{#if (and @../first ../../roll.advantage.type)}}{{#if (eq ../../roll.advantage.type 1)}} color-adv{{else}} color-dis{{/if}}{{/if}}{{#if success}} color-adv{{/if}}{{/if}}">
|
||||||
{{result}}
|
{{result}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue