Compare commits

..

No commits in common. "89ba2409983a3e16d5b298dc5fee918011c5301d" and "cec0bb75aea6e1e1ee0f7ca640b3fd655ea5495b" have entirely different histories.

10 changed files with 64 additions and 87 deletions

View file

@ -311,7 +311,7 @@ Hooks.on('chatMessage', (_, message) => {
target, target,
difficulty, difficulty,
title, title,
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll'), label: 'test',
actionType: null, actionType: null,
advantage advantage
}); });

View file

@ -2135,7 +2135,6 @@
"dropActorsHere": "Drop Actors here", "dropActorsHere": "Drop Actors here",
"dropFeaturesHere": "Drop Features here", "dropFeaturesHere": "Drop Features here",
"duality": "Duality", "duality": "Duality",
"dualityDice": "Duality Dice",
"dualityRoll": "Duality Roll", "dualityRoll": "Duality Roll",
"enabled": "Enabled", "enabled": "Enabled",
"evasion": "Evasion", "evasion": "Evasion",

View file

@ -44,13 +44,11 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
const target = this.actor.uuid; const target = this.actor.uuid;
const config = await enrichedFateRoll({ const config = await enrichedFateRoll({
target, target,
title: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.avoidDeath.name'), title: 'Avoid Death Hope Fate Roll',
label: `${game.i18n.localize('DAGGERHEART.GENERAL.hope')} ${game.i18n.localize('DAGGERHEART.GENERAL.fateRoll')}`, label: 'test',
fateType: 'Hope' fateType: 'Hope'
}); });
if (!config.roll.fate) return;
if (config.roll.fate.value <= this.actor.system.levelData.level.current) { if (config.roll.fate.value <= this.actor.system.levelData.level.current) {
// apply scarring - for now directly apply - later add a button. // apply scarring - for now directly apply - later add a button.
const newScarAmount = this.actor.system.scars + 1; const newScarAmount = this.actor.system.scars + 1;
@ -71,30 +69,36 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.avoidScar'); return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.avoidScar');
} }
async clearAllStressAndHitpoints() {
await this.actor.update({
system: {
resources: {
hitPoints: {
value: 0
},
stress: {
value: 0
}
}
}
});
}
async handleRiskItAll() { async handleRiskItAll() {
const config = await enrichedDualityRoll({ const config = await enrichedDualityRoll({
reaction: true, reaction: true,
traitValue: null, traitValue: null,
target: this.actor, target: null,
difficulty: null, difficulty: null,
title: game.i18n.localize('DAGGERHEART.CONFIG.DeathMoves.riskItAll.name'), title: 'Risk It All',
label: game.i18n.localize('DAGGERHEART.GENERAL.dualityDice'), label: 'test',
actionType: null, actionType: null,
advantage: null, advantage: null
customConfig: { skips: { resources: true } }
}); });
if (!config.roll.result) return;
const clearAllStressAndHitpointsUpdates = [
{ key: 'hitPoints', clear: true },
{ key: 'stress', clear: true }
];
let chatMessage = '';
if (config.roll.isCritical) { if (config.roll.isCritical) {
config.resourceUpdates.addResources(clearAllStressAndHitpointsUpdates); this.clearAllStressAndHitpoints();
chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllCritical'); return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllCritical');
} }
if (config.roll.result.duality == 1) { if (config.roll.result.duality == 1) {
@ -104,18 +108,15 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
config.roll.hope.value >= config.roll.hope.value >=
this.actor.system.resources.hitPoints.value + this.actor.system.resources.stress.value this.actor.system.resources.hitPoints.value + this.actor.system.resources.stress.value
) { ) {
config.resourceUpdates.addResources(clearAllStressAndHitpointsUpdates); this.clearAllStressAndHitpoints();
chatMessage = 'Hope roll value is more than the marked Stress and Hit Points, clearing both.'; return 'Hope roll value is more than the marked Stress and Hit Points, clearing both.';
} }
chatMessage = 'TODO - need to clear Stress and/or Hit Points up to: ' + config.roll.hope.value; return 'TODO - need to clear Stress and/or Hit Points up to: ' + config.roll.hope.value;
} }
if (config.roll.result.duality == -1) { if (config.roll.result.duality == -1) {
chatMessage = game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllFailure'); return game.i18n.localize('DAGGERHEART.UI.Chat.deathMove.riskItAllFailure');
} }
await config.resourceUpdates.updateResources();
return chatMessage;
} }
async handleBlazeOfGlory() { async handleBlazeOfGlory() {
@ -161,8 +162,6 @@ export default class DhDeathMove extends HandlebarsApplicationMixin(ApplicationV
result = await this.handleRiskItAll(); result = await this.handleRiskItAll();
} }
if (!result) return;
const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance) const autoExpandDescription = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance)
.expandRollMessage?.desc; .expandRollMessage?.desc;
const cls = getDocumentClass('ChatMessage'); const cls = getDocumentClass('ChatMessage');

View file

@ -364,14 +364,14 @@ export class ResourceUpdateMap extends Map {
if (!resource.key) continue; if (!resource.key) continue;
const existing = this.get(resource.key); const existing = this.get(resource.key);
if (!existing || resource.clear) { if (existing) {
this.set(resource.key, resource);
} else if (!existing?.clear) {
this.set(resource.key, { this.set(resource.key, {
...existing, ...existing,
value: existing.value + (resource.value ?? 0), value: existing.value + (resource.value ?? 0),
total: existing.total + (resource.total ?? 0) total: existing.total + (resource.total ?? 0)
}); });
} else {
this.set(resource.key, resource);
} }
} }
} }

View file

@ -87,7 +87,7 @@ export class DHActionRollData extends foundry.abstract.DataModel {
if (this.type === CONFIG.DH.GENERAL.rollTypes.attack.id) if (this.type === CONFIG.DH.GENERAL.rollTypes.attack.id)
modifiers.push({ modifiers.push({
label: 'Bonus to Hit', label: 'Bonus to Hit',
value: this.bonus ?? this.parent.actor.system.attack.roll.bonus ?? 0 value: this.bonus ?? this.parent.actor.system.attack.roll.bonus
}); });
break; break;
default: default:

View file

@ -35,9 +35,7 @@ export default class D20Roll extends DHRoll {
get isCritical() { get isCritical() {
if (!this.d20._evaluated) return; if (!this.d20._evaluated) return;
return this.d20.total >= this.data.system.criticalThreshold;
const criticalThreshold = this.options.actionType === 'reaction' ? 20 : this.data.system.criticalThreshold;
return this.d20.total >= criticalThreshold;
} }
get hasAdvantage() { get hasAdvantage() {

View file

@ -133,13 +133,11 @@ export default class DualityRoll extends D20Roll {
return; return;
} }
this.terms[0] = new foundry.dice.terms.Die({ const { defaultHopeDice, defaultFearDice } = this.data.rules.dualityRoll;
faces: this.data.rules.dualityRoll?.defaultHopeDice ?? 12
}); this.terms[0] = new foundry.dice.terms.Die({ faces: defaultHopeDice });
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' }); this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
this.terms[2] = new foundry.dice.terms.Die({ this.terms[2] = new foundry.dice.terms.Die({ faces: defaultFearDice });
faces: this.data.rules.dualityRoll?.defaultFearDice ?? 12
});
} }
applyAdvantage() { applyAdvantage() {
@ -278,8 +276,6 @@ export default class DualityRoll extends D20Roll {
} }
static async handleTriggers(roll, config) { static async handleTriggers(roll, config) {
if (!config.source?.actor) return;
const updates = []; const updates = [];
const dualityUpdates = await game.system.registeredTriggers.runTrigger( const dualityUpdates = await game.system.registeredTriggers.runTrigger(
CONFIG.DH.TRIGGER.triggers.dualityRoll.id, CONFIG.DH.TRIGGER.triggers.dualityRoll.id,

View file

@ -754,24 +754,16 @@ export default class DhpActor extends Actor {
}; };
} }
} else { } else {
const valueFunc = (base, resource, baseMax) => {
if (resource.clear) return baseMax && base.inverted ? baseMax : 0;
return (base.value ?? base) + resource.value;
};
switch (r.key) { switch (r.key) {
case 'fear': case 'fear':
ui.resources.updateFear( ui.resources.updateFear(
valueFunc( game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear) + r.value
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
r
)
); );
break; break;
case 'armor': case 'armor':
if (this.system.armor?.system?.marks) { if (this.system.armor?.system?.marks) {
updates.armor.resources['system.marks.value'] = Math.max( updates.armor.resources['system.marks.value'] = Math.max(
Math.min(valueFunc(this.system.armor.system.marks, r), this.system.armorScore), Math.min(this.system.armor.system.marks.value + r.value, this.system.armorScore),
0 0
); );
} }
@ -780,7 +772,7 @@ export default class DhpActor extends Actor {
if (this.system.resources?.[r.key]) { if (this.system.resources?.[r.key]) {
updates.actor.resources[`system.resources.${r.key}.value`] = Math.max( updates.actor.resources[`system.resources.${r.key}.value`] = Math.max(
Math.min( Math.min(
valueFunc(this.system.resources[r.key], r, this.system.resources[r.key].max), this.system.resources[r.key].value + r.value,
this.system.resources[r.key].max this.system.resources[r.key].max
), ),
0 0

View file

@ -80,29 +80,28 @@ export const renderDualityButton = async event => {
}; };
export const enrichedDualityRoll = async ( export const enrichedDualityRoll = async (
{ reaction, traitValue, target, difficulty, title, label, advantage, customConfig }, { reaction, traitValue, target, difficulty, title, label, advantage },
event event
) => { ) => {
const config = { const config = {
event: event ?? {}, event: event ?? {},
title: title, title: title,
headerTitle: label,
roll: { roll: {
trait: traitValue && target ? traitValue : null, trait: traitValue && target ? traitValue : null,
label: label,
difficulty: difficulty, difficulty: difficulty,
advantage, advantage,
type: reaction ? 'reaction' : null type: reaction ? 'reaction' : null
}, },
type: 'trait', type: 'trait',
hasRoll: true, hasRoll: true
...(customConfig ?? {})
}; };
if (target) { if (target) {
await target.diceRoll(config); await target.diceRoll(config);
} else { } else {
// For no target, call DualityRoll directly with basic data // For no target, call DualityRoll directly with basic data
config.data = { experiences: {}, traits: {}, rules: {} }; config.data = { experiences: {}, traits: {} };
config.source = { actor: null }; config.source = { actor: null };
await CONFIG.Dice.daggerheart.DualityRoll.build(config); await CONFIG.Dice.daggerheart.DualityRoll.build(config);
} }

View file

@ -6,7 +6,7 @@ export default function DhFateRollEnricher(match, _options) {
const fateTypeFromRoll = getFateType(roll?.type); const fateTypeFromRoll = getFateType(roll?.type);
if (fateTypeFromRoll == 'BAD') { if (fateTypeFromRoll == "BAD") {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return; return;
} }
@ -15,37 +15,27 @@ export default function DhFateRollEnricher(match, _options) {
} }
export function getFateType(fateTypeValue) { export function getFateType(fateTypeValue) {
const fateTypeFromValue = fateTypeValue const fateTypeFromValue = fateTypeValue ?
? fateTypeValue.toLowerCase() == 'fear' (fateTypeValue.toLowerCase() == "fear" ? "Fear" :
? 'Fear' (fateTypeValue.toLowerCase() == "hope" ? "Hope" : "BAD")) : "Hope";
: fateTypeValue.toLowerCase() == 'hope'
? 'Hope'
: 'BAD'
: 'Hope';
return fateTypeFromValue; return fateTypeFromValue;
} }
function getFateMessage(roll, flavor) { function getFateMessage(roll, flavor) {
const fateType = getFateType(roll?.type); const fateType = getFateType(roll?.type);
if (fateType == 'BAD') { if (fateType == "BAD") {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return ''; return '';
} }
const fateTypeLocalized = const fateTypeLocalized = fateType === "Hope" ? game.i18n.localize("DAGGERHEART.GENERAL.hope") : game.i18n.localize("DAGGERHEART.GENERAL.fear");
fateType === 'Hope'
? game.i18n.localize('DAGGERHEART.GENERAL.hope')
: game.i18n.localize('DAGGERHEART.GENERAL.fear');
const title = const title = flavor ?? fateTypeLocalized + ' ' +
flavor ?? game.i18n.localize('DAGGERHEART.GENERAL.fate') + ' ' +
fateTypeLocalized + game.i18n.localize('DAGGERHEART.GENERAL.roll');
' ' +
game.i18n.localize('DAGGERHEART.GENERAL.fate') +
' ' +
game.i18n.localize('DAGGERHEART.GENERAL.roll');
const dataLabel = game.i18n.localize('DAGGERHEART.GENERAL.fate'); const dataLabel = game.i18n.localize('DAGGERHEART.GENERAL.fate');
@ -66,11 +56,11 @@ function getFateMessage(roll, flavor) {
export const renderFateButton = async event => { export const renderFateButton = async event => {
const button = event.currentTarget, const button = event.currentTarget,
target = getCommandTarget({ allowNull: true }); target = getCommandTarget({ allowNull: true });
console.log('button', button); console.log("button", button);
const fateTypeFromButton = getFateType(button.dataset?.fatetype); const fateTypeFromButton = getFateType(button.dataset?.fatetype);
if (fateTypeFromButton == 'BAD') { if (fateTypeFromButton == "BAD") {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.fateTypeParsing'));
return; return;
} }
@ -86,12 +76,16 @@ export const renderFateButton = async event => {
); );
}; };
export const enrichedFateRoll = async ({ target, title, label, fateType }, event) => { export const enrichedFateRoll = async (
{ target, title, label, fateType },
event
) => {
const config = { const config = {
event: event ?? {}, event: event ?? {},
title: title, title: title,
headerTitle: label, roll: {
roll: {}, label: label,
},
hasRoll: true, hasRoll: true,
fateType: fateType fateType: fateType
}; };