Merge branch 'development' into feature/313-preset-measured-templates

This commit is contained in:
Chris Ryan 2025-11-09 20:19:32 +10:00
commit dbafd4b781
199 changed files with 3921 additions and 736 deletions

View file

@ -2,7 +2,7 @@ import autocomplete from 'autocompleter';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class AttriubtionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
export default class AttributionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(item) {
super({});

View file

@ -10,7 +10,9 @@ export default class AdversarySheet extends DHBaseActorSheet {
position: { width: 660, height: 766 },
window: { resizable: true },
actions: {
reactionRoll: AdversarySheet.#reactionRoll
reactionRoll: AdversarySheet.#reactionRoll,
toggleResourceDice: AdversarySheet.#toggleResourceDice,
handleResourceDice: AdversarySheet.#handleResourceDice
},
window: {
resizable: true,
@ -25,6 +27,10 @@ export default class AdversarySheet extends DHBaseActorSheet {
};
static PARTS = {
limited: {
template: 'systems/daggerheart/templates/sheets/actors/adversary/limited.hbs',
scrollable: ['.limited-container']
},
sidebar: {
template: 'systems/daggerheart/templates/sheets/actors/adversary/sidebar.hbs',
scrollable: ['.shortcut-items-section']
@ -52,6 +58,18 @@ export default class AdversarySheet extends DHBaseActorSheet {
}
};
/** @inheritdoc */
_initializeApplicationOptions(options) {
const applicationOptions = super._initializeApplicationOptions(options);
if (applicationOptions.document.testUserPermission(game.user, 'LIMITED', { exact: true })) {
applicationOptions.position.width = 360;
applicationOptions.position.height = 'auto';
}
return applicationOptions;
}
/**@inheritdoc */
async _prepareContext(options) {
const context = await super._prepareContext(options);
@ -65,6 +83,7 @@ export default class AdversarySheet extends DHBaseActorSheet {
context = await super._preparePartContext(partId, context, options);
switch (partId) {
case 'header':
case 'limited':
await this._prepareHeaderContext(context, options);
const adversaryTypes = CONFIG.DH.ACTOR.allAdversaryTypes();
@ -156,6 +175,40 @@ export default class AdversarySheet extends DHBaseActorSheet {
this.actor.diceRoll(config);
}
/**
* Toggle the used state of a resource dice.
* @type {ApplicationClickAction}
*/
static async #toggleResourceDice(event, target) {
const item = await getDocFromElement(target);
const { dice } = event.target.closest('.item-resource').dataset;
const diceState = item.system.resource.diceStates[dice];
await item.update({
[`system.resource.diceStates.${dice}.used`]: diceState ? !diceState.used : true
});
}
/**
* Handle the roll values of resource dice.
* @type {ApplicationClickAction}
*/
static async #handleResourceDice(_, target) {
const item = await getDocFromElement(target);
if (!item) return;
const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create(item, this.document);
if (!rollValues) return;
await item.update({
'system.resource.diceStates': rollValues.reduce((acc, state, index) => {
acc[index] = { value: state.value, used: state.used };
return acc;
}, {})
});
}
/* -------------------------------------------- */
/* Application Listener Actions */
/* -------------------------------------------- */

View file

@ -76,6 +76,11 @@ export default class CharacterSheet extends DHBaseActorSheet {
/**@override */
static PARTS = {
limited: {
id: 'limited',
scrollable: ['.limited-container'],
template: 'systems/daggerheart/templates/sheets/actors/character/limited.hbs'
},
sidebar: {
id: 'sidebar',
scrollable: ['.shortcut-items-section'],
@ -141,23 +146,37 @@ export default class CharacterSheet extends DHBaseActorSheet {
});
}
/** @inheritdoc */
_initializeApplicationOptions(options) {
const applicationOptions = super._initializeApplicationOptions(options);
if (applicationOptions.document.testUserPermission(game.user, 'LIMITED', { exact: true })) {
applicationOptions.position.width = 360;
applicationOptions.position.height = 'auto';
}
return applicationOptions;
}
/** @inheritDoc */
async _onRender(context, options) {
await super._onRender(context, options);
this.element
.querySelector('.level-value')
?.addEventListener('change', event => this.document.updateLevel(Number(event.currentTarget.value)));
if (!this.document.testUserPermission(game.user, 'LIMITED', { exact: true })) {
this.element
.querySelector('.level-value')
?.addEventListener('change', event => this.document.updateLevel(Number(event.currentTarget.value)));
const observer = this.document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER, {
exact: true
});
if (observer) {
this.element.querySelector('.window-content').classList.add('viewMode');
const observer = this.document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER, {
exact: true
});
if (observer) {
this.element.querySelector('.window-content').classList.add('viewMode');
}
this._createFilterMenus();
this._createSearchFilter();
}
this._createFilterMenus();
this._createSearchFilter();
}
/* -------------------------------------------- */

View file

@ -14,6 +14,10 @@ export default class DhCompanionSheet extends DHBaseActorSheet {
};
static PARTS = {
limited: {
template: 'systems/daggerheart/templates/sheets/actors/companion/limited.hbs',
scrollable: ['.limited-container']
},
header: { template: 'systems/daggerheart/templates/sheets/actors/companion/header.hbs' },
details: { template: 'systems/daggerheart/templates/sheets/actors/companion/details.hbs' },
effects: {

View file

@ -1,3 +1,4 @@
import { getDocFromElement } from '../../../helpers/utils.mjs';
import DHBaseActorSheet from '../api/base-actor.mjs';
/**@typedef {import('@client/applications/_types.mjs').ApplicationClickAction} ApplicationClickAction */
@ -20,12 +21,19 @@ export default class DhpEnvironment extends DHBaseActorSheet {
}
]
},
actions: {},
actions: {
toggleResourceDice: DhpEnvironment.#toggleResourceDice,
handleResourceDice: DhpEnvironment.#handleResourceDice
},
dragDrop: [{ dragSelector: '.action-section .inventory-item', dropSelector: null }]
};
/**@override */
static PARTS = {
limited: {
template: 'systems/daggerheart/templates/sheets/actors/environment/limited.hbs',
scrollable: ['.limited-container']
},
header: { template: 'systems/daggerheart/templates/sheets/actors/environment/header.hbs' },
features: {
template: 'systems/daggerheart/templates/sheets/actors/environment/features.hbs',
@ -47,6 +55,18 @@ export default class DhpEnvironment extends DHBaseActorSheet {
}
};
/** @inheritdoc */
_initializeApplicationOptions(options) {
const applicationOptions = super._initializeApplicationOptions(options);
if (applicationOptions.document.testUserPermission(game.user, 'LIMITED', { exact: true })) {
applicationOptions.position.width = 360;
applicationOptions.position.height = 'auto';
}
return applicationOptions;
}
/**@inheritdoc */
async _preparePartContext(partId, context, options) {
context = await super._preparePartContext(partId, context, options);
@ -118,4 +138,44 @@ export default class DhpEnvironment extends DHBaseActorSheet {
event.dataTransfer.setDragImage(item, 60, 0);
}
}
/* -------------------------------------------- */
/* Application Clicks Actions */
/* -------------------------------------------- */
/**
* Toggle the used state of a resource dice.
* @type {ApplicationClickAction}
*/
static async #toggleResourceDice(event, target) {
const item = await getDocFromElement(target);
const { dice } = event.target.closest('.item-resource').dataset;
const diceState = item.system.resource.diceStates[dice];
await item.update({
[`system.resource.diceStates.${dice}.used`]: diceState ? !diceState.used : true
});
}
/**
* Handle the roll values of resource dice.
* @type {ApplicationClickAction}
*/
static async #handleResourceDice(_, target) {
const item = await getDocFromElement(target);
if (!item) return;
const rollValues = await game.system.api.applications.dialogs.ResourceDiceDialog.create(item, this.document);
if (!rollValues) return;
await item.update({
'system.resource.diceStates': rollValues.reduce((acc, state, index) => {
acc[index] = { value: state.value, used: state.used };
return acc;
}, {})
});
}
}

View file

@ -47,6 +47,12 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
return (this.#settingSheet ??= SheetClass ? new SheetClass({ document: this.document }) : null);
}
get isVisible() {
const viewPermission = this.document.testUserPermission(game.user, this.options.viewPermission);
const limitedOnly = this.document.testUserPermission(game.user, this.options.viewPermission, { exact: true });
return limitedOnly ? this.document.system.metadata.hasLimitedView : viewPermission;
}
/* -------------------------------------------- */
/* Prepare Context */
/* -------------------------------------------- */
@ -72,6 +78,31 @@ export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
return context;
}
_configureRenderParts(options) {
const parts = super._configureRenderParts(options);
if (!this.document.system.metadata.hasLimitedView) return parts;
if (this.document.testUserPermission(game.user, 'LIMITED', { exact: true })) return { limited: parts.limited };
return Object.keys(parts).reduce((acc, key) => {
if (key !== 'limited') acc[key] = parts[key];
return acc;
}, {});
}
/** @inheritDoc */
async _onRender(context, options) {
await super._onRender(context, options);
if (
this.document.system.metadata.hasLimitedView &&
this.document.testUserPermission(game.user, 'LIMITED', { exact: true })
) {
this.element.classList = `${this.element.classList} limited`;
}
}
/**@inheritdoc */
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);

View file

@ -39,7 +39,8 @@ export default class DhSidebar extends foundry.applications.sidebar.Sidebar {
},
daggerheartMenu: {
tooltip: 'DAGGERHEART.UI.Sidebar.daggerheartMenu.title',
img: 'systems/daggerheart/assets/logos/FoundryBorneLogoWhite.svg'
img: 'systems/daggerheart/assets/logos/FoundryBorneLogoWhite.svg',
gmOnly: true
},
settings: {
tooltip: 'SIDEBAR.TabSettings',

View file

@ -29,8 +29,7 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract
},
actions: {
selectRefreshable: DaggerheartMenu.#selectRefreshable,
refreshActors: DaggerheartMenu.#refreshActors,
editCountdowns: DaggerheartMenu.#editCountdowns
refreshActors: DaggerheartMenu.#refreshActors
}
};
@ -158,8 +157,4 @@ export default class DaggerheartMenu extends HandlebarsApplicationMixin(Abstract
this.render();
}
static async #editCountdowns() {
new game.system.api.applications.ui.CountdownEdit().render(true);
}
}

View file

@ -32,6 +32,7 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
},
actions: {
toggleViewMode: DhCountdowns.#toggleViewMode,
editCountdowns: DhCountdowns.#editCountdowns,
decreaseCountdown: (_, target) => this.editCountdown(false, target),
increaseCountdown: (_, target) => this.editCountdown(true, target)
},
@ -67,6 +68,12 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
const header = frame.querySelector('.window-header');
header.querySelector('button[data-action="close"]').remove();
if (game.user.isGM) {
const editTooltip = game.i18n.localize('DAGGERHEART.APPLICATIONS.CountdownEdit.editTitle');
const editButton = `<a style="margin-right: 8px;" class="header-control" data-tooltip="${editTooltip}" aria-label="${editTooltip}" data-action="editCountdowns"><i class="fa-solid fa-wrench"></i></a>`;
header.insertAdjacentHTML('beforeEnd', editButton);
}
const minimizeTooltip = game.i18n.localize('DAGGERHEART.UI.Countdowns.toggleIconMode');
const minimizeButton = `<a class="header-control" data-tooltip="${minimizeTooltip}" aria-label="${minimizeTooltip}" data-action="toggleViewMode"><i class="fa-solid fa-down-left-and-up-right-to-center"></i></a>`;
header.insertAdjacentHTML('beforeEnd', minimizeButton);
@ -149,6 +156,10 @@ export default class DhCountdowns extends HandlebarsApplicationMixin(Application
this.render();
}
static async #editCountdowns() {
new game.system.api.applications.ui.CountdownEdit().render(true);
}
static async editCountdown(increase, target) {
if (!DhCountdowns.canPerformEdit()) return;