mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
[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:
parent
0cc1597dfe
commit
6e87e4dad0
25 changed files with 390 additions and 152 deletions
32
lang/en.json
32
lang/en.json
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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 }),
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -32,19 +32,19 @@ 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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,81 +1,75 @@
|
|||
@import '../../utils/spacing.less';
|
||||
@import '../../utils/colors.less';
|
||||
|
||||
.daggerheart.views {
|
||||
.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 {
|
||||
.downtime-header {
|
||||
margin: 0;
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
text-align: center;
|
||||
.activities-grouping {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.activity-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
.activities-container {
|
||||
width: 100%;
|
||||
|
||||
.activity-title {
|
||||
flex: 1;
|
||||
.activity-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 8px;
|
||||
|
||||
.activity-title-text {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.activity-image {
|
||||
width: 80px;
|
||||
position: relative;
|
||||
.activity-inner-container {
|
||||
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;
|
||||
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);
|
||||
padding: 0 8px;
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
.activity-marker {
|
||||
font-size: 8px;
|
||||
flex: none;
|
||||
color: light-dark(#18162e, #f3c267);
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
}
|
||||
.activity-select-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
&:hover,
|
||||
&.selected {
|
||||
filter: drop-shadow(0 0 6px gold);
|
||||
.activity-icon {
|
||||
min-width: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.custom-name-input {
|
||||
font-size: 24px;
|
||||
.activity-selected-marker {
|
||||
font-size: 14px;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
color: light-dark(@dark, @beige);
|
||||
background-image: url(../assets/parchments/dh-parchment-dark.png);
|
||||
padding: 0 8px;
|
||||
line-height: 1;
|
||||
font-weight: bold;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: rgb(239, 230, 216);
|
||||
}
|
||||
}
|
||||
|
||||
.activity-body {
|
||||
flex: 1;
|
||||
font-style: italic;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.downtime {
|
||||
.activity-text-area {
|
||||
resize: none;
|
||||
footer {
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
font-family: 'Montserrat', sans-serif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,22 @@
|
|||
height: 40px;
|
||||
width: 100%;
|
||||
|
||||
.feature-tab {
|
||||
border: none;
|
||||
.navigation-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
a {
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
font-family: @font-body;
|
||||
.navigation-inner-container {
|
||||
flex: 1;
|
||||
|
||||
.feature-tab {
|
||||
border: none;
|
||||
|
||||
a {
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
font-family: @font-body;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,5 +193,14 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.character-downtime-container {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
18
templates/dialogs/downtime/activities.hbs
Normal file
18
templates/dialogs/downtime/activities.hbs
Normal 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>
|
||||
14
templates/dialogs/downtime/downtime.hbs
Normal file
14
templates/dialogs/downtime/downtime.hbs
Normal 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>
|
||||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -1,11 +1,18 @@
|
|||
<section class='tab-navigation'>
|
||||
<line-div></line-div>
|
||||
<nav class='feature-tab sheet-tabs tabs' data-group='primary'>
|
||||
{{#each tabs as |tab|}}
|
||||
<a class='{{tab.id}} {{tab.cssClass}}' data-action='tab' data-group='{{tab.group}}' data-tab='{{tab.id}}'>
|
||||
{{localize tab.label}}
|
||||
</a>
|
||||
{{/each}}
|
||||
</nav>
|
||||
<line-div></line-div>
|
||||
<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|}}
|
||||
<a class='{{tab.id}} {{tab.cssClass}}' data-action='tab' data-group='{{tab.group}}' data-tab='{{tab.id}}'>
|
||||
{{localize tab.label}}
|
||||
</a>
|
||||
{{/each}}
|
||||
</nav>
|
||||
<line-div></line-div>
|
||||
</div>
|
||||
{{#if @partial-block}}
|
||||
{{> @partial-block }}
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
7
templates/ui/tooltip/downtime.hbs
Normal file
7
templates/ui/tooltip/downtime.hbs
Normal 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue