Feature/666 experience hope cost (#728)

* h

* Character & Companion Experience Hope Cost
This commit is contained in:
Dapoulp 2025-08-08 23:31:01 +02:00 committed by GitHub
parent f9cb0954f9
commit 45b3569cba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 61 additions and 13 deletions

View file

@ -45,6 +45,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
return this.config.title;
}
get actor() {
return this.config?.data?.parent;
}
/** @override */
static PARTS = {
header: {
@ -69,9 +73,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
icon
}));
this.config.costs ??= [];
if (this.config.costs?.length) {
const updatedCosts = game.system.api.fields.ActionFields.CostField.calcCosts.call(
this.action,
this.action ?? { actor: this.actor },
this.config.costs
);
context.costs = updatedCosts.map(x => ({
@ -80,7 +85,10 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
? this.action.parent.parent.name
: game.i18n.localize(CONFIG.DH.GENERAL.abilityCosts[x.key].label)
}));
context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call(this.action, updatedCosts);
context.canRoll = game.system.api.fields.ActionFields.CostField.hasCost.call(
this.action ?? { actor: this.actor },
updatedCosts
);
this.config.data.scale = this.config.costs[0].total;
}
if (this.config.uses?.max) {
@ -143,6 +151,12 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
this.config.experiences.indexOf(button.dataset.key) > -1
? this.config.experiences.filter(x => x !== button.dataset.key)
: [...this.config.experiences, button.dataset.key];
if(this.config?.data?.parent?.type === 'character' || this.config?.data?.parent?.type === 'companion') {
this.config.costs =
this.config.costs.indexOf(this.config.costs.find(c => c.extKey === button.dataset.key)) > -1
? this.config.costs.filter(x => x.extKey !== button.dataset.key)
: [...this.config.costs, { extKey: button.dataset.key, key: 'hope', value: 1, name: this.config.data?.experiences?.[button.dataset.key]?.name }];
}
this.render();
}

View file

@ -631,13 +631,34 @@ export default class CharacterSheet extends DHBaseActorSheet {
},
hasRoll: true
};
this.document.diceRoll({
const result = await this.document.diceRoll({
...config,
headerTitle: `${game.i18n.localize('DAGGERHEART.GENERAL.dualityRoll')}: ${this.actor.name}`,
title: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: abilityLabel
})
});
setTimeout(() => {
this.consumeResource(result?.costs);
}, 50);
}
async consumeResource(costs) {
if(!costs?.length) return;
const usefulResources = foundry.utils.deepClone(this.actor.system.resources);
const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(costs)
.map(c => {
const resource = usefulResources[c.key];
return {
key: c.key,
value: (c.total ?? c.value) * (resource.isReversed ? 1 : -1),
target: resource.target,
keyIsID: resource.keyIsID
};
});
await this.actor.modifyResource(resources);
}
//TODO: redo toggleEquipItem method

View file

@ -221,12 +221,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
}
}
const resources = config.costs
const resources = game.system.api.fields.ActionFields.CostField.getRealCosts(config.costs)
.filter(
c =>
c.enabled !== false &&
((!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
(successCost && c.consumeOnSuccess))
(!successCost && (!c.consumeOnSuccess || config.roll?.success)) ||
(successCost && c.consumeOnSuccess)
)
.map(c => {
const resource = usefulResources[c.key];
@ -238,7 +237,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
};
});
await this.actor.modifyResource(resources);
await (this.actor.system.partner ?? this.actor).modifyResource(resources);
if (
config.uses?.enabled &&
((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) ||

View file

@ -47,6 +47,7 @@ export default class CostField extends fields.ArrayField {
static hasCost(costs) {
const realCosts = CostField.getRealCosts.call(this, costs),
hasFearCost = realCosts.findIndex(c => c.key === 'fear');
if (hasFearCost > -1) {
const fearCost = realCosts.splice(hasFearCost, 1)[0];
if (
@ -70,7 +71,8 @@ export default class CostField extends fields.ArrayField {
}
static getResources(costs) {
const actorResources = this.actor.system.resources;
const actorResources = foundry.utils.deepClone(this.actor.system.resources);
if(this.actor.system.partner) actorResources.hope = foundry.utils.deepClone(this.actor.system.partner.system.resources.hope);
const itemResources = {};
for (let itemResource of costs) {
if (itemResource.keyIsID) {
@ -89,7 +91,13 @@ export default class CostField extends fields.ArrayField {
static getRealCosts(costs) {
const realCosts = costs?.length ? costs.filter(c => c.enabled) : [];
return realCosts;
let mergedCosts = [];
realCosts.forEach(c => {
const getCost = Object.values(mergedCosts).find(gc => gc.key === c.key);
if(getCost) getCost.total += c.total;
else mergedCosts.push(c);
});
return mergedCosts;
}
static formatMax(max) {

View file

@ -236,7 +236,9 @@ export const registerRollDiceHooks = () => {
if (updates.length) {
const target = actor.system.partner ?? actor;
if (!['dead', 'unconcious'].some(x => actor.statuses.has(x))) {
target.modifyResource(updates);
setTimeout(() => {
target.modifyResource(updates);
}, 50);
}
}