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.
This commit is contained in:
George Brocklehurst 2025-07-20 10:08:39 +01:00
parent 3dd2378ffb
commit b05915bd80
No known key found for this signature in database
GPG key ID: 0C643A97B51FFCFB

View file

@ -12,11 +12,13 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
); );
this.nrChoices = { this.nrChoices = {
shortRest: { shortRest: {
taken: 0,
max: max:
(shortrest ? this.moveData.shortRest.nrChoices : 0) + (shortrest ? this.moveData.shortRest.nrChoices : 0) +
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].shortMoves actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].shortMoves
}, },
longRest: { longRest: {
taken: 0,
max: max:
(!shortrest ? this.moveData.longRest.nrChoices : 0) + (!shortrest ? this.moveData.longRest.nrChoices : 0) +
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].longMoves actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].longMoves
@ -67,15 +69,23 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
return acc; return acc;
}, 0); }, 0);
const shortRestMovesSelected = Object.values(this.moveData.shortRest.moves).reduce(
(acc, x) => acc + (x.selected ?? 0),
0
);
const longRestMovesSelected = Object.values(this.moveData.longRest.moves).reduce(
(acc, x) => acc + (x.selected ?? 0),
0
);
context.nrChoices = { context.nrChoices = {
...this.nrChoices, ...this.nrChoices,
shortRest: { shortRest: {
...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: { longRest: {
...this.nrChoices.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 = { context.nrChoices.total = {
@ -86,26 +96,23 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
context.shortRestMoves = this.nrChoices.shortRest.max > 0 ? this.moveData.shortRest : null; context.shortRestMoves = this.nrChoices.shortRest.max > 0 ? this.moveData.shortRest : null;
context.longRestMoves = this.nrChoices.longRest.max > 0 ? this.moveData.longRest : 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; return context;
} }
static selectMove(_, target) { static selectMove(_, target) {
const nrSelected = Object.values(this.moveData[target.dataset.category].moves).reduce( const { category, move } = target.dataset;
(acc, x) => acc + (x.selected ?? 0),
0
);
if (nrSelected === this.nrChoices[target.dataset.category].max) { const nrSelected = Object.values(this.moveData[category].moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
if (nrSelected + this.nrChoices[category].taken >= this.nrChoices[category].max) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves')); ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves'));
return; return;
} }
const move = target.dataset.move; this.moveData[category].moves[move].selected = this.moveData[category].moves[move].selected
this.moveData[target.dataset.category].moves[move].selected = this.moveData[target.dataset.category].moves[move] ? this.moveData[category].moves[move].selected + 1
.selected
? this.moveData[target.dataset.category].moves[move].selected + 1
: 1; : 1;
this.render(); this.render();
@ -158,7 +165,25 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
cls.create(msg.toObject()); 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) { static async updateData(event, element, formData) {