Added the shell of the Countdown application

This commit is contained in:
WBHarry 2025-06-09 08:28:59 +02:00
parent 7799f4f1eb
commit db7ecf0c2f
8 changed files with 197 additions and 0 deletions

View file

@ -13,6 +13,8 @@ import { dualityRollEnricher } from './module/enrichers/DualityRollEnricher.mjs'
import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs'; import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs';
import { abilities } from './module/config/actorConfig.mjs'; import { abilities } from './module/config/actorConfig.mjs';
import Resources from './module/applications/resources.mjs'; import Resources from './module/applications/resources.mjs';
import Countdowns from './module/applications/countdowns.mjs';
import DhCountdowns from './module/data/countdowns.mjs';
globalThis.SYSTEM = SYSTEM; globalThis.SYSTEM = SYSTEM;
@ -96,6 +98,7 @@ Hooks.once('init', () => {
CONFIG.Token.rulerClass = DhpTokenRuler; CONFIG.Token.rulerClass = DhpTokenRuler;
CONFIG.ui.resources = Resources; CONFIG.ui.resources = Resources;
CONFIG.ui.countdowns = Countdowns;
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent); game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent);
@ -111,6 +114,9 @@ Hooks.once('init', () => {
Hooks.on('ready', () => { Hooks.on('ready', () => {
ui.resources = new CONFIG.ui.resources(); ui.resources = new CONFIG.ui.resources();
ui.resources.render({ force: true }); ui.resources.render({ force: true });
/* Temporary for ease of development. Countdown application should be opened through buttons somewhere */
new CONFIG.ui.countdowns(DhCountdowns.CountdownCategories.narrative).render({ force: true });
}); });
Hooks.once('dicesoniceready', () => {}); Hooks.once('dicesoniceready', () => {});

View file

@ -893,6 +893,29 @@
"Title": "Downtime" "Title": "Downtime"
} }
}, },
"Countdown": {
"FIELDS": {
"countdowns": {
"element": {
"name": { "label": "Name" },
"progress": {
"current": { "label": "Current" },
"max": { "label": "Max" },
"type": {
"value": { "label": "Value" },
"label": { "label": "Label", "hint": "Used for custom" }
}
}
}
}
},
"Type": {
"Spotlight": "Spotlight",
"Custom": "Custom"
},
"NewCountdown": "New Countdown",
"Title": "Countdowns"
},
"Sheets": { "Sheets": {
"PC": { "PC": {
"Name": "Name", "Name": "Name",

View file

@ -0,0 +1,74 @@
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(basePath) {
super();
this.basePath = basePath;
}
static DEFAULT_OPTIONS = {
id: 'countdown',
classes: [],
tag: 'form',
window: {
frame: true,
title: 'Countdowns',
resizable: true,
minimizable: true
},
actions: {
addCountdown: this.addCountdown,
removeCountdown: this.removeCountdown
},
form: { handler: this.updateData, submitOnChange: true }
};
static PARTS = {
countdowns: {
template: 'systems/daggerheart/templates/views/countdowns.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
const countdownData = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
context.base = this.basePath;
context.source = countdownData.toObject();
context.systemFields = countdownData.schema.fields;
context.countdownFields = context.systemFields.countdowns.element.fields;
return context;
}
static async updateData(event, _, formData) {
const data = foundry.utils.expandObject(formData.object);
const newSetting = foundry.utils.mergeObject(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns).toObject(),
data
);
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, newSetting);
this.render();
}
static async addCountdown() {
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
await countdownSetting.updateSource({
[`${this.basePath}.countdowns.${foundry.utils.randomID()}`]: {
name: game.i18n.localize('DAGGERHEART.Countdown.NewCountdown')
}
});
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, countdownSetting.toObject());
this.render();
}
static async removeCountdown(_, target) {
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
await countdownSetting.updateSource({ [`${this.basePath}.countdowns.-=${target.dataset.countdown}`]: null });
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, countdownSetting.toObject());
this.render();
}
}

View file

@ -4,6 +4,7 @@ import DhAppearance from '../data/settings/Appearance.mjs';
import DHAppearanceSettings from './settings/appearanceSettings.mjs'; import DHAppearanceSettings from './settings/appearanceSettings.mjs';
import DhVariantRules from '../data/settings/VariantRules.mjs'; import DhVariantRules from '../data/settings/VariantRules.mjs';
import DHVariantRuleSettings from './settings/variantRuleSettings.mjs'; import DHVariantRuleSettings from './settings/variantRuleSettings.mjs';
import DhCountdowns from '../data/countdowns.mjs';
class DhpAutomationSettings extends FormApplication { class DhpAutomationSettings extends FormApplication {
constructor(object = {}, options = {}) { constructor(object = {}, options = {}) {
@ -287,6 +288,12 @@ export const registerDHSettings = () => {
default: defaultLevelTiers default: defaultLevelTiers
}); });
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, {
scope: 'world',
config: false,
type: DhCountdowns
});
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, { game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Name'), name: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Name'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Label'), label: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Label'),

View file

@ -311,3 +311,14 @@ export const abilityCosts = {
label: 'Stress' label: 'Stress'
} }
}; };
export const countdownTypes = {
spotlight: {
id: 'spotlight',
label: 'DAGGERHEART.Countdown.Type.Spotlight'
},
custom: {
id: 'custom',
label: 'DAGGERHEART.Countdown.Type.Custom'
}
};

View file

@ -33,6 +33,7 @@ export const gameSettings = {
}, },
DualityRollColor: 'DualityRollColor', DualityRollColor: 'DualityRollColor',
LevelTiers: 'LevelTiers', LevelTiers: 'LevelTiers',
Countdowns: 'Countdowns',
appearance: 'Appearance', appearance: 'Appearance',
variantRules: 'VariantRules' variantRules: 'VariantRules'
}; };

View file

@ -0,0 +1,62 @@
import { countdownTypes } from '../config/generalConfig.mjs';
export default class DhCountdowns extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
narrative: new fields.EmbeddedDataField(DhCountdownData),
combat: new fields.EmbeddedDataField(DhCountdownData)
};
}
static CountdownCategories = { narrative: 'narrative', combat: 'combat' };
}
class DhCountdownData extends foundry.abstract.DataModel {
static LOCALIZATION_PREFIXES = ['DAGGERHEART.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))
};
}
}
class DhCountdown extends foundry.abstract.DataModel {
static defineSchema() {
const fields = foundry.data.fields;
return {
name: new fields.StringField({
required: true,
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.name.label'
}),
progress: new fields.SchemaField({
current: new fields.NumberField({
required: true,
integer: true,
initial: 0,
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.current.label'
}),
max: new fields.NumberField({
required: true,
integer: true,
initial: 0,
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.max.label'
}),
type: new fields.SchemaField({
value: new fields.StringField({
required: true,
choices: countdownTypes,
initial: countdownTypes.spotlight.id,
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.type.value.label'
}),
label: new fields.StringField({
label: 'DAGGERHEART.Countdown.FIELDS.countdowns.element.progress.type.label.label'
})
})
})
};
}
}

View file

@ -0,0 +1,13 @@
<div>
<div>{{localize "DAGGERHEART.Countdown.Title"}} <a><i class="fa-solid fa-plus icon-button" data-action="addCountdown"></i></a></div>
{{#each source.countdowns}}
<fieldset>
<legend>{{this.name}} <a><i class="fa-solid fa-trash icon-button" data-action="removeCountdown" data-countdown="{{@key}}"></i></a></legend>
{{formGroup @root.countdownFields.name name=(concat @root.base ".countdowns." @key ".name") value=this.name localize=true}}
{{formGroup @root.countdownFields.progress.fields.current name=(concat @root.base ".countdowns." @key ".progress.current") value=this.progress.current localize=true}}
{{formGroup @root.countdownFields.progress.fields.type.fields.value name=(concat @root.base ".countdowns." @key ".progress.type.value") value=this.progress.type.value localize=true localize=true}}
</fieldset>
{{/each}}
</div>