[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

@ -249,8 +249,9 @@
"title": "{actor} - Death Move"
},
"Downtime": {
"downtimeHeader": "Downtime Moves ({current}/{max})",
"longRest": {
"title": "Long Rest",
"moves": "Long Rest Moves ({current}/{max})",
"clearStress": {
"description": "Describe how you blow off steam or pull yourself together, and clear all marked Stress.",
"name": "Clear Stress"
@ -267,7 +268,6 @@
"description": "Describe how you patch yourself up and remove all marked Hit Points. You may also do this on an ally instead.",
"name": "Tend to Wounds"
},
"title": "Long Rest",
"workOnAProject": {
"description": "Establish or continue work on a project.",
"name": "Work on a Project"
@ -275,6 +275,7 @@
},
"shortRest": {
"title": "Short Rest",
"moves": "Short Rest Moves ({current}/{max})",
"tendToWounds": {
"name": "Tend to Wounds",
"description": "Describe how you hastily patch yourself up, then clear a number of Hit Points equal to 1d4 + your tier. You can do this to an ally instead."
@ -291,7 +292,8 @@
"name": "Prepare",
"description": "Describe how you prepare yourself for the path ahead, then gain a Hope. If you choose to Prepare with one or more members of your party, you each gain 2 Hope."
}
}
},
"takeDowntime": "Take Downtime"
},
"HUD": {
"tokenHUD": {
@ -1012,6 +1014,30 @@
"singular": "Adversary",
"plural": "Adversaries"
},
"Bonuses": {
"rest": {
"shortRest": {
"shortRestMoves": {
"label": "Short Rest: Bonus Short Rest Moves",
"hint": "The number of extra Short Rest Moves the character can take during a Short Rest."
},
"longRestMoves": {
"label": "Short Rest: Bonus Long Rest Moves",
"hint": "The number of extra Long Rest Moves the character can take during a Short Rest."
}
},
"longRest": {
"shortRestMoves": {
"label": "Long Rest: Bonus Short Rest Moves",
"hint": "The number of extra Short Rest Moves the character can take during a Long Rest."
},
"longRestMoves": {
"label": "Long Rest: Bonus Long Rest Moves",
"hint": "The number of extra Long Rest Moves the character can take during a Long Rest."
}
}
}
},
"Character": {
"singular": "Character",
"plural": "Characters"

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);

View file

@ -130,6 +130,7 @@ export const defaultRestOptions = {
tendToWounds: {
id: 'tendToWounds',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.tendToWounds.name'),
icon: 'fa-solid fa-bandage',
img: 'icons/magic/life/cross-worn-green.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.tendToWounds.description'),
actions: [
@ -153,6 +154,7 @@ export const defaultRestOptions = {
clearStress: {
id: 'clearStress',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.clearStress.name'),
icon: 'fa-regular fa-face-surprise',
img: 'icons/magic/perception/eye-ringed-green.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.clearStress.description'),
actions: [
@ -176,6 +178,7 @@ export const defaultRestOptions = {
repairArmor: {
id: 'repairArmor',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.repairArmor.name'),
icon: 'fa-solid fa-hammer',
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.repairArmor.description'),
actions: []
@ -183,6 +186,7 @@ export const defaultRestOptions = {
prepare: {
id: 'prepare',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.name'),
icon: 'fa-solid fa-dumbbell',
img: 'icons/skills/trades/academics-merchant-scribe.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.description'),
actions: []
@ -192,6 +196,7 @@ export const defaultRestOptions = {
tendToWounds: {
id: 'tendToWounds',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.tendToWounds.name'),
icon: 'fa-solid fa-bandage',
img: 'icons/magic/life/cross-worn-green.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.tendToWounds.description'),
actions: []
@ -199,6 +204,7 @@ export const defaultRestOptions = {
clearStress: {
id: 'clearStress',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.clearStress.name'),
icon: 'fa-regular fa-face-surprise',
img: 'icons/magic/perception/eye-ringed-green.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.clearStress.description'),
actions: []
@ -206,6 +212,7 @@ export const defaultRestOptions = {
repairArmor: {
id: 'repairArmor',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.repairArmor.name'),
icon: 'fa-solid fa-hammer',
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.repairArmor.description'),
actions: []
@ -213,6 +220,7 @@ export const defaultRestOptions = {
prepare: {
id: 'prepare',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.name'),
icon: 'fa-solid fa-dumbbell',
img: 'icons/skills/trades/academics-merchant-scribe.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.description'),
actions: []
@ -220,19 +228,12 @@ export const defaultRestOptions = {
workOnAProject: {
id: 'workOnAProject',
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.workOnAProject.name'),
icon: 'fa-solid fa-diagram-project',
img: 'icons/skills/social/thumbsup-approval-like.webp',
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.workOnAProject.description'),
actions: []
}
}),
custom: {
id: 'customActivity',
name: '',
img: 'icons/skills/trades/academics-investigation-puzzles.webp',
description: '',
namePlaceholder: 'DAGGERHEART.APPLICATIONS.Downtime.custom.namePlaceholder',
placeholder: 'DAGGERHEART.APPLICATIONS.Downtime.custom.placeholder'
}
})
};
export const deathMoves = {

View file

@ -126,6 +126,44 @@ export default class DhCharacter extends BaseDataActor {
}),
rally: new fields.ArrayField(new fields.StringField(), {
label: 'DAGGERHEART.CLASS.Feature.rallyDice'
}),
rest: new fields.SchemaField({
shortRest: new fields.SchemaField({
shortMoves: new fields.NumberField({
required: true,
integer: true,
min: 0,
initial: 0,
label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.label',
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.shortRestMoves.hint'
}),
longMoves: new fields.NumberField({
required: true,
integer: true,
min: 0,
initial: 0,
label: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.label',
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.shortRest.longRestMoves.hint'
})
}),
longRest: new fields.SchemaField({
shortMoves: new fields.NumberField({
required: true,
integer: true,
min: 0,
initial: 0,
label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.label',
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.shortRestMoves.hint'
}),
longMoves: new fields.NumberField({
required: true,
integer: true,
min: 0,
initial: 0,
label: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.label',
hint: 'DAGGERHEART.GENERAL.Bonuses.rest.longRest.longRestMoves.hint'
})
})
})
}),
companion: new ForeignDocumentUUIDField({ type: 'Actor', nullable: true, initial: null }),

View file

@ -54,6 +54,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
moves: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField({ required: true }),
icon: new fields.StringField({ required: true }),
img: new fields.FilePathField({
initial: 'icons/magic/life/cross-worn-green.webp',
categories: ['IMAGE'],
@ -70,6 +71,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
moves: new fields.TypedObjectField(
new fields.SchemaField({
name: new fields.StringField({ required: true }),
icon: new fields.StringField({ required: true }),
img: new fields.FilePathField({
initial: 'icons/magic/life/cross-worn-green.webp',
categories: ['IMAGE'],

View file

@ -16,7 +16,7 @@ export default class DHToken extends TokenDocument {
});
bars.sort((a, b) => a.label.compare(b.label));
const invalidAttributes = ['gold', 'levelData', 'rules.damageReduction.maxArmorMarked.value'];
const invalidAttributes = ['gold', 'levelData', 'actions', 'rules.damageReduction.maxArmorMarked.value'];
const values = attributes.value.reduce((acc, v) => {
const a = v.join('.');
if (invalidAttributes.some(x => a.startsWith(x))) return acc;
@ -33,18 +33,18 @@ export default class DHToken extends TokenDocument {
return bars.concat(values);
}
static _getTrackedAttributesFromSchema(schema, _path=[]) {
const attributes = {bar: [], value: []};
for ( const [name, field] of Object.entries(schema.fields) ) {
static _getTrackedAttributesFromSchema(schema, _path = []) {
const attributes = { bar: [], value: [] };
for (const [name, field] of Object.entries(schema.fields)) {
const p = _path.concat([name]);
if ( field instanceof foundry.data.fields.NumberField ) attributes.value.push(p);
if ( field instanceof foundry.data.fields.ArrayField ) attributes.value.push(p);
if (field instanceof foundry.data.fields.NumberField) attributes.value.push(p);
if (field instanceof foundry.data.fields.ArrayField) attributes.value.push(p);
const isSchema = field instanceof foundry.data.fields.SchemaField;
const isModel = field instanceof foundry.data.fields.EmbeddedDataField;
if ( isSchema || isModel ) {
if (isSchema || isModel) {
const schema = isModel ? field.model.schema : field;
const isBar = schema.has && schema.has("value") && schema.has("max");
if ( isBar ) attributes.bar.push(p);
const isBar = schema.has && schema.has('value') && schema.has('max');
if (isBar) attributes.bar.push(p);
else {
const inner = this.getTrackedAttributes(schema, p);
attributes.bar.push(...inner.bar);

View file

@ -22,6 +22,28 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
options.direction = this._determineItemTooltipDirection(element);
}
} else {
const shortRest = element.dataset.tooltip?.startsWith('#shortRest#');
const longRest = element.dataset.tooltip?.startsWith('#longRest#');
if (shortRest || longRest) {
const key = element.dataset.tooltip.slice(shortRest ? 11 : 10);
const downtimeOptions = shortRest
? CONFIG.DH.GENERAL.defaultRestOptions.shortRest()
: CONFIG.DH.GENERAL.defaultRestOptions.longRest();
const move = downtimeOptions[key];
html = await foundry.applications.handlebars.renderTemplate(
`systems/daggerheart/templates/ui/tooltip/downtime.hbs`,
{
move: move
}
);
this.tooltip.innerHTML = html;
options.direction = this._determineItemTooltipDirection(
element,
this.constructor.TOOLTIP_DIRECTIONS.UP
);
}
const isAdvantage = element.dataset.tooltip?.startsWith('#advantage#');
const isDisadvantage = element.dataset.tooltip?.startsWith('#disadvantage#');
if (isAdvantage || isDisadvantage) {
@ -44,9 +66,34 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
super.activate(element, { ...options, html: html });
}
_determineItemTooltipDirection(element) {
_determineItemTooltipDirection(element, prefered = this.constructor.TOOLTIP_DIRECTIONS.LEFT) {
const pos = element.getBoundingClientRect();
const dirs = this.constructor.TOOLTIP_DIRECTIONS;
return dirs[pos.x - this.tooltip.offsetWidth < 0 ? 'DOWN' : 'LEFT'];
switch (prefered) {
case this.constructor.TOOLTIP_DIRECTIONS.LEFT:
return dirs[
pos.x - this.tooltip.offsetWidth < 0
? this.constructor.TOOLTIP_DIRECTIONS.DOWN
: this.constructor.TOOLTIP_DIRECTIONS.LEFT
];
case this.constructor.TOOLTIP_DIRECTIONS.UP:
return dirs[
pos.y - this.tooltip.offsetHeight < 0
? this.constructor.TOOLTIP_DIRECTIONS.RIGHT
: this.constructor.TOOLTIP_DIRECTIONS.UP
];
case this.constructor.TOOLTIP_DIRECTIONS.RIGHT:
return dirs[
pos.x + this.tooltip.offsetWidth > document.body.clientWidth
? this.constructor.TOOLTIP_DIRECTIONS.DOWN
: this.constructor.TOOLTIP_DIRECTIONS.RIGHT
];
case this.constructor.TOOLTIP_DIRECTIONS.DOWN:
return dirs[
pos.y + this.tooltip.offsetHeight > document.body.clientHeight
? this.constructor.TOOLTIP_DIRECTIONS.LEFT
: this.constructor.TOOLTIP_DIRECTIONS.DOWN
];
}
}
}

View file

@ -25,6 +25,7 @@ export const preloadHandlebarsTemplates = async function () {
'systems/daggerheart/templates/settings/components/settings-item-line.hbs',
'systems/daggerheart/templates/ui/chat/parts/damage-chat.hbs',
'systems/daggerheart/templates/ui/chat/parts/target-chat.hbs',
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs'
'systems/daggerheart/templates/ui/tooltip/parts/tooltipTags.hbs',
'systems/daggerheart/templates/dialogs/downtime/activities.hbs'
]);
};

View file

@ -1,81 +1,75 @@
@import '../../utils/spacing.less';
@import '../../utils/colors.less';
.daggerheart.views {
.downtime-container {
.downtime-header {
margin: 0;
color: light-dark(@dark-blue, @golden);
text-align: center;
.theme-light .daggerheart.dh-style.views.downtime {
.downtime-container .activity-container .activity-selected-marker {
background-image: url(../assets/parchments/dh-parchment-light.png);
}
}
.daggerheart.dh-style.views.downtime {
font-family: @font-body;
.downtime-container {
.activities-grouping {
width: 280px;
}
.activities-container {
width: 100%;
.activity-container {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px;
.activity-title {
flex: 1;
.activity-inner-container {
display: flex;
align-items: center;
gap: 4px;
.activity-title-text {
font-size: 24px;
font-weight: bold;
.activity-marker {
font-size: 8px;
flex: none;
color: light-dark(#18162e, #f3c267);
margin-right: 4px;
}
.activity-image {
width: 80px;
position: relative;
.activity-select-section {
display: flex;
justify-content: center;
margin-right: 8px;
border: 2px solid black;
border-radius: 50%;
cursor: pointer;
align-items: center;
gap: 4px;
.activity-select-label {
position: absolute;
top: -9px;
.activity-icon {
min-width: 24px;
text-align: center;
}
}
}
.activity-selected-marker {
font-size: 14px;
border: 1px solid light-dark(@dark-blue, @golden);
border-radius: 6px;
color: light-dark(@beige, @dark);
background-image: url(../assets/parchments/dh-parchment-light.png);
color: light-dark(@dark, @beige);
background-image: url(../assets/parchments/dh-parchment-dark.png);
padding: 0 8px;
line-height: 1;
font-weight: bold;
}
img {
border-radius: 50%;
}
&:hover,
&.selected {
filter: drop-shadow(0 0 6px gold);
}
}
.custom-name-input {
font-size: 24px;
font-weight: bold;
padding: 0;
background: transparent;
color: rgb(239, 230, 216);
}
}
footer {
margin-top: 8px;
display: flex;
gap: 8px;
.activity-body {
button {
flex: 1;
font-style: italic;
}
}
}
&.downtime {
.activity-text-area {
resize: none;
font-family: 'Montserrat', sans-serif;
}
}
}

View file

@ -7,6 +7,14 @@
height: 40px;
width: 100%;
.navigation-container {
display: flex;
align-items: center;
gap: 8px;
.navigation-inner-container {
flex: 1;
.feature-tab {
border: none;
@ -16,4 +24,6 @@
}
}
}
}
}
}

View file

@ -193,5 +193,14 @@
}
}
}
.character-downtime-container {
display: flex;
gap: 2px;
button {
flex: 1;
}
}
}
}

View file

@ -10,7 +10,6 @@
border-color: light-dark(@dark, @beige);
border-radius: 6px;
background-image: url('../assets/parchments/dh-parchment-dark.png');
z-index: 200;
max-height: 400px !important;
width: fit-content !important;
overflow-y: auto;

View file

@ -4,6 +4,20 @@
align-items: center;
gap: 4px;
.tooltip-title-container {
width: 100%;
display: flex;
align-items: center;
gap: 16px;
.tooltip-image {
height: 40px;
width: 40px;
border-radius: 6px;
border: 1px solid @golden;
}
}
.tooltip-title {
margin: 0;
text-align: center;

View file

@ -1,24 +0,0 @@
<div>
<div class="downtime-container">
<h2 class="downtime-header">{{localize "DAGGERHEART.APPLICATIONS.Downtime.downtimeHeader" current=nrCurrentChoices max=moveData.nrChoices}}</h2>
{{#each moveData.moves as |move key|}}
<div class="activity-container">
<div class="activity-title">
<div class="activity-image {{#if this.selected}}selected{{/if}}" data-action="selectMove" data-move="{{key}}">
{{#if this.selected}}<div class="activity-select-label">{{move.selected}}</div>{{/if}}
<img src="{{move.img}}" />
</div>
<span class="activity-title-text">{{localize this.name}}</span>
</div>
<div class="activity-body">
{{localize this.description}}
</div>
</div>
{{/each}}
</div>
<footer class="flexrow">
<button type="button" data-action="close">{{localize "DAGGERHEART.Application.Cancel"}}</button>
<button type="button" data-action="takeDowntime" {{#if this.disabledDowntime}}disabled{{/if}}>{{localize "DAGGERHEART.Application.Downtime.TakeDowntime"}}</button>
</footer>
</div>

View file

@ -0,0 +1,18 @@
<fieldset class="one-column activities-grouping">
<legend>{{localize (concat "DAGGERHEART.APPLICATIONS.Downtime." category ".moves") max=nrChoices.max current=nrChoices.current}}</legend>
<div class="activities-container">
{{#each moves as |move key|}}
<a class="activity-container" data-action="selectMove" data-category="{{../category}}" data-move="{{key}}" data-tooltip="{{concat "#" ../category "#" key}}">
<div class="activity-inner-container">
<i class="{{#if move.selected}}fa-solid{{else}}fa-regular{{/if}} fa-circle activity-marker"></i>
<div class="activity-select-section">
<i class="{{move.icon}} activity-icon"></i>
<div>{{move.name}}</div>
</div>
</div>
{{#if move.selected}}<div class="activity-selected-marker">{{move.selected}}</div>{{/if}}
</a>
{{/each}}
</div>
</fieldset>

View file

@ -0,0 +1,14 @@
<div>
<header class="dialog-header">
<h1>{{title}}</h1>
</header>
<div class="downtime-container {{#if (and shortRestMoves.moves longRestMoves.moves)}}two-columns even{{else}}one-column{{/if}}">
{{#if shortRestMoves.moves}}{{> "systems/daggerheart/templates/dialogs/downtime/activities.hbs" moves=shortRestMoves.moves category='shortRest' nrChoices=nrChoices.shortRest}}{{/if}}
{{#if longRestMoves.moves}}{{> "systems/daggerheart/templates/dialogs/downtime/activities.hbs" moves=longRestMoves.moves category='longRest' nrChoices=nrChoices.longRest}}{{/if}}
</div>
<footer>
<button type="button" data-action="close">{{localize "Cancel"}}</button>
<button type="button" data-action="takeDowntime" {{#if disabledDowntime}}disabled{{/if}}>{{localize "DAGGERHEART.APPLICATIONS.Downtime.takeDowntime"}}</button>
</footer>
</div>

View file

@ -6,7 +6,7 @@
</div>
{{formGroup settingFields.schema.fields.actionPoints value=settingFields._source.actionPoints localize=true}}
s {{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}}
{{formGroup settingFields.schema.fields.hordeDamage value=settingFields._source.hordeDamage localize=true}}
<footer class="form-footer">
<button data-action="reset">

View file

@ -1,18 +1,17 @@
<div>
<div class="form-group">
<label>{{localize "Icon"}}</label>
<div class="form-field">
<input type="text" name="icon" value="{{icon}}" />
</div>
</div>
<fieldset>
<legend>{{localize "Description"}}</legend>
<prose-mirror name="description" value="{{description}}" toggled=true>
<prose-mirror name="description" value="{{description}}">
{{{ enrichedDescription }}}
</prose-mirror>
</fieldset>
{{!-- <fieldset>
<legend>{{localize "Actions"}} <a data-action="addItem"><i class="fa-solid fa-plus"></i></a></legend>
<div class="settings-items">
{{#each this.actions as |action index|}}
{{> "systems/daggerheart/templates/settings/components/settings-item-line.hbs" action type="actions" id=index }}
{{/each}}
</div>
</fieldset> --}}
</div>

View file

@ -116,5 +116,14 @@
{{/each}}
</div>
{{> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
{{#> 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
<div class="character-downtime-container">
<button data-action="useDowntime" data-type="shortRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.shortRest.title"}}">
<i class="fa-solid fa-chair"></i>
</button>
<button data-action="useDowntime" data-type="longRest" data-tooltip="{{localize "DAGGERHEART.APPLICATIONS.Downtime.longRest.title"}}">
<i class="fa-solid fa-bed"></i>
</button>
</div>
{{/'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs'}}
</header>

View file

@ -1,4 +1,6 @@
<section class='tab-navigation'>
<div class='navigation-container'>
<div class="navigation-inner-container">
<line-div></line-div>
<nav class='feature-tab sheet-tabs tabs' data-group='primary'>
{{#each tabs as |tab|}}
@ -8,4 +10,9 @@
{{/each}}
</nav>
<line-div></line-div>
</div>
{{#if @partial-block}}
{{> @partial-block }}
{{/if}}
</div>
</section>

View file

@ -0,0 +1,7 @@
<div class="daggerheart dh-style tooltip">
<div class="tooltip-title-container">
<img class="tooltip-image" src="{{move.img}}" />
<h2 class="tooltip-title">{{move.name}}</h2>
</div>
<div class="tooltip-description">{{{move.description}}}</div>
</div>