mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
* Restructured all the files * Moved build/daggerheart.js to ./daggerheart.js. Changed rollup to use the css file instead of the less * Restored build/ folder * Mvoed config out form under application * Moved roll.mjs to module/dice and renamed to dhRolls.mjs * Update module/canvas/placeables/_module.mjs Co-authored-by: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com> * Le massive export update * Removed unncessary import --------- Co-authored-by: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com>
370 lines
14 KiB
JavaScript
370 lines
14 KiB
JavaScript
import { countdownTypes } from '../../config/generalConfig.mjs';
|
|
import { GMUpdateEvent, RefreshType, socketEvent } from '../../systemRegistration/socket.mjs';
|
|
import constructHTMLButton from '../../helpers/utils.mjs';
|
|
import OwnershipSelection from '../dialogs/ownershipSelection.mjs';
|
|
|
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
|
|
|
class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
|
|
constructor(basePath) {
|
|
super({});
|
|
|
|
this.basePath = basePath;
|
|
}
|
|
|
|
get title() {
|
|
return game.i18n.format('DAGGERHEART.Countdown.Title', {
|
|
type: game.i18n.localize(`DAGGERHEART.Countdown.Types.${this.basePath}`)
|
|
});
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
classes: ['daggerheart', 'dh-style', 'countdown'],
|
|
tag: 'form',
|
|
position: { width: 740, height: 700 },
|
|
window: {
|
|
frame: true,
|
|
title: 'Countdowns',
|
|
resizable: true,
|
|
minimizable: false
|
|
},
|
|
actions: {
|
|
addCountdown: this.addCountdown,
|
|
removeCountdown: this.removeCountdown,
|
|
editImage: this.onEditImage,
|
|
openOwnership: this.openOwnership,
|
|
openCountdownOwnership: this.openCountdownOwnership,
|
|
toggleSimpleView: this.toggleSimpleView
|
|
},
|
|
form: { handler: this.updateData, submitOnChange: true }
|
|
};
|
|
|
|
static PARTS = {
|
|
countdowns: {
|
|
template: 'systems/daggerheart/templates/ui/countdowns.hbs',
|
|
scrollable: ['.expanded-view']
|
|
}
|
|
};
|
|
|
|
_attachPartListeners(partId, htmlElement, options) {
|
|
super._attachPartListeners(partId, htmlElement, options);
|
|
|
|
htmlElement.querySelectorAll('.mini-countdown-container').forEach(element => {
|
|
element.addEventListener('click', event => this.updateCountdownValue.bind(this)(event, false));
|
|
element.addEventListener('contextmenu', event => this.updateCountdownValue.bind(this)(event, true));
|
|
});
|
|
}
|
|
|
|
async _preFirstRender(context, options) {
|
|
options.position =
|
|
game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].position) ??
|
|
Countdowns.DEFAULT_OPTIONS.position;
|
|
|
|
const viewSetting =
|
|
game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].simple) ?? !game.user.isGM;
|
|
this.simpleView =
|
|
game.user.isGM || !this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER) ? viewSetting : true;
|
|
context.simple = this.simpleView;
|
|
}
|
|
|
|
_onPosition(position) {
|
|
game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].position, position);
|
|
}
|
|
|
|
async _renderFrame(options) {
|
|
const frame = await super._renderFrame(options);
|
|
|
|
if (this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER)) {
|
|
const button = constructHTMLButton({
|
|
label: '',
|
|
classes: ['header-control', 'icon', 'fa-solid', 'fa-wrench'],
|
|
dataset: { action: 'toggleSimpleView', tooltip: 'DAGGERHEART.Countdown.ToggleSimple' }
|
|
});
|
|
this.window.controls.after(button);
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
testUserPermission(level, exact, altSettings) {
|
|
if (game.user.isGM) return true;
|
|
|
|
const settings =
|
|
altSettings ?? game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
|
const defaultAllowed = exact ? settings.ownership.default === level : settings.ownership.default >= level;
|
|
const userAllowed = exact
|
|
? settings.playerOwnership[game.user.id]?.value === level
|
|
: settings.playerOwnership[game.user.id]?.value >= level;
|
|
return defaultAllowed || userAllowed;
|
|
}
|
|
|
|
async _prepareContext(_options) {
|
|
const context = await super._prepareContext(_options);
|
|
const countdownData = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[
|
|
this.basePath
|
|
];
|
|
|
|
context.isGM = game.user.isGM;
|
|
context.base = this.basePath;
|
|
|
|
context.canCreate = this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER, true);
|
|
context.source = {
|
|
...countdownData,
|
|
countdowns: Object.keys(countdownData.countdowns).reduce((acc, key) => {
|
|
const countdown = countdownData.countdowns[key];
|
|
|
|
if (this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED, false, countdown)) {
|
|
acc[key] = {
|
|
...countdown,
|
|
canEdit: this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER, true, countdown)
|
|
};
|
|
}
|
|
|
|
return acc;
|
|
}, {})
|
|
};
|
|
context.systemFields = countdownData.schema.fields;
|
|
context.countdownFields = context.systemFields.countdowns.element.fields;
|
|
context.simple = this.simpleView;
|
|
|
|
return context;
|
|
}
|
|
|
|
static async updateData(event, _, formData) {
|
|
const data = foundry.utils.expandObject(formData.object);
|
|
const newSetting = foundry.utils.mergeObject(
|
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).toObject(),
|
|
data
|
|
);
|
|
|
|
if (game.user.isGM) {
|
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, newSetting);
|
|
this.render();
|
|
} else {
|
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
|
action: socketEvent.GMUpdate,
|
|
data: {
|
|
action: GMUpdateEvent.UpdateSetting,
|
|
uuid: CONFIG.DH.SETTINGS.gameSettings.Countdowns,
|
|
update: newSetting
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
async updateSetting(update) {
|
|
if (game.user.isGM) {
|
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, update);
|
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
|
action: socketEvent.Refresh,
|
|
data: {
|
|
refreshType: RefreshType.Countdown,
|
|
application: `${this.basePath}-countdowns`
|
|
}
|
|
});
|
|
|
|
this.render();
|
|
} else {
|
|
await game.socket.emit(`system.${CONFIG.DH.id}`, {
|
|
action: socketEvent.GMUpdate,
|
|
data: {
|
|
action: GMUpdateEvent.UpdateSetting,
|
|
uuid: CONFIG.DH.SETTINGS.gameSettings.Countdowns,
|
|
update: update,
|
|
refresh: { refreshType: RefreshType.Countdown, application: `${this.basePath}-countdowns` }
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
static onEditImage(_, target) {
|
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
|
const current = setting.countdowns[target.dataset.countdown].img;
|
|
const fp = new foundry.applications.apps.FilePicker.implementation({
|
|
current,
|
|
type: 'image',
|
|
callback: async path => this.updateImage.bind(this)(path, target.dataset.countdown),
|
|
top: this.position.top + 40,
|
|
left: this.position.left + 10
|
|
});
|
|
return fp.browse();
|
|
}
|
|
|
|
async updateImage(path, countdown) {
|
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
await setting.updateSource({
|
|
[`${this.basePath}.countdowns.${countdown}.img`]: path
|
|
});
|
|
|
|
await this.updateSetting(setting);
|
|
}
|
|
|
|
static openOwnership(_, target) {
|
|
new Promise((resolve, reject) => {
|
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath];
|
|
const ownership = { default: setting.ownership.default, players: setting.playerOwnership };
|
|
new OwnershipSelection(resolve, reject, this.title, ownership).render(true);
|
|
}).then(async ownership => {
|
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
await setting.updateSource({
|
|
[`${this.basePath}.ownership`]: ownership
|
|
});
|
|
|
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, setting.toObject());
|
|
this.render();
|
|
});
|
|
}
|
|
|
|
static openCountdownOwnership(_, target) {
|
|
const countdownId = target.dataset.countdown;
|
|
new Promise((resolve, reject) => {
|
|
const countdown = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath]
|
|
.countdowns[countdownId];
|
|
const ownership = { default: countdown.ownership.default, players: countdown.playerOwnership };
|
|
new OwnershipSelection(resolve, reject, countdown.name, ownership).render(true);
|
|
}).then(async ownership => {
|
|
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
await setting.updateSource({
|
|
[`${this.basePath}.countdowns.${countdownId}.ownership`]: ownership
|
|
});
|
|
|
|
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, setting);
|
|
this.render();
|
|
});
|
|
}
|
|
|
|
static async toggleSimpleView() {
|
|
this.simpleView = !this.simpleView;
|
|
await game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].simple, this.simpleView);
|
|
this.render();
|
|
}
|
|
|
|
async updateCountdownValue(event, increase) {
|
|
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
const countdown = countdownSetting[this.basePath].countdowns[event.currentTarget.dataset.countdown];
|
|
|
|
if (!this.testUserPermission(CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) {
|
|
return;
|
|
}
|
|
|
|
const currentValue = countdown.progress.current;
|
|
|
|
if (increase && currentValue === countdown.progress.max) return;
|
|
if (!increase && currentValue === 0) return;
|
|
|
|
await countdownSetting.updateSource({
|
|
[`${this.basePath}.countdowns.${event.currentTarget.dataset.countdown}.progress.current`]: increase
|
|
? currentValue + 1
|
|
: currentValue - 1
|
|
});
|
|
|
|
await this.updateSetting(countdownSetting.toObject());
|
|
}
|
|
|
|
static async addCountdown() {
|
|
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
await countdownSetting.updateSource({
|
|
[`${this.basePath}.countdowns.${foundry.utils.randomID()}`]: {
|
|
name: game.i18n.localize('DAGGERHEART.Countdown.NewCountdown'),
|
|
ownership: game.user.isGM
|
|
? {}
|
|
: {
|
|
players: {
|
|
[game.user.id]: { type: CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
await this.updateSetting(countdownSetting.toObject());
|
|
}
|
|
|
|
static async removeCountdown(_, target) {
|
|
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
const countdownName = countdownSetting[this.basePath].countdowns[target.dataset.countdown].name;
|
|
|
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
|
window: {
|
|
title: game.i18n.localize('DAGGERHEART.Countdown.RemoveCountdownTitle')
|
|
},
|
|
content: game.i18n.format('DAGGERHEART.Countdown.RemoveCountdownText', { name: countdownName })
|
|
});
|
|
if (!confirmed) return;
|
|
|
|
await countdownSetting.updateSource({ [`${this.basePath}.countdowns.-=${target.dataset.countdown}`]: null });
|
|
|
|
await this.updateSetting(countdownSetting.toObject());
|
|
}
|
|
|
|
async open() {
|
|
await this.render(true);
|
|
if (
|
|
Object.keys(
|
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath].countdowns
|
|
).length > 0
|
|
) {
|
|
this.minimize();
|
|
}
|
|
}
|
|
}
|
|
|
|
export class NarrativeCountdowns extends Countdowns {
|
|
constructor() {
|
|
super('narrative');
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
id: 'narrative-countdowns'
|
|
};
|
|
}
|
|
|
|
export class EncounterCountdowns extends Countdowns {
|
|
constructor() {
|
|
super('encounter');
|
|
}
|
|
|
|
static DEFAULT_OPTIONS = {
|
|
id: 'encounter-countdowns'
|
|
};
|
|
}
|
|
|
|
export const registerCountdownApplicationHooks = () => {
|
|
const updateCountdowns = async shouldProgress => {
|
|
if (game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).countdowns) {
|
|
const countdownSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
|
|
for (let countdownCategoryKey in countdownSetting) {
|
|
const countdownCategory = countdownSetting[countdownCategoryKey];
|
|
for (let countdownKey in countdownCategory.countdowns) {
|
|
const countdown = countdownCategory.countdowns[countdownKey];
|
|
|
|
if (shouldProgress(countdown)) {
|
|
await countdownSetting.updateSource({
|
|
[`${countdownCategoryKey}.countdowns.${countdownKey}.progress.current`]:
|
|
countdown.progress.current - 1
|
|
});
|
|
await game.settings.set(
|
|
CONFIG.DH.id,
|
|
CONFIG.DH.SETTINGS.gameSettings.Countdowns,
|
|
countdownSetting
|
|
);
|
|
foundry.applications.instances.get(`${countdownCategoryKey}-countdowns`)?.render();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Hooks.on(CONFIG.DH.HOOKS.characterAttack, async () => {
|
|
updateCountdowns(countdown => {
|
|
return (
|
|
countdown.progress.type.value === countdownTypes.characterAttack.id && countdown.progress.current > 0
|
|
);
|
|
});
|
|
});
|
|
|
|
Hooks.on(CONFIG.DH.HOOKS.spotlight, async () => {
|
|
updateCountdowns(countdown => {
|
|
return countdown.progress.type.value === countdownTypes.spotlight.id && countdown.progress.current > 0;
|
|
});
|
|
});
|
|
};
|