[Fix] Downtime Rework (#367)

* Fixed so that the dropdown for activeEffectAutocomplete never ends up behind dialog

* Downtime can now display both ShortRest and LongRest options depending on character rules

* Initial downtime layout rework

* Fixed styling for downtime tooltip

* Added icon to homebrew menu for DowntimeActions

* Fixed columns if both types of moves are not available

* Changed the lightmode to darkmode

* Added downtime buttons

* .

* Moved extra rest options from rules to bonuses

* Improved dialog width
This commit is contained in:
WBHarry 2025-07-18 00:48:59 +02:00 committed by GitHub
parent 0cc1597dfe
commit 6e87e4dad0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 390 additions and 152 deletions

View file

@ -7,8 +7,22 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
this.actor = actor;
this.shortrest = shortrest;
const options = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves;
this.moveData = shortrest ? options.shortRest : options.longRest;
this.moveData = foundry.utils.deepClone(
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves
);
this.nrChoices = {
shortRest: {
max:
(shortrest ? this.moveData.shortRest.nrChoices : 0) +
actor.system.bonuses.rest[`${shortrest ? 'short' : 'long'}Rest`].shortMoves
},
longRest: {
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() {
@ -17,8 +31,8 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'views', 'downtime'],
position: { width: 680, height: 'auto' },
classes: ['daggerheart', 'views', 'dh-style', 'dialog', 'downtime'],
position: { width: 'auto', height: 'auto' },
actions: {
selectMove: this.selectMove,
takeDowntime: this.takeDowntime
@ -29,7 +43,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
static PARTS = {
application: {
id: 'downtime',
template: 'systems/daggerheart/templates/dialogs/downtime.hbs'
template: 'systems/daggerheart/templates/dialogs/downtime/downtime.hbs'
}
};
@ -37,46 +51,83 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
super._attachPartListeners(partId, htmlElement, options);
htmlElement
.querySelectorAll('.activity-image')
.querySelectorAll('.activity-container')
.forEach(element => element.addEventListener('contextmenu', this.deselectMove.bind(this)));
}
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.title = game.i18n.localize(
`DAGGERHEART.APPLICATIONS.Downtime.${this.shortrest ? 'shortRest' : 'longRest'}.title`
);
context.selectedActivity = this.selectedActivity;
context.moveData = this.moveData;
context.nrCurrentChoices = Object.values(this.moveData.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
context.disabledDowntime = context.nrCurrentChoices < context.moveData.nrChoices;
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);
context.nrChoices = {
...this.nrChoices,
shortRest: {
...this.nrChoices.shortRest,
current: Object.values(this.moveData.shortRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
},
longRest: {
...this.nrChoices.longRest,
current: Object.values(this.moveData.longRest.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0)
}
};
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;
return context;
}
static selectMove(_, button) {
const nrSelected = Object.values(this.moveData.moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
if (nrSelected === this.moveData.nrChoices) {
static selectMove(_, target) {
const nrSelected = Object.values(this.moveData[target.dataset.category].moves).reduce(
(acc, x) => acc + (x.selected ?? 0),
0
);
if (nrSelected === this.nrChoices[target.dataset.category].max) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves'));
return;
}
const move = button.dataset.move;
this.moveData.moves[move].selected = this.moveData.moves[move].selected
? this.moveData.moves[move].selected + 1
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
: 1;
this.render();
}
deselectMove(event) {
const move = event.currentTarget.dataset.move;
this.moveData.moves[move].selected = this.moveData.moves[move].selected
? this.moveData.moves[move].selected - 1
const button = event.target.closest('.activity-container');
const move = button.dataset.move;
this.moveData[button.dataset.category].moves[move].selected = this.moveData[button.dataset.category].moves[move]
.selected
? this.moveData[button.dataset.category].moves[move].selected - 1
: 0;
this.render();
}
static async takeDowntime() {
const moves = Object.values(this.moveData.moves).filter(x => x.selected);
const moves = Object.values(this.moveData).flatMap(category => {
return Object.values(category.moves)
.filter(x => x.selected)
.flatMap(move => [...Array(move.selected).keys()].map(_ => move));
});
const cls = getDocumentClass('ChatMessage');
const msg = new cls({

View file

@ -4,13 +4,14 @@ import DHActionConfig from '../../sheets-configs/action-config.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhSettingsActionView extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(resolve, reject, title, name, img, description, actions) {
constructor(resolve, reject, title, name, icon, img, description, actions) {
super({});
this.resolve = resolve;
this.reject = reject;
this.viewTitle = title;
this.name = name;
this.icon = icon;
this.img = img;
this.description = description;
this.actions = actions;
@ -23,7 +24,7 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'setting', 'dh-style'],
position: { width: '400', height: 'auto' },
position: { width: 440, height: 'auto' },
actions: {
editImage: this.onEditImage,
addItem: this.addItem,
@ -46,6 +47,7 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.name = this.name;
context.icon = this.icon;
context.img = this.img;
context.description = this.description;
context.enrichedDescription = await foundry.applications.ux.TextEditor.enrichHTML(context.description);
@ -55,8 +57,9 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
}
static async updateData(event, element, formData) {
const { name, img, description } = foundry.utils.expandObject(formData.object);
const { name, icon, description } = foundry.utils.expandObject(formData.object);
this.name = name;
this.icon = icon;
this.description = description;
this.render();
@ -65,6 +68,7 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
static async saveForm(event) {
this.resolve({
name: this.name,
icon: this.icon,
img: this.img,
description: this.description,
actions: this.actions

View file

@ -76,6 +76,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
reject,
game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMoves'),
move.name,
move.icon,
move.img,
move.description,
move.actions
@ -87,6 +88,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
await this.settings.updateSource({
[`restMoves.${type}.moves.${id}`]: {
name: data.name,
icon: data.icon,
img: data.img,
description: data.description
}

View file

@ -88,6 +88,9 @@ export default class DhActiveEffectConfig extends foundry.applications.sheets.Ac
element.value = `system.${item.value}`;
},
click: e => e.fetch(),
customize: function (_input, _inputRect, container) {
container.style.zIndex = foundry.applications.api.ApplicationV2._maxZ;
},
minLength: 0
});
});

View file

@ -28,7 +28,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
useAction: this.useAction,
toggleResourceDice: this.toggleResourceDice,
handleResourceDice: this.handleResourceDice,
toChat: this.toChat
toChat: this.toChat,
useDowntime: this.useDowntime
},
window: {
resizable: true
@ -752,6 +753,12 @@ export default class CharacterSheet extends DHBaseActorSheet {
}
}
static useDowntime(_, button) {
new game.system.api.applications.dialogs.Downtime(this.document, button.dataset.type === 'shortRest').render(
true
);
}
async _onDragStart(event) {
const item = this.getItem(event);