[Feature] 613 - Countdown Improvements (#1184)

* Added CountdownEdit view

* Added countdowns UI element

* .

* Fixed migration of countdowns

* .

* .

* style countdown interface, application and ownership dialog

* fix buttons height in ownsership selection

* .

* Added coloured pips to UI cooldowns to signify player visibility if not every player has it

* .

* Added max-height and overflow

* Sync countdown current with max when equal (#1221)

* Update module/applications/ui/countdownEdit.mjs

Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>

* .

---------

Co-authored-by: moliloo <dev.murilobrito@gmail.com>
Co-authored-by: Carlos Fernandez <CarlosFdez@users.noreply.github.com>
This commit is contained in:
WBHarry 2025-10-27 22:24:38 +01:00 committed by GitHub
parent 07cdcf2d78
commit 906c7ac853
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 1024 additions and 498 deletions

View file

@ -1,25 +1,28 @@
import { RefreshType, socketEvent } from '../systemRegistration/socket.mjs';
export default class DhCountdowns extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
/* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */
narrative: new fields.EmbeddedDataField(DhCountdownData),
encounter: new fields.EmbeddedDataField(DhCountdownData)
encounter: new fields.EmbeddedDataField(DhCountdownData),
/**/
countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhCountdown)),
defaultOwnership: new fields.NumberField({
required: true,
choices: CONFIG.DH.GENERAL.basicOwnershiplevels,
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER
})
};
}
static CountdownCategories = { narrative: 'narrative', combat: 'combat' };
}
/* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */
class DhCountdownData extends foundry.abstract.DataModel {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.APPLICATIONS.Countdown']; // Nots ure why this won't work. Setting labels manually for now
static defineSchema() {
const fields = foundry.data.fields;
return {
countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhCountdown)),
countdowns: new fields.TypedObjectField(new fields.EmbeddedDataField(DhOldCountdown)),
ownership: new fields.SchemaField({
default: new fields.NumberField({
required: true,
@ -56,7 +59,8 @@ class DhCountdownData extends foundry.abstract.DataModel {
}
}
class DhCountdown extends foundry.abstract.DataModel {
/* Outdated and unused. Needed for migration. Remove in next minor version. (1.3) */
class DhOldCountdown extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
@ -129,17 +133,88 @@ class DhCountdown extends foundry.abstract.DataModel {
}
}
export const registerCountdownHooks = () => {
Hooks.on(socketEvent.Refresh, ({ refreshType, application }) => {
if (refreshType === RefreshType.Countdown) {
if (application) {
foundry.applications.instances.get(application)?.render();
} else {
foundry.applications.instances.get('narrative-countdowns')?.render();
foundry.applications.instances.get('encounter-countdowns')?.render();
}
export class DhCountdown extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
type: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.countdownBaseTypes,
label: 'DAGGERHEART.GENERAL.type'
}),
name: new fields.StringField({
required: true,
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.name.label'
}),
img: new fields.FilePathField({
categories: ['IMAGE'],
base64: false,
initial: 'icons/magic/time/hourglass-yellow-green.webp'
}),
ownership: new fields.TypedObjectField(
new fields.NumberField({
required: true,
choices: CONFIG.DH.GENERAL.simpleOwnershiplevels,
initial: CONST.DOCUMENT_OWNERSHIP_LEVELS.INHERIT
})
),
progress: new fields.SchemaField({
current: new fields.NumberField({
required: true,
integer: true,
initial: 1,
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.current.label'
}),
max: new fields.NumberField({
required: true,
integer: true,
initial: 1,
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.progress.max.label'
}),
type: new fields.StringField({
required: true,
choices: CONFIG.DH.GENERAL.countdownTypes,
initial: CONFIG.DH.GENERAL.countdownTypes.custom.id,
label: 'DAGGERHEART.APPLICATIONS.Countdown.FIELDS.countdowns.element.type.label'
})
})
};
}
return false;
}
});
};
static defaultCountdown(type, playerHidden) {
const ownership = playerHidden
? game.users.reduce((acc, user) => {
if (!user.isGM) {
acc[user.id] = CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE;
}
return acc;
}, {})
: undefined;
return {
type: type ?? CONFIG.DH.GENERAL.countdownBaseTypes.narrative.id,
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Countdown.newCountdown'),
img: 'icons/magic/time/hourglass-yellow-green.webp',
ownership: ownership,
progress: {
current: 1,
max: 1
}
};
}
get playerOwnership() {
return Array.from(game.users).reduce((acc, user) => {
acc[user.id] = {
value: user.isGM
? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER
: this.ownership.players[user.id] && this.ownership.players[user.id].type !== -1
? this.ownership.players[user.id].type
: this.ownership.default,
isGM: user.isGM
};
return acc;
}, {});
}
}