Roll fixes

This commit is contained in:
WBHarry 2025-06-13 10:51:43 +02:00
parent dba49a9bfb
commit 564dcf8932
13 changed files with 121 additions and 286 deletions

View file

@ -141,14 +141,14 @@ const renderDualityButton = async event => {
const config = { const config = {
event: event, event: event,
title: button.dataset.label, title: button.dataset.title,
roll: { roll: {
modifier: traitValue ? target.system.traits[traitValue].value : null, modifier: traitValue ? target.system.traits[traitValue].value : null,
label: button.dataset.label, label: button.dataset.label,
type: button.dataset.actionType ?? null // Need check type: button.dataset.actionType ?? null // Need check
}, },
chatMessage: { chatMessage: {
template: 'systems/daggerheart/templates/chat/attack-roll.hbs' template: 'systems/daggerheart/templates/chat/duality-roll.hbs'
} }
}; };
await target.diceRoll(config); await target.diceRoll(config);
@ -220,6 +220,7 @@ Hooks.on('chatMessage', (_, message) => {
} }
const traitValue = rollCommand.trait?.toLowerCase(); const traitValue = rollCommand.trait?.toLowerCase();
const advantageState = rollCommand.advantage ? true : rollCommand.disadvantage ? false : null;
// Target not required if an attribute is not used. // Target not required if an attribute is not used.
const target = traitValue ? getCommandTarget() : undefined; const target = traitValue ? getCommandTarget() : undefined;
@ -239,15 +240,11 @@ Hooks.on('chatMessage', (_, message) => {
: game.i18n.localize('DAGGERHEART.General.Duality'); : game.i18n.localize('DAGGERHEART.General.Duality');
const hopeAndFearRoll = `1${rollCommand.hope ?? 'd12'}+1${rollCommand.fear ?? 'd12'}`; const hopeAndFearRoll = `1${rollCommand.hope ?? 'd12'}+1${rollCommand.fear ?? 'd12'}`;
const advantageRoll = `${rollCommand.advantage && !rollCommand.disadvantage ? '+d6' : rollCommand.disadvantage && !rollCommand.advantage ? '-d6' : ''}`; const advantageRoll = `${advantageState === true ? '+d6' : advantageState === false ? '-d6' : ''}`;
const attributeRoll = `${trait?.value ? `${trait.value > 0 ? `+${trait.value}` : `${trait.value}`}` : ''}`; const attributeRoll = `${trait?.value ? `${trait.value > 0 ? `+${trait.value}` : `${trait.value}`}` : ''}`;
const roll = await Roll.create(`${hopeAndFearRoll}${advantageRoll}${attributeRoll}`).evaluate(); const roll = await Roll.create(`${hopeAndFearRoll}${advantageRoll}${attributeRoll}`).evaluate();
setDiceSoNiceForDualityRoll( setDiceSoNiceForDualityRoll(roll, advantageState);
roll,
rollCommand.advantage && !rollCommand.disadvantage,
rollCommand.disadvantage && !rollCommand.advantage
);
resolve({ resolve({
roll, roll,
@ -268,14 +265,8 @@ Hooks.on('chatMessage', (_, message) => {
modifiers: trait ? [trait] : [], modifiers: trait ? [trait] : [],
hope: { dice: rollCommand.hope ?? 'd12', value: roll.dice[0].total }, hope: { dice: rollCommand.hope ?? 'd12', value: roll.dice[0].total },
fear: { dice: rollCommand.fear ?? 'd12', value: roll.dice[1].total }, fear: { dice: rollCommand.fear ?? 'd12', value: roll.dice[1].total },
advantage: advantage: advantageState !== null ? { dice: 'd6', value: roll.dice[2].total } : undefined,
rollCommand.advantage && !rollCommand.disadvantage advantageState
? { dice: 'd6', value: roll.dice[2].total }
: undefined,
disadvantage:
rollCommand.disadvantage && !rollCommand.advantage
? { dice: 'd6', value: roll.dice[2].total }
: undefined
}); });
const msgData = { const msgData = {

View file

@ -3,12 +3,7 @@ import DHDualityRoll from '../data/chat-message/dualityRoll.mjs';
export default class DhpChatMessage extends foundry.documents.ChatMessage { export default class DhpChatMessage extends foundry.documents.ChatMessage {
async renderHTML() { async renderHTML() {
if ( if (this.type === 'dualityRoll' || this.type === 'adversaryRoll') {
this.type === 'dualityRoll' ||
this.type === 'adversaryRoll' ||
this.type === 'damageRoll' ||
this.type === 'abilityUse'
) {
this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system); this.content = await foundry.applications.handlebars.renderTemplate(this.content, this.system);
} }

View file

@ -16,7 +16,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
hope: ['d12'], hope: ['d12'],
fear: ['d12'], fear: ['d12'],
advantage: null, advantage: null,
// disadvantage: null,
hopeResource: hopeResource hopeResource: hopeResource
}; };
} }
@ -32,8 +31,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
actions: { actions: {
updateIsAdvantage: this.updateIsAdvantage, updateIsAdvantage: this.updateIsAdvantage,
selectExperience: this.selectExperience, selectExperience: this.selectExperience,
// setAdvantage: this.setAdvantage,
// setDisadvantage: this.setDisadvantage,
finish: this.finish finish: this.finish
}, },
form: { form: {
@ -62,7 +59,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
context.hope = this.data.hope; context.hope = this.data.hope;
context.fear = this.data.fear; context.fear = this.data.fear;
context.advantage = this.data.advantage; context.advantage = this.data.advantage;
// context.disadvantage = this.data.disadvantage;
context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] })); context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] }));
context.hopeResource = this.data.hopeResource + 1; context.hopeResource = this.data.hopeResource + 1;
@ -92,20 +88,6 @@ export default class RollSelectionDialog extends HandlebarsApplicationMixin(Appl
this.render(); this.render();
} }
/* static setAdvantage() {
this.data.advantage = this.data.advantage ? null : 'd6';
this.data.disadvantage = null;
this.render(true);
}
static setDisadvantage() {
this.data.advantage = null;
this.data.disadvantage = this.data.disadvantage ? null : 'd6';
this.render(true);
} */
static async finish() { static async finish() {
const { diceOptions, ...rest } = this.data; const { diceOptions, ...rest } = this.data;

View file

@ -1,4 +1,5 @@
import { DHActionDiceData, DHDamageData, DHDamageField } from "./actionDice.mjs"; import { abilities } from '../../config/actorConfig.mjs';
import { DHActionDiceData, DHDamageData, DHDamageField } from './actionDice.mjs';
export default class DHAction extends foundry.abstract.DataModel { export default class DHAction extends foundry.abstract.DataModel {
static defineSchema() { static defineSchema() {
@ -56,23 +57,37 @@ export class DHBaseAction extends foundry.abstract.DataModel {
_id: new fields.DocumentIdField(), _id: new fields.DocumentIdField(),
type: new fields.StringField({ initial: undefined, readonly: true, required: true }), type: new fields.StringField({ initial: undefined, readonly: true, required: true }),
name: new fields.StringField({ initial: undefined }), name: new fields.StringField({ initial: undefined }),
img: new fields.FilePathField({ initial: undefined, categories: ["IMAGE"], base64: false }), img: new fields.FilePathField({ initial: undefined, categories: ['IMAGE'], base64: false }),
actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: 'action', nullable: true }), actionType: new fields.StringField({ choices: SYSTEM.ITEM.actionTypes, initial: 'action', nullable: true }),
cost: new fields.ArrayField( cost: new fields.ArrayField(
new fields.SchemaField({ new fields.SchemaField({
type: new fields.StringField({ choices: SYSTEM.GENERAL.abilityCosts, nullable: false, required: true, initial: 'hope' }), type: new fields.StringField({
choices: SYSTEM.GENERAL.abilityCosts,
nullable: false,
required: true,
initial: 'hope'
}),
value: new fields.NumberField({ nullable: true, initial: 1 }), value: new fields.NumberField({ nullable: true, initial: 1 }),
scalable: new fields.BooleanField({ initial: false }), scalable: new fields.BooleanField({ initial: false }),
step: new fields.NumberField({ nullable: true, initial: null }), step: new fields.NumberField({ nullable: true, initial: null })
}) })
), ),
uses: new fields.SchemaField({ uses: new fields.SchemaField({
value: new fields.NumberField({ nullable: true, initial: null }), value: new fields.NumberField({ nullable: true, initial: null }),
max: new fields.NumberField({ nullable: true, initial: null }), max: new fields.NumberField({ nullable: true, initial: null }),
recovery: new fields.StringField({ choices: SYSTEM.GENERAL.refreshTypes, initial: null, nullable: true }) recovery: new fields.StringField({
choices: SYSTEM.GENERAL.refreshTypes,
initial: null,
nullable: true
})
}), }),
range: new fields.StringField({ choices: SYSTEM.GENERAL.range, required: true, blank: false, initial: "self" }) range: new fields.StringField({
} choices: SYSTEM.GENERAL.range,
required: true,
blank: false,
initial: 'self'
})
};
} }
prepareData() {} prepareData() {}
@ -100,25 +115,27 @@ export class DHBaseAction extends foundry.abstract.DataModel {
static getSourceConfig(parent) { static getSourceConfig(parent) {
const updateSource = {}; const updateSource = {};
updateSource.img ??= parent?.img ?? parent?.system?.img; updateSource.img ??= parent?.img ?? parent?.system?.img;
if(parent?.system?.trait) { if (parent?.system?.trait) {
updateSource['roll'] = { updateSource['roll'] = {
type: this.getRollType(), type: this.getRollType(),
trait: parent.system.trait trait: parent.system.trait
}; };
} }
if(parent?.system?.range) { if (parent?.system?.range) {
updateSource['range'] = parent?.system?.range; updateSource['range'] = parent?.system?.range;
} }
return updateSource; return updateSource;
} }
async use(event) { async use(event) {
if(this.roll.type && this.roll.trait) { if (this.roll.type && this.roll.trait) {
const modifierValue = this.actor.system.traits[this.roll.trait].value;
const config = { const config = {
event: event, event: event,
title: this.item.name, title: this.item.name,
roll: { roll: {
modifier: this.actor.system.traits[this.roll.trait].value, modifier: modifierValue,
label: game.i18n.localize(abilities[this.roll.trait].label),
type: this.actionType, type: this.actionType,
difficulty: this.roll?.difficulty difficulty: this.roll?.difficulty
}, },
@ -126,14 +143,14 @@ export class DHBaseAction extends foundry.abstract.DataModel {
template: this.chatTemplate template: this.chatTemplate
} }
}; };
if(this.target?.type) config.checkTarget = true; if (this.target?.type) config.checkTarget = true;
if(this.damage.parts.length) { if (this.damage.parts.length) {
config.damage = { config.damage = {
value: this.damage.parts.map(p => p.getFormula(this.actor)).join(' + '), value: this.damage.parts.map(p => p.getFormula(this.actor)).join(' + '),
type: this.damage.parts[0].type type: this.damage.parts[0].type
}; };
} }
if(this.effects.length) { if (this.effects.length) {
// Apply Active Effects. In Chat Message ? // Apply Active Effects. In Chat Message ?
} }
return this.actor.diceRoll(config); return this.actor.diceRoll(config);
@ -143,7 +160,7 @@ export class DHBaseAction extends foundry.abstract.DataModel {
const extraDefineSchema = (field, option) => { const extraDefineSchema = (field, option) => {
return { return {
[field] : { [field]: {
// damage: new fields.SchemaField({ // damage: new fields.SchemaField({
// parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData)) // parts: new fields.ArrayField(new fields.EmbeddedDataField(DHDamageData))
// }), // }),
@ -154,16 +171,19 @@ const extraDefineSchema = (field, option) => {
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }) difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 })
}), }),
target: new fields.SchemaField({ target: new fields.SchemaField({
type: new fields.StringField({ choices: SYSTEM.ACTIONS.targetTypes, initial: SYSTEM.ACTIONS.targetTypes.other.id }) type: new fields.StringField({
choices: SYSTEM.ACTIONS.targetTypes,
initial: SYSTEM.ACTIONS.targetTypes.other.id
})
}), }),
effects: new fields.ArrayField( // ActiveEffect effects: new fields.ArrayField( // ActiveEffect
new fields.SchemaField({ new fields.SchemaField({
'_id': new fields.DocumentIdField() _id: new fields.DocumentIdField()
}) })
) )
}[field] }[field]
}; };
} };
export class DHAttackAction extends DHBaseAction { export class DHAttackAction extends DHBaseAction {
static defineSchema() { static defineSchema() {
@ -173,7 +193,7 @@ export class DHAttackAction extends DHBaseAction {
...extraDefineSchema('roll'), ...extraDefineSchema('roll'),
...extraDefineSchema('target'), ...extraDefineSchema('target'),
...extraDefineSchema('effects') ...extraDefineSchema('effects')
} };
} }
static getRollType() { static getRollType() {
@ -182,7 +202,7 @@ export class DHAttackAction extends DHBaseAction {
prepareData() { prepareData() {
super.prepareData(); super.prepareData();
if ( this.damage.includeBase && !!this.item?.system?.damage ) { if (this.damage.includeBase && !!this.item?.system?.damage) {
const baseDamage = this.getParentDamage(); const baseDamage = this.getParentDamage();
this.damage.parts.unshift(new DHDamageData(baseDamage)); this.damage.parts.unshift(new DHDamageData(baseDamage));
} }
@ -212,7 +232,7 @@ export class DHSpellCastAction extends DHBaseAction {
...extraDefineSchema('roll'), ...extraDefineSchema('roll'),
...extraDefineSchema('target'), ...extraDefineSchema('target'),
...extraDefineSchema('effects') ...extraDefineSchema('effects')
} };
} }
static getRollType() { static getRollType() {
@ -227,12 +247,12 @@ export class DHDamageAction extends DHBaseAction {
...extraDefineSchema('damage', false), ...extraDefineSchema('damage', false),
...extraDefineSchema('target'), ...extraDefineSchema('target'),
...extraDefineSchema('effects') ...extraDefineSchema('effects')
} };
} }
async use(event) { async use(event) {
const formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + '); const formula = this.damage.parts.map(p => p.getFormula(this.actor)).join(' + ');
if(!formula || formula == '') return; if (!formula || formula == '') return;
let roll = { formula: formula, total: formula }; let roll = { formula: formula, total: formula };
if (isNaN(formula)) { if (isNaN(formula)) {
@ -261,17 +281,23 @@ export class DHHealingAction extends DHBaseAction {
return { return {
...super.defineSchema(), ...super.defineSchema(),
healing: new fields.SchemaField({ healing: new fields.SchemaField({
type: new fields.StringField({ choices: SYSTEM.GENERAL.healingTypes, required: true, blank: false, initial: SYSTEM.GENERAL.healingTypes.health.id, label: "Healing" }), type: new fields.StringField({
choices: SYSTEM.GENERAL.healingTypes,
required: true,
blank: false,
initial: SYSTEM.GENERAL.healingTypes.health.id,
label: 'Healing'
}),
value: new fields.EmbeddedDataField(DHActionDiceData) value: new fields.EmbeddedDataField(DHActionDiceData)
}), }),
...extraDefineSchema('target'), ...extraDefineSchema('target'),
...extraDefineSchema('effects') ...extraDefineSchema('effects')
} };
} }
async use(event) { async use(event) {
const formula = this.healing.value.getFormula(this.actor); const formula = this.healing.value.getFormula(this.actor);
if(!formula || formula == '') return; if (!formula || formula == '') return;
// const roll = await super.use(event); // const roll = await super.use(event);
let roll = { formula: formula, total: formula }; let roll = { formula: formula, total: formula };
@ -308,10 +334,10 @@ export class DHResourceAction extends DHBaseAction {
...extraDefineSchema('target'), ...extraDefineSchema('target'),
...extraDefineSchema('effects'), ...extraDefineSchema('effects'),
resource: new fields.SchemaField({ resource: new fields.SchemaField({
type: new fields.StringField({ choices: [], initial: "", label: "Resource" }), type: new fields.StringField({ choices: [], initial: '', label: 'Resource' }),
value: new fields.NumberField({ initial: 0, label: "Value" }) value: new fields.NumberField({ initial: 0, label: 'Value' })
}) })
} };
} }
} }
@ -319,8 +345,8 @@ export class DHSummonAction extends DHBaseAction {
static defineSchema() { static defineSchema() {
return { return {
...super.defineSchema(), ...super.defineSchema(),
documentUUID: new fields.StringField({ blank: true, initial: "", placeholder:'Enter a Creature UUID' }) documentUUID: new fields.StringField({ blank: true, initial: '', placeholder: 'Enter a Creature UUID' })
} };
} }
} }
@ -329,7 +355,7 @@ export class DHEffectAction extends DHBaseAction {
return { return {
...super.defineSchema(), ...super.defineSchema(),
...extraDefineSchema('effects') ...extraDefineSchema('effects')
} };
} }
} }
@ -337,19 +363,18 @@ export class DHMacroAction extends DHBaseAction {
static defineSchema() { static defineSchema() {
return { return {
...super.defineSchema(), ...super.defineSchema(),
documentUUID: new fields.StringField({ blank: true, initial: "", placeholder:'Enter a macro UUID' }) documentUUID: new fields.StringField({ blank: true, initial: '', placeholder: 'Enter a macro UUID' })
} };
} }
async use(event) { async use(event) {
const fixUUID = !this.documentUUID.includes('Macro.') ? `Macro.${this.documentUUID}` : this.documentUUID, const fixUUID = !this.documentUUID.includes('Macro.') ? `Macro.${this.documentUUID}` : this.documentUUID,
macro = await fromUuid(fixUUID); macro = await fromUuid(fixUUID);
try { try {
if(!macro) throw new Error(`No macro found for the UUID: ${this.documentUUID}.`); if (!macro) throw new Error(`No macro found for the UUID: ${this.documentUUID}.`);
macro.execute(); macro.execute();
} catch (error) { } catch (error) {
ui.notifications.error(error); ui.notifications.error(error);
} }
} }
} }

View file

@ -9,7 +9,13 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
total: new fields.NumberField({ required: true, integer: true }), total: new fields.NumberField({ required: true, integer: true }),
type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false }) type: new fields.StringField({ choices: Object.keys(SYSTEM.GENERAL.damageTypes), integer: false })
}), }),
dice: new fields.ArrayField(new fields.EmbeddedDataField(DhpDamageDice)), dice: new fields.ArrayField(
new fields.SchemaField({
type: new fields.StringField({ required: true }),
rolls: new fields.ArrayField(new fields.NumberField({ required: true, integer: true })),
total: new fields.NumberField({ integer: true })
})
),
modifiers: new fields.ArrayField( modifiers: new fields.ArrayField(
new fields.SchemaField({ new fields.SchemaField({
value: new fields.NumberField({ required: true, integer: true }), value: new fields.NumberField({ required: true, integer: true }),
@ -26,18 +32,3 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
}; };
} }
} }
class DhpDamageDice extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
type: new fields.StringField({ required: true }),
rolls: new fields.ArrayField(new fields.NumberField({ required: true, integer: true }))
};
}
get rollTotal() {
return this.rolls.reduce((acc, roll) => acc + roll, 0);
}
}

View file

@ -28,10 +28,8 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
), ),
hope: diceField(), hope: diceField(),
fear: diceField(), fear: diceField(),
advantageState: new fields.NumberField({ integer: true }), advantageState: new fields.BooleanField({ nullable: true, initial: null }),
advantage: diceField(), advantage: diceField(),
// advantage: diceField(),
// disadvantage: diceField(),
targets: new fields.ArrayField( targets: new fields.ArrayField(
new fields.SchemaField({ new fields.SchemaField({
id: new fields.StringField({}), id: new fields.StringField({}),
@ -66,16 +64,6 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
}; };
} }
get total() {
// const advantage = this.advantage.value
// ? this.advantage.value
// : this.disadvantage.value
// ? -this.disadvantage.value
// : 0;
// return this.diceTotal + advantage + this.modifierTotal.value;
return this.roll.total;
}
get diceTotal() { get diceTotal() {
return this.hope.value + this.fear.value; return this.hope.value + this.fear.value;
} }
@ -115,7 +103,7 @@ export default class DHDualityRoll extends foundry.abstract.TypeDataModel {
} }
prepareDerivedData() { prepareDerivedData() {
const total = this.total; const total = this.roll.total;
this.hope.discarded = this.hope.value < this.fear.value; this.hope.discarded = this.hope.value < this.fear.value;
this.fear.discarded = this.fear.value < this.hope.value; this.fear.discarded = this.fear.value < this.hope.value;

View file

@ -165,8 +165,6 @@ export default class DhpActor extends Actor {
}); });
rollConfig = await dialogClosed; rollConfig = await dialogClosed;
// advantageDice = result.advantage;
// disadvantageDice = result.disadvantage;
advantage = rollConfig.advantage; advantage = rollConfig.advantage;
hopeDice = rollConfig.hope; hopeDice = rollConfig.hope;
fearDice = rollConfig.fear; fearDice = rollConfig.fear;
@ -199,7 +197,7 @@ export default class DhpActor extends Actor {
const roll = await Roll.create(formula).evaluate(); const roll = await Roll.create(formula).evaluate();
if (this.type === 'character') { if (this.type === 'character') {
setDiceSoNiceForDualityRoll(roll, advantageDice, disadvantageDice); setDiceSoNiceForDualityRoll(roll, advantage);
hope = roll.dice[0].results[0].result; hope = roll.dice[0].results[0].result;
fear = roll.dice[1].results[0].result; fear = roll.dice[1].results[0].result;
if ( if (
@ -249,8 +247,6 @@ export default class DhpActor extends Actor {
configRoll.hope = { dice: hopeDice, value: hope }; configRoll.hope = { dice: hopeDice, value: hope };
configRoll.fear = { dice: fearDice, value: fear }; configRoll.fear = { dice: fearDice, value: fear };
configRoll.advantage = { dice: advantageDice, value: roll.dice[2]?.results[0].result ?? null }; configRoll.advantage = { dice: advantageDice, value: roll.dice[2]?.results[0].result ?? null };
/* advantage: { dice: advantageDice, value: advantage },
disadvantage: { dice: disadvantageDice, value: disadvantage } */
} }
if (damage) configRoll.damage = damage; if (damage) configRoll.damage = damage;
if (targets) configRoll.targets = targets; if (targets) configRoll.targets = targets;
@ -283,151 +279,6 @@ export default class DhpActor extends Actor {
: []; : [];
} }
// Delete when new roll logic test done
/* async diceRollOld(modifier, shiftKey) {
if (this.type === 'character') {
return await this.dualityRoll(modifier, shiftKey);
} else {
return await this.npcRoll(modifier, shiftKey);
}
}
async npcRoll(modifier, shiftKey) {
let advantage = null;
const modifiers = [
{
value: Number.parseInt(modifier.value),
label: modifier.value >= 0 ? `+${modifier.value}` : `-${modifier.value}`,
title: modifier.title
}
];
if (!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new NpcRollSelectionDialog(this.system.experiences, resolve).render(true);
});
const result = await dialogClosed;
advantage = result.advantage;
result.experiences.forEach(x =>
modifiers.push({
value: x.value,
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
title: x.description
})
);
}
const roll = Roll.create(
`${advantage === true || advantage === false ? 2 : 1}d20${advantage === true ? 'kh' : advantage === false ? 'kl' : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
);
let rollResult = await roll.evaluate();
const dice = [];
for (var i = 0; i < rollResult.terms.length; i++) {
const term = rollResult.terms[i];
if (term.faces) {
dice.push({ type: `d${term.faces}`, rolls: term.results.map(x => ({ value: x.result })) });
}
}
// There is Only ever one dice term here
return { roll, dice: dice[0], modifiers, advantageState: advantage === true ? 1 : advantage === false ? 2 : 0 };
}
async dualityRoll(modifier, shiftKey) {
let hopeDice = 'd12',
fearDice = 'd12',
advantageDice = null,
disadvantageDice = null;
const modifiers =
modifier.value !== null
? [
{
value: modifier.value ? Number.parseInt(modifier.value) : 0,
label:
modifier.value >= 0
? `${modifier.title} +${modifier.value}`
: `${modifier.title} ${modifier.value}`,
title: modifier.title
}
]
: [];
if (!shiftKey) {
const dialogClosed = new Promise((resolve, _) => {
new RollSelectionDialog(this.system.experiences, this.system.resources.hope.value, resolve).render(
true
);
});
const result = await dialogClosed;
(hopeDice = result.hope),
(fearDice = result.fear),
(advantageDice = result.advantage),
(disadvantageDice = result.disadvantage);
result.experiences.forEach(x =>
modifiers.push({
value: x.value,
label: x.value >= 0 ? `+${x.value}` : `-${x.value}`,
title: x.description
})
);
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
if (automateHope && result.hopeUsed) {
await this.update({
'system.resources.hope.value': this.system.resources.hope.value - result.hopeUsed
});
}
}
const roll = new Roll(
`1${hopeDice} + 1${fearDice}${advantageDice ? ` + 1${advantageDice}` : disadvantageDice ? ` - 1${disadvantageDice}` : ''} ${modifiers.map(x => `+ ${x.value}`).join(' ')}`
);
let rollResult = await roll.evaluate();
setDiceSoNiceForDualityRoll(rollResult, advantageDice, disadvantageDice);
const hope = rollResult.dice[0].results[0].result;
const fear = rollResult.dice[1].results[0].result;
const advantage = advantageDice ? rollResult.dice[2].results[0].result : null;
const disadvantage = disadvantageDice ? rollResult.dice[2].results[0].result : null;
if (disadvantage) {
rollResult = { ...rollResult, total: rollResult.total - Math.max(hope, disadvantage) };
}
if (advantage) {
rollResult = { ...rollResult, total: 'Select Hope Die' };
}
const automateHope = await game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope);
if (automateHope && hope > fear) {
await this.update({
'system.resources.hope.value': Math.min(
this.system.resources.hope.value + 1,
this.system.resources.hope.max
)
});
}
if (automateHope && hope === fear) {
await this.update({
'system.resources': {
'hope.value': Math.min(this.system.resources.hope.value + 1, this.system.resources.hope.max),
'stress.value': Math.max(this.system.resources.stress.value - 1, 0)
}
});
}
return {
roll,
rollResult,
hope: { dice: hopeDice, value: hope },
fear: { dice: fearDice, value: fear },
advantage: { dice: advantageDice, value: advantage },
disadvantage: { dice: disadvantageDice, value: disadvantage },
modifiers: modifiers
};
} */
async damageRoll(title, damage, targets, shiftKey) { async damageRoll(title, damage, targets, shiftKey) {
let rollString = damage.value; let rollString = damage.value;
let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? []; let bonusDamage = damage.bonusDamage?.filter(x => x.initiallySelected) ?? [];
@ -455,7 +306,11 @@ export default class DhpActor extends Actor {
for (var i = 0; i < rollResult.terms.length; i++) { for (var i = 0; i < rollResult.terms.length; i++) {
const term = rollResult.terms[i]; const term = rollResult.terms[i];
if (term.faces) { if (term.faces) {
dice.push({ type: `d${term.faces}`, rolls: term.results.map(x => x.result) }); dice.push({
type: `d${term.faces}`,
rolls: term.results.map(x => x.result),
total: term.results.reduce((acc, x) => acc + x.result, 0)
});
} else if (term.operator) { } else if (term.operator) {
} else if (term.number) { } else if (term.number) {
const operator = i === 0 ? '' : rollResult.terms[i - 1].operator; const operator = i === 0 ? '' : rollResult.terms[i - 1].operator;

View file

@ -15,12 +15,17 @@ export function getDualityMessage(roll) {
check: game.i18n.localize(abilities[roll.trait].label) check: game.i18n.localize(abilities[roll.trait].label)
}) })
: null; : null;
const label = traitLabel ?? game.i18n.localize('DAGGERHEART.General.Duality'); const label = traitLabel ?? game.i18n.localize('DAGGERHEART.General.Duality');
const dataLabel = traitLabel
? game.i18n.localize(abilities[roll.trait].label)
: game.i18n.localize('DAGGERHEART.General.Duality');
const dualityElement = document.createElement('span'); const dualityElement = document.createElement('span');
dualityElement.innerHTML = ` dualityElement.innerHTML = `
<button class="duality-roll-button" <button class="duality-roll-button"
data-label="${label}" data-title="${label}"
data-label="${dataLabel}"
data-hope="${roll.hope ?? 'd12'}" data-hope="${roll.hope ?? 'd12'}"
data-fear="${roll.fear ?? 'd12'}" data-fear="${roll.fear ?? 'd12'}"
${roll.trait && abilities[roll.trait] ? `data-trait="${roll.trait}"` : ''} ${roll.trait && abilities[roll.trait] ? `data-trait="${roll.trait}"` : ''}

View file

@ -122,14 +122,14 @@ export const getCommandTarget = () => {
return target; return target;
}; };
export const setDiceSoNiceForDualityRoll = (rollResult, advantage, disadvantage) => { export const setDiceSoNiceForDualityRoll = (rollResult, advantageState) => {
const diceSoNicePresets = getDiceSoNicePresets(); const diceSoNicePresets = getDiceSoNicePresets();
rollResult.dice[0].options.appearance = diceSoNicePresets.hope; rollResult.dice[0].options.appearance = diceSoNicePresets.hope;
rollResult.dice[1].options.appearance = diceSoNicePresets.fear; rollResult.dice[1].options.appearance = diceSoNicePresets.fear;
if(rollResult.dice[2]) { if (rollResult.dice[2]) {
if (advantage) { if (advantageState === true) {
rollResult.dice[2].options.appearance = diceSoNicePresets.advantage; rollResult.dice[2].options.appearance = diceSoNicePresets.advantage;
} else if (disadvantage) { } else if (advantageState === false) {
rollResult.dice[2].options.appearance = diceSoNicePresets.disadvantage; rollResult.dice[2].options.appearance = diceSoNicePresets.disadvantage;
} }
} }
@ -227,8 +227,11 @@ export const getDeleteKeys = (property, innerProperty, innerPropertyDefaultValue
// Fix on Foundry native formula replacement for DH // Fix on Foundry native formula replacement for DH
const nativeReplaceFormulaData = Roll.replaceFormulaData; const nativeReplaceFormulaData = Roll.replaceFormulaData;
Roll.replaceFormulaData = function(formula, data, {missing, warn=false}={}) { Roll.replaceFormulaData = function (formula, data, { missing, warn = false } = {}) {
const terms = [{term: 'prof', default: 1}, {term: 'cast', default: 1}]; const terms = [
formula = terms.reduce((a,c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula); { term: 'prof', default: 1 },
return nativeReplaceFormulaData(formula, data, {missing, warn}); { term: 'cast', default: 1 }
} ];
formula = terms.reduce((a, c) => a.replaceAll(`@${c.term}`, data[c.term] ?? c.default), formula);
return nativeReplaceFormulaData(formula, data, { missing, warn });
};

View file

@ -10,12 +10,12 @@
{{label}} {{label}}
</div> </div>
{{/each}} {{/each}}
{{#if (eq advantageState 1)}} {{#if advantageState}}
<div class="duality-modifier"> <div class="duality-modifier">
{{localize "DAGGERHEART.General.Advantage.Full"}} {{localize "DAGGERHEART.General.Advantage.Full"}}
</div> </div>
{{/if}} {{/if}}
{{#if (eq advantageState 2)}} {{#if (eq advantageState false)}}
<div class="duality-modifier"> <div class="duality-modifier">
{{localize "DAGGERHEART.General.Disadvantage.Full"}} {{localize "DAGGERHEART.General.Disadvantage.Full"}}
</div> </div>
@ -41,7 +41,7 @@
<div class="dice-value">{{fear.value}}</div> <div class="dice-value">{{fear.value}}</div>
</div> </div>
</div> </div>
{{#if (eq advantageState 1)}} {{#if advantageState}}
<div class="advantage-container advantage"> <div class="advantage-container advantage">
<div class="dice-wrapper"> <div class="dice-wrapper">
<img class="dice" src="../icons/svg/d6-grey.svg"/> <img class="dice" src="../icons/svg/d6-grey.svg"/>
@ -49,7 +49,7 @@
</div> </div>
</div> </div>
{{/if}} {{/if}}
{{#if (eq advantageState 2)}} {{#if (eq advantageState false)}}
<div class="advantage-container disadvantage"> <div class="advantage-container disadvantage">
<div class="dice-wrapper"> <div class="dice-wrapper">
<img class="dice" src="../icons/svg/d6-grey.svg"/> <img class="dice" src="../icons/svg/d6-grey.svg"/>
@ -61,7 +61,7 @@
</div> </div>
{{#if (not damage.value)}} {{#if (not damage.value)}}
<div class="duality-result"> <div class="duality-result">
<div>{{total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div> <div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
</div> </div>
{{/if}} {{/if}}
</div> </div>
@ -80,9 +80,9 @@
{{/if}} {{/if}}
{{#if damage.value}} {{#if damage.value}}
<div class="duality-actions"> <div class="duality-actions">
<button class="duality-action" data-value="{{total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>Roll Damage</span></button> <button class="duality-action" data-value="{{roll.total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>Roll Damage</span></button>
<div class="duality-result"> <div class="duality-result">
<div>{{total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div> <div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -148,7 +148,7 @@
<div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}"> <div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}">
<div class="dice-total-label">{{totalLabel}}</div> <div class="dice-total-label">{{totalLabel}}</div>
<div class="dice-total-value"> <div class="dice-total-value">
{{total}} {{roll.total}}
</div> </div>
</div> </div>
{{#if (gt targets.length 0)}} {{#if (gt targets.length 0)}}
@ -164,7 +164,7 @@
</div> </div>
{{/if}} {{/if}}
<div class="dice-actions"> <div class="dice-actions">
<button class="duality-action" data-value="{{total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>{{localize "DAGGERHEART.Chat.AttackRoll.RollDamage"}}</span></button> <button class="duality-action" data-value="{{roll.total}}" data-damage="{{damage.value}}" data-damage-type="{{damage.type}}" {{#if damage.disabled}}disabled{{/if}}><span>{{localize "DAGGERHEART.Chat.AttackRoll.RollDamage"}}</span></button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -11,7 +11,7 @@
<header class="part-header flexrow"> <header class="part-header flexrow">
<span class="part-formula">{{rolls.length}}{{type}}</span> <span class="part-formula">{{rolls.length}}{{type}}</span>
<span class="part-total">{{rollTotal}}</span> <span class="part-total">{{this.total}}</span>
</header> </header>
<ol class="dice-rolls"> <ol class="dice-rolls">
{{#each rolls}} {{#each rolls}}
@ -23,7 +23,7 @@
</section> </section>
</div> </div>
</div> </div>
<div class="dice-total">{{total}}</div> <div class="dice-total">{{damage.total}}</div>
<div class="dice-actions"> <div class="dice-actions">
<button class="damage-button" data-target-hit="true" {{#if (eq targets.length 0)}}disabled{{/if}}>{{localize "DAGGERHEART.Chat.DamageRoll.DealDamageToTargets"}}</button> <button class="damage-button" data-target-hit="true" {{#if (eq targets.length 0)}}disabled{{/if}}>{{localize "DAGGERHEART.Chat.DamageRoll.DealDamageToTargets"}}</button>
<button class="damage-button">{{localize "DAGGERHEART.Chat.DamageRoll.DealDamage"}}</button> <button class="damage-button">{{localize "DAGGERHEART.Chat.DamageRoll.DealDamage"}}</button>

View file

@ -10,12 +10,12 @@
{{label}} {{label}}
</div> </div>
{{/each}} {{/each}}
{{#if (eq advantageState 1)}} {{#if advantageState}}
<div class="duality-modifier"> <div class="duality-modifier">
{{localize "DAGGERHEART.General.Advantage.Full"}} {{localize "DAGGERHEART.General.Advantage.Full"}}
</div> </div>
{{/if}} {{/if}}
{{#if (eq advantageState 2)}} {{#if (eq advantageState false)}}
<div class="duality-modifier"> <div class="duality-modifier">
{{localize "DAGGERHEART.General.Disadvantage.Full"}} {{localize "DAGGERHEART.General.Disadvantage.Full"}}
</div> </div>
@ -41,7 +41,7 @@
<div class="dice-value">{{fear.value}}</div> <div class="dice-value">{{fear.value}}</div>
</div> </div>
</div> </div>
{{#if (eq advantageState 1)}} {{#if advantageState}}
<div class="advantage-container advantage"> <div class="advantage-container advantage">
<div class="dice-wrapper"> <div class="dice-wrapper">
<img class="dice" src="../icons/svg/d6-grey.svg"/> <img class="dice" src="../icons/svg/d6-grey.svg"/>
@ -49,7 +49,7 @@
</div> </div>
</div> </div>
{{/if}} {{/if}}
{{#if (eq advantageState 2)}} {{#if (eq advantageState false)}}
<div class="advantage-container disadvantage"> <div class="advantage-container disadvantage">
<div class="dice-wrapper"> <div class="dice-wrapper">
<img class="dice" src="../icons/svg/d6-grey.svg"/> <img class="dice" src="../icons/svg/d6-grey.svg"/>
@ -61,7 +61,7 @@
</div> </div>
{{#if (not damage.value)}} {{#if (not damage.value)}}
<div class="duality-result"> <div class="duality-result">
<div>{{total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div> <div>{{roll.total}} {{#if (eq dualityResult 1)}}With Hope{{else}}{{#if (eq dualityResult 2)}}With Fear{{else}}Critical Success{{/if}}{{/if}}</div>
</div> </div>
{{/if}} {{/if}}
</div> </div>
@ -135,7 +135,7 @@
<div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}"> <div class="dice-total duality {{#if fear.discarded}}hope{{else}}{{#if hope.discarded}}fear{{else}}critical{{/if}}{{/if}}">
<div class="dice-total-label">{{totalLabel}}</div> <div class="dice-total-label">{{totalLabel}}</div>
<div class="dice-total-value"> <div class="dice-total-value">
{{total}} {{roll.total}}
</div> </div>
</div> </div>
</div> </div>

View file

@ -13,7 +13,7 @@
</div> </div>
<div class="flexrow"> <div class="flexrow">
<button class="disadvantage flex1 {{#if this.advantage}}selected{{/if}}" data-action="updateIsAdvantage" data-advantage="true">{{localize "DAGGERHEART.General.Advantage.Full"}}</button> <button class="disadvantage flex1 {{#if this.advantage}}selected{{/if}}" data-action="updateIsAdvantage" data-advantage="true">{{localize "DAGGERHEART.General.Advantage.Full"}}</button>
<button class="disadvantage flex1 {{#if this.disadvantage}}selected{{/if}}" data-action="updateIsAdvantage">{{localize "DAGGERHEART.General.Disadvantage.Full"}}</button> <button class="disadvantage flex1 {{#if (eq this.advantage false)}}selected{{/if}}" data-action="updateIsAdvantage">{{localize "DAGGERHEART.General.Disadvantage.Full"}}</button>
</div> </div>
{{#if (not this.isNpc)}} {{#if (not this.isNpc)}}
<div class="form-group"> <div class="form-group">