Apply the first downtime move before picking the second one (#383)

* Downtime: allow moves to be taken individually.

Fixes https://github.com/Foundryborne/daggerheart/issues/374

Some downtime moves require a roll to see how successful they are. In these
cases, the player might want to see how their first move works out before
they select their next one.

This commit updates the downtime dialog to allow for this behaviour:

- The "Take Downtime" button is enabled whenever any moves are selected.
- Clicking the button only closes the dialog when all moves have been made.

To keep track of this, the `nrChoices` object has been expanded to include a
`taken` counter, which is increased whenever a move is taken.

After making one move the selection is reset, but the number of moves
displayed in the dialog header and the number of permitted selections both
take the number of taken moves into account.

* Fix heading in short rest chat message.

Prior to this commit the heading for a short rest chat message was "long
rest".

* Remove unused template context.

* Extract method for repeated calculation.

In the downtime dialog, we need to calculate the number of selected moves in
several places. This commit extracts a method to handle that, which reduces
repetition and hopefully makes the code more readable.
This commit is contained in:
George Brocklehurst 2025-07-20 11:40:11 +01:00 committed by GitHub
parent 3dd2378ffb
commit 1e828547bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -12,17 +12,18 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
);
this.nrChoices = {
shortRest: {
taken: 0,
max:
(shortrest ? this.moveData.shortRest.nrChoices : 0) +
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].shortMoves
},
longRest: {
taken: 0,
max:
(!shortrest ? this.moveData.longRest.nrChoices : 0) +
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].longMoves
}
};
this.nrChoices.total = { max: this.nrChoices.shortRest.max + this.nrChoices.longRest.max };
}
get title() {
@ -62,50 +63,41 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
);
context.selectedActivity = this.selectedActivity;
context.moveData = this.moveData;
context.nrCurrentChoices = Object.values(this.moveData).reduce((acc, category) => {
acc += Object.values(category.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
return acc;
}, 0);
const shortRestMovesSelected = this.#nrSelectedMoves('shortRest');
const longRestMovesSelected = this.#nrSelectedMoves('longRest');
context.nrChoices = {
...this.nrChoices,
shortRest: {
...this.nrChoices.shortRest,
current: Object.values(this.moveData.shortRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
current: this.nrChoices.shortRest.taken + shortRestMovesSelected
},
longRest: {
...this.nrChoices.longRest,
current: Object.values(this.moveData.longRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
current: this.nrChoices.longRest.taken + longRestMovesSelected
}
};
context.nrChoices.total = {
...this.nrChoices.total,
current: context.nrChoices.shortRest.current + context.nrChoices.longRest.current
};
context.shortRestMoves = this.nrChoices.shortRest.max > 0 ? this.moveData.shortRest : null;
context.longRestMoves = this.nrChoices.longRest.max > 0 ? this.moveData.longRest : null;
context.disabledDowntime = context.nrChoices.total.current < context.nrChoices.total.max;
context.disabledDowntime = shortRestMovesSelected === 0 && longRestMovesSelected === 0;
return context;
}
static selectMove(_, target) {
const nrSelected = Object.values(this.moveData[target.dataset.category].moves).reduce(
(acc, x) => acc + (x.selected ?? 0),
0
);
const { category, move } = target.dataset;
if (nrSelected === this.nrChoices[target.dataset.category].max) {
const nrSelected = this.#nrSelectedMoves(category);
if (nrSelected + this.nrChoices[category].taken >= this.nrChoices[category].max) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves'));
return;
}
const move = target.dataset.move;
this.moveData[target.dataset.category].moves[move].selected = this.moveData[target.dataset.category].moves[move]
.selected
? this.moveData[target.dataset.category].moves[move].selected + 1
this.moveData[category].moves[move].selected = this.moveData[category].moves[move].selected
? this.moveData[category].moves[move].selected + 1
: 1;
this.render();
@ -150,7 +142,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/ui/chat/downtime.hbs',
{
title: `${this.actor.name} - ${game.i18n.localize(`DAGGERHEART.APPLICATIONS.Downtime.${this.shortRest ? 'shortRest' : 'longRest'}.title`)}`,
title: `${this.actor.name} - ${game.i18n.localize(`DAGGERHEART.APPLICATIONS.Downtime.${this.shortrest ? 'shortRest' : 'longRest'}.title`)}`,
moves: moves
}
)
@ -158,11 +150,33 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
cls.create(msg.toObject());
this.close();
// Reset selection and update number of taken moves
for (const [catName, category] of Object.entries(this.moveData)) {
for (const move of Object.values(category.moves)) {
if (move.selected > 0) {
this.nrChoices[catName].taken += move.selected;
move.selected = 0;
}
}
}
// We can close the window when all moves are taken
if (
this.nrChoices.shortRest.taken >= this.nrChoices.shortRest.max &&
this.nrChoices.longRest.taken >= this.nrChoices.longRest.max
) {
this.close();
} else {
this.render();
}
}
static async updateData(event, element, formData) {
this.customActivity = foundry.utils.mergeObject(this.customActivity, formData.object);
this.render();
}
#nrSelectedMoves(category) {
return Object.values(this.moveData[category].moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
}
}