File Structure Rework (#262)

* 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>
This commit is contained in:
WBHarry 2025-07-05 00:26:33 +02:00 committed by GitHub
parent 099a4576da
commit 9d76405221
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
203 changed files with 1556 additions and 2565 deletions

View file

@ -1,22 +1,8 @@
export { default as DhCharacterSheet } from './sheets/actors/character.mjs';
export { default as DhpAdversarySheet } from './sheets/actors/adversary.mjs';
export { default as DhCompanionSheet } from './sheets/actors/companion.mjs';
export { default as DhpClassSheet } from './sheets/items/class.mjs';
export { default as DhpSubclass } from './sheets/items/subclass.mjs';
export { default as DhpFeatureSheet } from './sheets/items/feature.mjs';
export { default as DhpDomainCardSheet } from './sheets/items/domainCard.mjs';
export { default as DhpAncestry } from './sheets/items/ancestry.mjs';
export { default as DhpCommunity } from './sheets/items/community.mjs';
export { default as DhpMiscellaneous } from './sheets/items/miscellaneous.mjs';
export { default as DhpConsumable } from './sheets/items/consumable.mjs';
export { default as DhpWeapon } from './sheets/items/weapon.mjs';
export { default as DhpArmor } from './sheets/items/armor.mjs';
export { default as DhpChatMessage } from './chatMessage.mjs';
export { default as DhpEnvironment } from './sheets/actors/environment.mjs';
export { default as DhActiveEffectConfig } from './sheets/activeEffectConfig.mjs';
export { default as DhContextMenu } from './contextMenu.mjs';
export { default as DhBeastform } from './sheets/items/beastform.mjs';
export { default as DhTooltipManager } from './tooltipManager.mjs';
export * as api from './sheets/api/_modules.mjs';
export * as characterCreation from './characterCreation/_module.mjs';
export * as dialogs from './dialogs/_module.mjs';
export * as levelup from './levelup/_module.mjs';
export * as settings from './settings/_module.mjs';
export * as sheets from './sheets/_module.mjs';
export * as sheetConfigs from './sheets-configs/_module.mjs';
export * as ui from './ui/_module.mjs';
export * as ux from './ux/_module.mjs';

View file

@ -1,250 +0,0 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(resolve) {
super({});
this.resolve = resolve;
this.data = {
ancestries: [],
features: [],
ancestryInfo: {
name: '',
img: null,
customImg: 'icons/svg/mystery-man.svg',
description: ''
}
};
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'views', 'ancestry-selection'],
position: {
width: 800,
height: 'auto'
},
actions: {
selectAncestry: this.selectAncestry,
selectFeature: this.selectFeature,
viewItem: this.viewItem,
selectImage: this.selectImage,
editImage: this._onEditImage,
saveAncestry: this.saveAncestry
},
form: {
submitOnChange: true,
closeOnSubmit: false
}
};
/** @override */
static PARTS = {
damageSelection: {
id: 'ancestrySelection',
template: 'systems/daggerheart/templates/views/ancestrySelection.hbs'
}
};
/* -------------------------------------------- */
/** @inheritDoc */
get title() {
return `Ancestry Selection`;
}
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
const ancestryNameInput = $(htmlElement).find('.ancestry-name');
if (ancestryNameInput.length > 0) {
ancestryNameInput.on('change', this.setName.bind(this));
$(htmlElement).find('.ancestry-description').on('change', this.setDescription.bind(this));
}
// $(htmlElement).find(".ancestry-image").on("change", this.selectImage.bind(this));
}
async _prepareContext(_options) {
const systemAncestries = Array.from((await game.packs.get('daggerheart.ancestries')).index).map(x => ({
...x,
selected: this.data.ancestries.some(selected => selected.uuid === x.uuid)
}));
const customAncestries = game.items.reduce((acc, x) => {
if (x.type === 'ancestry') {
acc.push({
...x,
uuid: x.uuid,
selected: this.data.ancestries.some(selected => selected.uuid === x.uuid)
});
}
return acc;
}, []);
const ancestryFeatures = this.data.ancestries.flatMap(x =>
x.system.abilities.map(x => ({
...x,
selected: this.data.features.some(selected => selected.uuid === x.uuid)
}))
);
return {
systemAncestries,
customAncestries,
ancestryFeatures,
selectedAncestries: this.data.ancestries,
selectedFeatures: this.data.features,
ancestryInfo: this.data.ancestryInfo
};
}
static async selectAncestry(_, button) {
const newAncestries = [...this.data.ancestries];
if (!newAncestries.findSplice(x => x.uuid === button.dataset.uuid) && this.data.ancestries.length < 2) {
const ancestry = await fromUuid(button.dataset.uuid);
newAncestries.push(ancestry);
}
this.data.ancestries = newAncestries;
this.data.features = newAncestries.length === 1 ? newAncestries[0].system.abilities : [];
this.render(true);
}
static async selectFeature(_, button) {
const newFeatures = [...this.data.features];
if (!newFeatures.findSplice(x => x.uuid === button.dataset.uuid) && this.data.features.length < 2) {
const feature = await fromUuid(button.dataset.uuid);
newFeatures.push(feature);
}
this.data.features = newFeatures;
this.render(true);
}
static async viewItem(_, button) {
(await fromUuid(button.dataset.uuid)).sheet.render(true);
}
setName(event) {
this.data.ancestryInfo.name = event.currentTarget.value;
this.render(true);
}
setDescription(event) {
this.data.ancestryInfo.description = event.currentTarget.value;
this.render(true);
}
static selectImage(_, button) {
this.data.ancestryInfo.img = button.dataset.img;
this.render(true);
}
static _onEditImage() {
const fp = new foundry.applications.apps.FilePicker.implementation({
current: this.data.ancestryInfo.img,
type: 'image',
redirectToRoot: ['icons/svg/mystery-man.svg'],
callback: async path => this._updateImage.bind(this)(path),
top: this.position.top + 40,
left: this.position.left + 10
});
return fp.browse();
}
_updateImage(path) {
this.data.ancestryInfo.customImg = path;
this.data.ancestryInfo.img = path;
this.render(true);
}
static async saveAncestry(_, button) {
if (this.data.ancestries.length === 2) {
const { name, img, description } = this.data.ancestryInfo;
this.resolve({
data: {
name: name,
img: img,
type: 'ancestry',
system: {
description: description,
abilities: this.data.features.map(x => ({
name: x.name,
img: x.img,
uuid: x.uuid,
subclassLevel: ''
}))
}
}
});
} else {
this.resolve({ data: this.data.ancestries[0].toObject() });
}
this.close();
}
}
// export default class DamageSelectionDialog extends FormApplication {
// constructor(rollString, bonusDamage, resolve){
// super({}, {});
// this.data = {
// rollString,
// bonusDamage: bonusDamage.map(x => ({
// ...x,
// hopeUses: 0
// })),
// }
// this.resolve = resolve;
// }
// get title (){
// return 'Damage Options';
// }
// static get defaultOptions() {
// const defaults = super.defaultOptions;
// const overrides = {
// height: 'auto',
// width: 400,
// id: 'damage-selection',
// template: 'systems/daggerheart/templates/views/damageSelection.hbs',
// closeOnSubmit: false,
// classes: ["daggerheart", "views", "damage-selection"],
// };
// const mergedOptions = foundry.utils.mergeObject(defaults, overrides);
// return mergedOptions;
// }
// async getData(){
// const context = super.getData();
// context.rollString = this.data.rollString;
// context.bonusDamage = this.data.bonusDamage;
// return context;
// }
// activateListeners(html) {
// super.activateListeners(html);
// html.find('.roll-button').click(this.finish.bind(this));
// html.find('.').change();
// }
// // async _updateObject(_, formData) {
// // const data = foundry.utils.expandObject(formData);
// // this.data = foundry.utils.mergeObject(this.data, data);
// // this.render(true);
// // }
// finish(){
// this.resolve(this.data);
// this.close();
// }
// }

View file

@ -0,0 +1 @@
export { default as CharacterCreation } from './characterCreation.mjs';

View file

@ -1,5 +1,5 @@
import { abilities } from '../config/actorConfig.mjs';
import { burden } from '../config/generalConfig.mjs';
import { abilities } from '../../config/actorConfig.mjs';
import { burden } from '../../config/generalConfig.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -74,11 +74,11 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
};
static PARTS = {
tabs: { template: 'systems/daggerheart/templates/views/characterCreation/tabs.hbs' },
setup: { template: 'systems/daggerheart/templates/views/characterCreation/tabs/setup.hbs' },
equipment: { template: 'systems/daggerheart/templates/views/characterCreation/tabs/equipment.hbs' },
// story: { template: 'systems/daggerheart/templates/views/characterCreation/tabs/story.hbs' },
footer: { template: 'systems/daggerheart/templates/views/characterCreation/footer.hbs' }
tabs: { template: 'systems/daggerheart/templates/characterCreation/tabs.hbs' },
setup: { template: 'systems/daggerheart/templates/characterCreation/tabs/setup.hbs' },
equipment: { template: 'systems/daggerheart/templates/characterCreation/tabs/equipment.hbs' },
// story: { template: 'systems/daggerheart/templates/characterCreation/tabs/story.hbs' },
footer: { template: 'systems/daggerheart/templates/characterCreation/footer.hbs' }
};
static TABS = {
@ -176,7 +176,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
switch (partId) {
case 'setup':
const availableTraitModifiers = game.settings
.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew)
.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew)
.traitArray.map(trait => ({ key: trait, name: trait }));
for (let trait of Object.values(this.setup.traits).filter(x => x.value !== null)) {
const index = availableTraitModifiers.findIndex(x => x.key === trait.value);
@ -396,7 +396,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
const item = await foundry.utils.fromUuid(data.uuid);
if (item.type === 'ancestry' && event.target.closest('.ancestry-card')) {
this.setup.ancestry = {

View file

@ -1,40 +0,0 @@
export default class DhpChatMessage extends foundry.documents.ChatMessage {
async renderHTML() {
if (this.system.messageTemplate)
this.content = await foundry.applications.handlebars.renderTemplate(
this.system.messageTemplate,
this.system
);
/* We can change to fully implementing the renderHTML function if needed, instead of augmenting it. */
const html = await super.renderHTML();
this.applyPermission(html);
if (this.type === 'dualityRoll') {
html.classList.add('duality');
switch (this.system.roll.result.duality) {
case 1:
html.classList.add('hope');
break;
case -1:
html.classList.add('fear');
break;
default:
html.classList.add('critical');
break;
}
}
return html;
}
applyPermission(html) {
const elements = html.querySelectorAll('[data-perm-id]');
elements.forEach(e => {
const uuid = e.dataset.permId,
document = fromUuidSync(uuid);
e.setAttribute('data-view-perm', document.testUserPermission(game.user, 'OBSERVER'));
e.setAttribute('data-use-perm', document.testUserPermission(game.user, 'OWNER'));
});
}
}

View file

@ -0,0 +1,9 @@
export { default as BeastformDialog } from './beastformDialog.mjs';
export { default as costSelectionDialog } from './costSelectionDialog.mjs';
export { default as d20RollDialog } from './d20RollDialog.mjs';
export { default as DamageDialog } from './damageDialog.mjs';
export { default as DamageReductionDialog } from './damageReductionDialog.mjs';
export { default as DamageSelectionDialog } from './damageSelectionDialog.mjs';
export { default as DeathMove } from './deathMove.mjs';
export { default as Downtime } from './downtime.mjs';
export { default as OwnershipSelection } from './ownershipSelection.mjs';

View file

@ -0,0 +1,84 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class BeastformDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(configData) {
super();
this.configData = configData;
this.selected = null;
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'views', 'dh-style', 'beastform-selection'],
position: {
width: 600,
height: 'auto'
},
actions: {
selectBeastform: this.selectBeastform,
submitBeastform: this.submitBeastform
},
form: {
handler: this.updateBeastform,
submitOnChange: true,
submitOnClose: false
}
};
get title() {
return game.i18n.localize('DAGGERHEART.Sheets.Beastform.dialogTitle');
}
/** @override */
static PARTS = {
beastform: {
template: 'systems/daggerheart/templates/dialogs/beastformDialog.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.beastformTiers = game.items.reduce((acc, x) => {
const tier = CONFIG.DH.GENERAL.tiers[x.system.tier];
if (x.type !== 'beastform' || tier.value > this.configData.tierLimit) return acc;
if (!acc[tier.value]) acc[tier.value] = { label: game.i18n.localize(tier.label), values: {} };
acc[tier.value].values[x.uuid] = { selected: this.selected == x.uuid, value: x };
return acc;
}, {}); // Also get from compendium when added
context.canSubmit = this.selected;
return context;
}
static updateBeastform(event, _, formData) {
this.selected = foundry.utils.mergeObject(this.selected, formData.object);
this.render();
}
static selectBeastform(_, target) {
this.selected = this.selected === target.dataset.uuid ? null : target.dataset.uuid;
this.render();
}
static async submitBeastform() {
await this.close({ submitted: true });
}
/** @override */
_onClose(options = {}) {
if (!options.submitted) this.config = false;
}
static async configure(configData) {
return new Promise(resolve => {
const app = new this(configData);
app.addEventListener('close', () => resolve(app.selected), { once: true });
app.render({ force: true });
});
}
}

View file

@ -30,7 +30,7 @@ export default class CostSelectionDialog extends HandlebarsApplicationMixin(Appl
static PARTS = {
costSelection: {
id: 'costSelection',
template: 'systems/daggerheart/templates/views/costSelection.hbs'
template: 'systems/daggerheart/templates/dialogs/costSelection.hbs'
}
};

View file

@ -0,0 +1,132 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class D20RollDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(roll, config = {}, options = {}) {
super(options);
this.roll = roll;
this.config = config;
this.config.experiences = [];
if (config.source?.action) {
this.item = config.data.parent.items.get(config.source.item) ?? config.data.parent;
this.action =
config.data.attack?._id == config.source.action
? config.data.attack
: this.item.system.actions.find(a => a._id === config.source.action);
}
}
static DEFAULT_OPTIONS = {
tag: 'form',
id: 'roll-selection',
classes: ['daggerheart', 'views', 'roll-selection'],
position: {
width: 400,
height: 'auto'
},
actions: {
updateIsAdvantage: this.updateIsAdvantage,
selectExperience: this.selectExperience,
submitRoll: this.submitRoll
},
form: {
handler: this.updateRollConfiguration,
submitOnChange: true,
submitOnClose: false
}
};
/** @override */
static PARTS = {
costSelection: {
id: 'costSelection',
template: 'systems/daggerheart/templates/dialogs/costSelection.hbs'
},
rollSelection: {
id: 'rollSelection',
template: 'systems/daggerheart/templates/dialogs/rollSelection.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.hasRoll = !!this.config.roll;
context.roll = this.roll;
context.rollType = this.roll?.constructor.name;
context.experiences = Object.keys(this.config.data.experiences).map(id => ({
id,
...this.config.data.experiences[id]
}));
context.selectedExperiences = this.config.experiences;
context.advantage = this.config.roll?.advantage;
context.diceOptions = CONFIG.DH.GENERAL.diceTypes;
context.canRoll = true;
context.isLite = this.config.roll?.lite;
if (this.config.costs?.length) {
const updatedCosts = this.action.calcCosts(this.config.costs);
context.costs = updatedCosts;
context.canRoll = this.action.hasCost(updatedCosts);
this.config.data.scale = this.config.costs[0].total;
}
if (this.config.uses?.max) {
context.uses = this.action.calcUses(this.config.uses);
context.canRoll = context.canRoll && this.action.hasUses(context.uses);
}
context.extraFormula = this.config.extraFormula;
context.formula = this.roll.constructFormula(this.config);
return context;
}
static updateRollConfiguration(event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object);
if (this.config.costs) {
this.config.costs = foundry.utils.mergeObject(this.config.costs, rest.costs);
}
if (this.config.uses) this.config.uses = foundry.utils.mergeObject(this.config.uses, rest.uses);
if (rest.roll?.dice) {
Object.entries(rest.roll.dice).forEach(([key, value]) => {
this.roll[key] = value;
});
}
this.config.extraFormula = rest.extraFormula;
this.render();
}
static updateIsAdvantage(_, button) {
const advantage = Number(button.dataset.advantage);
this.config.roll.advantage = this.config.roll.advantage === advantage ? 0 : advantage;
this.render();
}
static selectExperience(_, button) {
/* if (this.config.experiences.find(x => x === button.dataset.key)) {
this.config.experiences = this.config.experiences.filter(x => x !== button.dataset.key);
} else {
this.config.experiences = [...this.config.experiences, button.dataset.key];
} */
this.config.experiences =
this.config.experiences.indexOf(button.dataset.key) > -1
? this.config.experiences.filter(x => x !== button.dataset.key)
: [...this.config.experiences, button.dataset.key];
this.render();
}
static async submitRoll() {
await this.close({ submitted: true });
}
/** @override */
_onClose(options = {}) {
if (!options.submitted) this.config = false;
}
static async configure(roll, config = {}, options = {}) {
return new Promise(resolve => {
const app = new this(roll, config, options);
app.addEventListener('close', () => resolve(app.config), { once: true });
app.render({ force: true });
});
}
}

View file

@ -0,0 +1,67 @@
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class DamageDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(roll, config = {}, options = {}) {
super(options);
this.roll = roll;
this.config = config;
}
static DEFAULT_OPTIONS = {
tag: 'form',
id: 'roll-selection',
classes: ['daggerheart', 'views', 'damage-selection'],
position: {
width: 400,
height: 'auto'
},
actions: {
submitRoll: this.submitRoll
},
form: {
handler: this.updateRollConfiguration,
submitOnChange: true,
submitOnClose: false
}
};
/** @override */
static PARTS = {
damageSelection: {
id: 'damageSelection',
template: 'systems/daggerheart/templates/dialogs/damageSelection.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.title = this.config.title;
context.extraFormula = this.config.extraFormula;
context.formula = this.roll.constructFormula(this.config);
return context;
}
static updateRollConfiguration(event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object);
this.config.extraFormula = rest.extraFormula;
this.render();
}
static async submitRoll() {
await this.close({ submitted: true });
}
/** @override */
_onClose(options = {}) {
if (!options.submitted) this.config = false;
}
static async configure(roll, config = {}) {
return new Promise(resolve => {
const app = new this(roll, config);
app.addEventListener('close', () => resolve(app.config), { once: true });
app.render({ force: true });
});
}
}

View file

@ -1,4 +1,4 @@
import { damageKeyToNumber, getDamageLabel } from '../helpers/utils.mjs';
import { damageKeyToNumber, getDamageLabel } from '../../helpers/utils.mjs';
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
@ -71,7 +71,7 @@ export default class DamageReductionDialog extends HandlebarsApplicationMixin(Ap
static PARTS = {
damageSelection: {
id: 'damageReduction',
template: 'systems/daggerheart/templates/views/damageReduction.hbs'
template: 'systems/daggerheart/templates/dialogs/damageReduction.hbs'
}
};

View file

@ -7,7 +7,7 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
this.data = {
rollString,
bonusDamage: bonusDamage.reduce((acc, x) => {
if (x.appliesOn === SYSTEM.EFFECTS.applyLocations.damageRoll.id) {
if (x.appliesOn === CONFIG.DH.EFFECTS.applyLocations.damageRoll.id) {
acc.push({
...x,
hopeUses: 0
@ -44,7 +44,7 @@ export default class DamageSelectionDialog extends HandlebarsApplicationMixin(Ap
static PARTS = {
damageSelection: {
id: 'damageSelection',
template: 'systems/daggerheart/templates/views/damageSelection.hbs'
template: 'systems/daggerheart/templates/dialogs/damageSelection.hbs'
}
};

View file

@ -24,21 +24,21 @@ export default class DhpDeathMove extends HandlebarsApplicationMixin(Application
static PARTS = {
application: {
id: 'death-move',
template: 'systems/daggerheart/templates/views/deathMove.hbs'
template: 'systems/daggerheart/templates/dialogs/deathMove.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.selectedMove = this.selectedMove;
context.options = SYSTEM.GENERAL.deathMoves;
context.options = CONFIG.DH.GENERAL.deathMoves;
return context;
}
static selectMove(_, button) {
const move = button.dataset.move;
this.selectedMove = SYSTEM.GENERAL.deathMoves[move];
this.selectedMove = CONFIG.DH.GENERAL.deathMoves[move];
this.render();
}
@ -48,7 +48,7 @@ export default class DhpDeathMove extends HandlebarsApplicationMixin(Application
const msg = new cls({
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/deathMove.hbs',
'systems/daggerheart/templates/ui/chat/deathMove.hbs',
{
player: this.actor.name,
title: game.i18n.localize(this.selectedMove.name),

View file

@ -1,5 +1,3 @@
import { actionsTypes } from '../data/_module.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV2) {
@ -9,7 +7,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
this.actor = actor;
this.shortrest = shortrest;
const options = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).restMoves;
const options = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).restMoves;
this.moveData = shortrest ? options.shortRest : options.longRest;
}
@ -31,7 +29,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
static PARTS = {
application: {
id: 'downtime',
template: 'systems/daggerheart/templates/views/downtime.hbs'
template: 'systems/daggerheart/templates/dialogs/downtime.hbs'
}
};
@ -88,7 +86,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
actor: this.actor.uuid
},
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/downtime.hbs',
'systems/daggerheart/templates/ui/chat/downtime.hbs',
{
title: `${this.actor.name} - ${game.i18n.localize(`DAGGERHEART.Downtime.${this.shortRest ? 'ShortRest' : 'LongRest'}.title`)}`,
moves: moves

View file

@ -22,7 +22,7 @@ export default class OwnershipSelection extends HandlebarsApplicationMixin(Appli
static PARTS = {
selection: {
template: 'systems/daggerheart/templates/views/ownershipSelection.hbs'
template: 'systems/daggerheart/templates/dialogs/ownershipSelection.hbs'
}
};

View file

@ -0,0 +1,3 @@
export { default as CharacterLevelup } from './characterLevelup.mjs';
export { default as CompanionLevelup } from './companionLevelup.mjs';
export { default as Levelup } from './levelup.mjs';

View file

@ -7,7 +7,9 @@ export default class DhCharacterLevelUp extends LevelUpBase {
constructor(actor) {
super(actor);
this.levelTiers = this.addBonusChoices(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers));
this.levelTiers = this.addBonusChoices(
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers)
);
const playerLevelupData = actor.system.levelData;
this.levelup = new DhLevelup(DhLevelup.initializeData(this.levelTiers, playerLevelupData));
}

View file

@ -43,10 +43,10 @@ export default class DhlevelUp extends HandlebarsApplicationMixin(ApplicationV2)
};
static PARTS = {
tabs: { template: 'systems/daggerheart/templates/views/levelup/tabs/tab-navigation.hbs' },
advancements: { template: 'systems/daggerheart/templates/views/levelup/tabs/advancements.hbs' },
selections: { template: 'systems/daggerheart/templates/views/levelup/tabs/selections.hbs' },
summary: { template: 'systems/daggerheart/templates/views/levelup/tabs/summary.hbs' }
tabs: { template: 'systems/daggerheart/templates/levelup/tabs/tab-navigation.hbs' },
advancements: { template: 'systems/daggerheart/templates/levelup/tabs/advancements.hbs' },
selections: { template: 'systems/daggerheart/templates/levelup/tabs/selections.hbs' },
summary: { template: 'systems/daggerheart/templates/levelup/tabs/summary.hbs' }
};
static TABS = {

View file

@ -1,80 +0,0 @@
/** NOT USED ANYMORE - TO BE DELETED **/
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
export default class NpcRollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(experiences, resolve, reject) {
super({});
this.experiences = experiences;
this.resolve = resolve;
this.reject = reject;
this.selectedExperiences = [];
this.data = {
advantage: null
};
}
get title() {
return game.i18n.localize('DAGGERHEART.Application.RollSelection.Title');
}
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'views', 'npc-roll-selection'],
position: { width: '500', height: 'auto' },
actions: {
updateIsAdvantage: this.updateIsAdvantage,
selectExperience: this.selectExperience
},
form: { handler: this.updateData, submitOnChange: false }
};
static PARTS = {
main: {
id: 'main',
template: 'systems/daggerheart/templates/views/npcRollSelection.hbs'
}
};
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.advantage = this.data.advantage;
context.experiences = Object.values(this.experiences).map(x => ({
...x,
selected: this.selectedExperiences.find(selected => selected.id === x.id),
value: `${x.value >= 0 ? '+' : '-'}${x.value}`
}));
return context;
}
static updateIsAdvantage(_, button) {
const advantage = Boolean(button.dataset.advantage);
this.data.advantage = this.data.advantage === advantage ? null : advantage;
this.render();
}
static selectExperience(_, button) {
const experience = Object.values(this.experiences).find(experience => experience.id === button.id);
this.selectedExperiences = this.selectedExperiences.find(x => x.id === experience.id)
? this.selectedExperiences.filter(x => x.id !== experience.id)
: [...this.selectedExperiences, experience];
this.render();
}
static async updateData() {
this.resolve({ ...this.data, experiences: this.selectedExperiences });
this.close({ updateClose: true });
}
async close(options = {}) {
const { updateClose, ...baseOptions } = options;
if (!updateClose) {
this.reject();
}
await super.close(baseOptions);
}
}

View file

@ -1,491 +0,0 @@
import D20RollDialog from '../dialogs/d20RollDialog.mjs';
import DamageDialog from '../dialogs/damageDialog.mjs';
import { setDiceSoNiceForDualityRoll } from '../helpers/utils.mjs';
/*
- Damage & other resources roll
- Close dialog => don't roll
*/
export class DHRoll extends Roll {
baseTerms = [];
constructor(formula, data, options) {
super(formula, data, options);
}
static messageType = 'adversaryRoll';
static DefaultDialog = D20RollDialog;
static async build(config = {}, message = {}) {
const roll = await this.buildConfigure(config, message);
if (!roll) return;
await this.buildEvaluate(roll, config, (message = {}));
await this.buildPost(roll, config, (message = {}));
return config;
}
static async buildConfigure(config = {}, message = {}) {
config.hooks = [...(config.hooks ?? []), ''];
config.dialog ??= {};
for (const hook of config.hooks) {
if (Hooks.call(`${SYSTEM.id}.preRoll${hook.capitalize()}`, config, message) === false) return null;
}
this.applyKeybindings(config);
let roll = new this(config.roll.formula, config.data, config);
if (config.dialog.configure !== false) {
// Open Roll Dialog
const DialogClass = config.dialog?.class ?? this.DefaultDialog;
const configDialog = await DialogClass.configure(roll, config, message);
if (!configDialog) return;
}
for (const hook of config.hooks) {
if (Hooks.call(`${SYSTEM.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false)
return [];
}
return roll;
}
static async buildEvaluate(roll, config = {}, message = {}) {
if (config.evaluate !== false) await roll.evaluate();
this.postEvaluate(roll, config);
}
static async buildPost(roll, config, message) {
for (const hook of config.hooks) {
if (Hooks.call(`${SYSTEM.id}.postRoll${hook.capitalize()}`, config, message) === false) return null;
}
// Create Chat Message
if (config.source?.message) {
} else {
const messageData = {};
config.message = await this.toMessage(roll, config);
}
}
static postEvaluate(roll, config = {}) {
if (!config.roll) config.roll = {};
config.roll.total = roll.total;
config.roll.formula = roll.formula;
config.roll.dice = [];
roll.dice.forEach(d => {
config.roll.dice.push({
dice: d.denomination,
total: d.total,
formula: d.formula,
results: d.results
});
});
}
static async toMessage(roll, config) {
const cls = getDocumentClass('ChatMessage'),
msg = {
type: this.messageType,
user: game.user.id,
sound: config.mute ? null : CONFIG.sounds.dice,
system: config,
rolls: [roll]
};
return await cls.create(msg);
}
static applyKeybindings(config) {
if (config.event)
config.dialog.configure ??= !(config.event.shiftKey || config.event.altKey || config.event.ctrlKey);
}
formatModifier(modifier) {
const numTerm = modifier < 0 ? '-' : '+';
return [
new foundry.dice.terms.OperatorTerm({ operator: numTerm }),
new foundry.dice.terms.NumericTerm({ number: Math.abs(modifier) })
];
}
getFaces(faces) {
return Number(faces.startsWith('d') ? faces.replace('d', '') : faces);
}
constructFormula(config) {
this.terms = Roll.parse(this.options.roll.formula, config.data);
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(this.options.extraFormula, this.options.data)
);
}
return (this._formula = this.constructor.getFormula(this.terms));
}
static calculateTotalModifiers(roll) {
let modifierTotal = 0;
for (let i = 0; i < roll.terms.length; i++) {
if (
roll.terms[i] instanceof foundry.dice.terms.NumericTerm &&
!!roll.terms[i - 1] &&
roll.terms[i - 1] instanceof foundry.dice.terms.OperatorTerm
)
modifierTotal += Number(`${roll.terms[i - 1].operator}${roll.terms[i].total}`);
}
return modifierTotal;
}
}
export class DualityDie extends foundry.dice.terms.Die {
constructor({ number = 1, faces = 12, ...args } = {}) {
super({ number, faces, ...args });
}
}
export class D20Roll extends DHRoll {
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
this.constructFormula();
}
static ADV_MODE = {
NORMAL: 0,
ADVANTAGE: 1,
DISADVANTAGE: -1
};
static messageType = 'adversaryRoll';
static CRITICAL_TRESHOLD = 20;
static DefaultDialog = D20RollDialog;
get d20() {
if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
return this.terms[0];
}
set d20(faces) {
if (!(this.terms[0] instanceof foundry.dice.terms.Die)) this.createBaseDice();
this.terms[0].faces = this.getFaces(faces);
}
get dAdvantage() {
return this.dice[2];
}
get isCritical() {
if (!this.d20._evaluated) return;
return this.d20.total >= this.constructor.CRITICAL_TRESHOLD;
}
get hasAdvantage() {
return this.options.roll.advantage === this.constructor.ADV_MODE.ADVANTAGE;
}
get hasDisadvantage() {
return this.options.roll.advantage === this.constructor.ADV_MODE.DISADVANTAGE;
}
static applyKeybindings(config) {
let keys = {
normal: true,
advantage: false,
disadvantage: false
};
if (config.event) {
keys = {
normal: config.event.shiftKey || config.event.altKey || config.event.ctrlKey,
advantage: config.event.altKey,
disadvantage: config.event.ctrlKey
};
}
// Should the roll configuration dialog be displayed?
config.dialog.configure ??= !Object.values(keys).some(k => k);
// Determine advantage mode
const advantage = config.roll.advantage === this.ADV_MODE.ADVANTAGE || keys.advantage || config.advantage;
const disadvantage =
config.roll.advantage === this.ADV_MODE.DISADVANTAGE || keys.disadvantage || config.disadvantage;
if (advantage && !disadvantage) config.roll.advantage = this.ADV_MODE.ADVANTAGE;
else if (!advantage && disadvantage) config.roll.advantage = this.ADV_MODE.DISADVANTAGE;
else config.roll.advantage = this.ADV_MODE.NORMAL;
}
constructFormula(config) {
// this.terms = [];
this.createBaseDice();
this.configureModifiers();
this.resetFormula();
return this._formula;
}
createBaseDice() {
if (this.terms[0] instanceof foundry.dice.terms.Die) {
this.terms = [this.terms[0]];
return;
}
this.terms[0] = new foundry.dice.terms.Die({ faces: 20 });
}
configureModifiers() {
this.applyAdvantage();
this.applyBaseBonus();
this.options.experiences?.forEach(m => {
if (this.options.data.experiences?.[m])
this.options.roll.modifiers.push({
label: this.options.data.experiences[m].name,
value: this.options.data.experiences[m].total ?? this.options.data.experiences[m].value
});
});
this.options.roll.modifiers?.forEach(m => {
this.terms.push(...this.formatModifier(m.value));
});
this.baseTerms = foundry.utils.deepClone(this.terms);
if (this.options.extraFormula) {
this.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(this.options.extraFormula, this.options.data)
);
}
}
applyAdvantage() {
this.d20.modifiers.findSplice(m => ['kh', 'kl'].includes(m));
if (!this.hasAdvantage && !this.hasDisadvantage) this.number = 1;
else {
this.d20.number = 2;
this.d20.modifiers.push(this.hasAdvantage ? 'kh' : 'kl');
}
}
applyBaseBonus() {
this.options.roll.modifiers = [];
if (!this.options.roll.bonus) return;
this.options.roll.modifiers.push({
label: 'Bonus to Hit',
value: this.options.roll.bonus
// value: Roll.replaceFormulaData('@attackBonus', this.data)
});
}
static async buildEvaluate(roll, config = {}, message = {}) {
if (config.evaluate !== false) await roll.evaluate();
const advantageState =
config.roll.advantage == this.ADV_MODE.ADVANTAGE
? true
: config.roll.advantage == this.ADV_MODE.DISADVANTAGE
? false
: null;
setDiceSoNiceForDualityRoll(roll, advantageState);
this.postEvaluate(roll, config);
}
static postEvaluate(roll, config = {}) {
super.postEvaluate(roll, config);
if (config.targets?.length) {
config.targets.forEach(target => {
const difficulty = config.roll.difficulty ?? target.difficulty ?? target.evasion;
target.hit = this.isCritical || roll.total >= difficulty;
});
} else if (config.roll.difficulty)
config.roll.success = roll.isCritical || roll.total >= config.roll.difficulty;
config.roll.advantage = {
type: config.roll.advantage,
dice: roll.dAdvantage?.denomination,
value: roll.dAdvantage?.total
};
config.roll.isCritical = roll.isCritical;
config.roll.extra = roll.dice
.filter(d => !roll.baseTerms.includes(d))
.map(d => {
return {
dice: d.denomination,
value: d.total
};
});
config.roll.modifierTotal = this.calculateTotalModifiers(roll);
}
resetFormula() {
return (this._formula = this.constructor.getFormula(this.terms));
}
}
export class DualityRoll extends D20Roll {
_advantageFaces = 6;
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
}
static messageType = 'dualityRoll';
static DefaultDialog = D20RollDialog;
get dHope() {
// if ( !(this.terms[0] instanceof foundry.dice.terms.Die) ) return;
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
return this.dice[0];
// return this.#hopeDice;
}
set dHope(faces) {
if (!(this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
this.terms[0].faces = this.getFaces(faces);
// this.#hopeDice = `d${face}`;
}
get dFear() {
// if ( !(this.terms[1] instanceof foundry.dice.terms.Die) ) return;
if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
return this.dice[1];
// return this.#fearDice;
}
set dFear(faces) {
if (!(this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie)) this.createBaseDice();
this.dice[1].faces = this.getFaces(faces);
// this.#fearDice = `d${face}`;
}
get dAdvantage() {
return this.dice[2];
}
get advantageFaces() {
return this._advantageFaces;
}
set advantageFaces(faces) {
this._advantageFaces = this.getFaces(faces);
}
get isCritical() {
if (!this.dHope._evaluated || !this.dFear._evaluated) return;
return this.dHope.total === this.dFear.total;
}
get withHope() {
if (!this._evaluated) return;
return this.dHope.total > this.dFear.total;
}
get withFear() {
if (!this._evaluated) return;
return this.dHope.total < this.dFear.total;
}
get hasBarRally() {
return null;
}
get totalLabel() {
const label = this.withHope
? 'DAGGERHEART.General.Hope'
: this.withFear
? 'DAGGERHEART.General.Fear'
: 'DAGGERHEART.General.CriticalSuccess';
return game.i18n.localize(label);
}
updateFormula() {}
createBaseDice() {
if (
this.dice[0] instanceof CONFIG.Dice.daggerheart.DualityDie &&
this.dice[1] instanceof CONFIG.Dice.daggerheart.DualityDie
) {
this.terms = [this.terms[0], this.terms[1], this.terms[2]];
return;
}
this.terms[0] = new CONFIG.Dice.daggerheart.DualityDie();
this.terms[1] = new foundry.dice.terms.OperatorTerm({ operator: '+' });
this.terms[2] = new CONFIG.Dice.daggerheart.DualityDie();
}
applyAdvantage() {
const dieFaces = this.advantageFaces,
bardRallyFaces = this.hasBarRally,
advDie = new foundry.dice.terms.Die({ faces: dieFaces });
if (this.hasAdvantage || this.hasDisadvantage || bardRallyFaces)
this.terms.push(new foundry.dice.terms.OperatorTerm({ operator: this.hasDisadvantage ? '-' : '+' }));
if (bardRallyFaces) {
const rallyDie = new foundry.dice.terms.Die({ faces: bardRallyFaces });
if (this.hasAdvantage) {
this.terms.push(
new foundry.dice.terms.PoolTerm({
terms: [advDie.formula, rallyDie.formula],
modifiers: ['kh']
})
);
} else if (this.hasDisadvantage) {
this.terms.push(advDie, new foundry.dice.terms.OperatorTerm({ operator: '+' }), rallyDie);
}
} else if (this.hasAdvantage || this.hasDisadvantage) this.terms.push(advDie);
}
applyBaseBonus() {
this.options.roll.modifiers = [];
if (!this.options.roll.trait) return;
this.options.roll.modifiers.push({
label: `DAGGERHEART.Abilities.${this.options.roll.trait}.name`,
value: Roll.replaceFormulaData(`@traits.${this.options.roll.trait}.total`, this.data)
});
}
static postEvaluate(roll, config = {}) {
super.postEvaluate(roll, config);
config.roll.hope = {
dice: roll.dHope.denomination,
value: roll.dHope.total
};
config.roll.fear = {
dice: roll.dFear.denomination,
value: roll.dFear.total
};
config.roll.result = {
duality: roll.withHope ? 1 : roll.withFear ? -1 : 0,
total: roll.dHope.total + roll.dFear.total,
label: roll.totalLabel
};
}
}
export class DamageRoll extends DHRoll {
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
}
static messageType = 'damageRoll';
static DefaultDialog = DamageDialog;
static async postEvaluate(roll, config = {}) {
super.postEvaluate(roll, config);
config.roll.type = config.type;
config.roll.modifierTotal = this.calculateTotalModifiers(roll);
if (config.source?.message) {
const chatMessage = ui.chat.collection.get(config.source.message);
chatMessage.update({ 'system.damage': config });
}
}
constructFormula(config) {
super.constructFormula(config);
if(config.isCritical) {
const tmpRoll = new Roll(this._formula)._evaluateSync({maximize: true}),
criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll);
this.terms.push(...this.formatModifier(criticalBonus));
}
return (this._formula = this.constructor.getFormula(this.terms));
}
}

View file

@ -1,111 +0,0 @@
/** NOT USED ANYMORE - TO BE DELETED **/
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
export default class RollSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(experiences, costs, action, resolve) {
super({}, {});
this.experiences = experiences;
this.costs = costs;
this.action = action;
this.resolve = resolve;
this.isNpc;
this.selectedExperiences = [];
this.data = {
diceOptions: [
{ name: 'd12', value: 'd12' },
{ name: 'd20', value: 'd20' }
],
hope: ['d12'],
fear: ['d12'],
advantage: null
};
}
static DEFAULT_OPTIONS = {
tag: 'form',
id: 'roll-selection',
classes: ['daggerheart', 'views', 'roll-selection'],
position: {
width: 400,
height: 'auto'
},
actions: {
updateIsAdvantage: this.updateIsAdvantage,
selectExperience: this.selectExperience,
finish: this.finish
},
form: {
handler: this.updateSelection,
submitOnChange: true,
submitOnClose: false
}
};
/** @override */
static PARTS = {
costSelection: {
id: 'costSelection',
template: 'systems/daggerheart/templates/views/costSelection.hbs'
},
damageSelection: {
id: 'damageSelection',
template: 'systems/daggerheart/templates/views/rollSelection.hbs'
}
};
get title() {
return game.i18n.localize('DAGGERHEART.Application.RollSelection.Title');
}
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.isNpc = this.isNpc;
context.diceOptions = this.data.diceOptions;
context.hope = this.data.hope;
context.fear = this.data.fear;
context.advantage = this.data.advantage;
context.experiences = Object.keys(this.experiences).map(id => ({ id, ...this.experiences[id] }));
if (this.costs?.length) {
const updatedCosts = this.action.calcCosts(this.costs);
context.costs = updatedCosts;
context.canRoll = this.action.getRealCosts(updatedCosts)?.hasCost;
} else context.canRoll = true;
return context;
}
static updateSelection(event, _, formData) {
const { ...rest } = foundry.utils.expandObject(formData.object);
this.data = foundry.utils.mergeObject(this.data, rest);
this.costs = foundry.utils.mergeObject(this.costs, rest.costs);
this.render();
}
static selectExperience(_, button) {
if (this.selectedExperiences.find(x => x.id === button.dataset.key)) {
this.selectedExperiences = this.selectedExperiences.filter(x => x.id !== button.dataset.key);
} else {
this.selectedExperiences = [...this.selectedExperiences, button.dataset.key];
}
this.render();
}
static updateIsAdvantage(_, button) {
const advantage = Boolean(button.dataset.advantage);
this.data.advantage = this.data.advantage === advantage ? null : advantage;
this.render();
}
static async finish() {
const { diceOptions, ...rest } = this.data;
this.resolve({
...rest,
experiences: this.selectedExperiences.map(x => ({ id: x, ...this.experiences[x] })),
costs: this.action.getRealCosts(this.costs)
});
this.close();
}
}

View file

@ -1,140 +0,0 @@
import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs';
import DhCountdowns from '../data/countdowns.mjs';
import {
DhAppearance,
DhAutomation,
DhHomebrew,
DhRangeMeasurement,
DhVariantRules
} from '../data/settings/_module.mjs';
import {
DhAppearanceSettings,
DhAutomationSettings,
DhHomebrewSettings,
DhRangeMeasurementSettings,
DhVariantRuleSettings
} from './settings/_module.mjs';
export const registerDHSettings = () => {
registerMenuSettings();
registerMenus();
registerNonConfigSettings();
};
const registerMenuSettings = () => {
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.variantRules, {
scope: 'world',
config: false,
type: DhVariantRules
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation, {
scope: 'world',
config: false,
type: DhAutomation
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew, {
scope: 'world',
config: false,
type: DhHomebrew,
onChange: value => {
if (value.maxFear) {
if (ui.resources) ui.resources.render({ force: true });
}
}
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance, {
scope: 'client',
config: false,
type: DhAppearance,
onChange: value => {
if (value.displayFear) {
if (ui.resources) {
if (value.displayFear === 'hide') ui.resources.close({ allowed: true });
else ui.resources.render({ force: true });
}
}
}
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.RangeMeasurement, {
scope: 'client',
config: false,
type: DhRangeMeasurement
});
};
const registerMenus = () => {
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Automation.Name, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Name'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Label'),
hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Automation.Hint'),
icon: SYSTEM.SETTINGS.menu.Automation.Icon,
type: DhAutomationSettings,
restricted: true
});
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Homebrew.Name, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Name'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Label'),
hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Homebrew.Hint'),
icon: SYSTEM.SETTINGS.menu.Homebrew.Icon,
type: DhHomebrewSettings,
restricted: true
});
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.Range.Name, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Name'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Label'),
hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Range.Hint'),
icon: SYSTEM.SETTINGS.menu.Range.Icon,
type: DhRangeMeasurementSettings,
restricted: true
});
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.Appearance.title'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.Appearance.label'),
hint: game.i18n.localize('DAGGERHEART.Settings.Menu.Appearance.hint'),
icon: 'fa-solid fa-palette',
type: DhAppearanceSettings,
restricted: false
});
game.settings.registerMenu(SYSTEM.id, SYSTEM.SETTINGS.menu.VariantRules.Name, {
name: game.i18n.localize('DAGGERHEART.Settings.Menu.VariantRules.title'),
label: game.i18n.localize('DAGGERHEART.Settings.Menu.VariantRules.label'),
hint: game.i18n.localize('DAGGERHEART.Settings.Menu.VariantRules.hint'),
icon: SYSTEM.SETTINGS.menu.VariantRules.Icon,
type: DhVariantRuleSettings,
restricted: false
});
};
const registerNonConfigSettings = () => {
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers, {
scope: 'world',
config: false,
type: DhLevelTiers,
default: defaultLevelTiers
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, {
name: game.i18n.localize('DAGGERHEART.Settings.Resources.Fear.Name'),
hint: game.i18n.localize('DAGGERHEART.Settings.Resources.Fear.Hint'),
scope: 'world',
config: false,
type: Number,
default: 0,
onChange: () => {
if (ui.resources) ui.resources.render({ force: true });
ui.combat.render({ force: true });
}
});
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, {
scope: 'world',
config: false,
type: DhCountdowns
});
};

View file

@ -1,13 +1,5 @@
import DhAppearanceSettings from './appearanceSettings.mjs';
import DhAutomationSettings from './automationSettings.mjs';
import DhHomebrewSettings from './homebrewSettings.mjs';
import DhRangeMeasurementSettings from './rangeMeasurementSettings.mjs';
import DhVariantRuleSettings from './variantRuleSettings.mjs';
export {
DhAppearanceSettings,
DhAutomationSettings,
DhHomebrewSettings,
DhRangeMeasurementSettings,
DhVariantRuleSettings
};
export { default as DhAppearanceSettings } from './appearanceSettings.mjs';
export { default as DhAutomationSettings } from './automationSettings.mjs';
export { default as DhHomebrewSettings } from './homebrewSettings.mjs';
export { default as DhRangeMeasurementSettings } from './rangeMeasurementSettings.mjs';
export { default as DhVariantRuleSettings } from './variantRuleSettings.mjs';

View file

@ -7,7 +7,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
super({});
this.settings = new DhAppearance(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).toObject()
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).toObject()
);
}
@ -53,10 +53,10 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
}
static async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance, this.settings.toObject());
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, this.settings.toObject());
document.body.classList.toggle(
'theme-colorful',
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme ===
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).dualityColorScheme ===
DualityRollColor.colorful.value
);

View file

@ -7,7 +7,7 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
super({});
this.settings = new DhAutomation(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).toObject()
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).toObject()
);
}
@ -53,7 +53,7 @@ export default class DhAutomationSettings extends HandlebarsApplicationMixin(App
}
static async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation, this.settings.toObject());
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation, this.settings.toObject());
this.close();
}
}

View file

@ -1,5 +1,5 @@
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
import { actionsTypes } from '../../../data/action/_module.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -96,8 +96,8 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
async selectActionType() {
const content = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/views/actionType.hbs',
{ types: SYSTEM.ACTIONS.actionTypes }
'systems/daggerheart/templates/actionTypes/actionType.hbs',
{ types: CONFIG.DH.ACTIONS.actionTypes }
),
title = 'Select Action Type',
type = 'form',
@ -123,7 +123,7 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
action = new cls({
_id: foundry.utils.randomID(),
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
});

View file

@ -7,7 +7,9 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
constructor() {
super({});
this.settings = new DhHomebrew(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).toObject());
this.settings = new DhHomebrew(
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).toObject()
);
}
get title() {
@ -113,7 +115,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
if (!confirmed) return;
const fields = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).schema.fields;
const fields = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).schema.fields;
const removeUpdate = Object.keys(this.settings.restMoves[target.dataset.type].moves).reduce((acc, key) => {
acc[`-=${key}`] = null;
@ -153,7 +155,7 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
}
static async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew, this.settings.toObject());
this.close();
}

View file

@ -7,7 +7,7 @@ export default class DhRangeMeasurementSettings extends HandlebarsApplicationMix
super({});
this.settings = new DhRangeMeasurement(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.RangeMeasurement).toObject()
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement).toObject()
);
}
@ -53,7 +53,11 @@ export default class DhRangeMeasurementSettings extends HandlebarsApplicationMix
}
static async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.RangeMeasurement, this.settings.toObject());
await game.settings.set(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.RangeMeasurement,
this.settings.toObject()
);
this.close();
}
}

View file

@ -7,7 +7,7 @@ export default class DHVariantRuleSettings extends HandlebarsApplicationMixin(Ap
super({});
this.settings = new DhVariantRules(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.variantRules).toObject()
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).toObject()
);
}
@ -53,7 +53,7 @@ export default class DHVariantRuleSettings extends HandlebarsApplicationMixin(Ap
}
static async save() {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.variantRules, this.settings.toObject());
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules, this.settings.toObject());
this.close();
}
}

View file

@ -0,0 +1,5 @@
export { default as ActionConfig } from './action-config.mjs';
export { default as AdversarySettings } from './adversary-settings.mjs';
export { default as CompanionSettings } from './companion-settings.mjs';
export { default as EnvironmentSettings } from './environment-settings.mjs';
export { default as ActiveEffectConfig } from './activeEffectConfig.mjs';

View file

@ -34,7 +34,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
static PARTS = {
form: {
id: 'action',
template: 'systems/daggerheart/templates/views/action.hbs'
template: 'systems/daggerheart/templates/config/action.hbs'
}
};
@ -60,7 +60,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
context.source = this.action.toObject(false);
context.openSection = this.openSection;
context.tabs = this._getTabs();
context.config = SYSTEM;
context.config = CONFIG.DH;
if (!!this.action.effects) context.effects = this.action.effects.map(e => this.action.item.effects.get(e._id));
if (this.action.damage?.hasOwnProperty('includeBase') && this.action.type === 'attack')
context.hasBaseDamage = !!this.action.parent.damage;
@ -70,7 +70,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
context.isNPC = this.action.actor && this.action.actor.type !== 'character';
context.hasRoll = this.action.hasRoll;
const settingsTiers = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers).tiers;
const settingsTiers = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LevelTiers).tiers;
context.tierOptions = [
{ key: 1, label: game.i18n.localize('DAGGERHEART.Tiers.tier1') },
...Object.values(settingsTiers).map(x => ({ key: x.tier, label: x.name }))

View file

@ -1,6 +1,6 @@
import DHActionConfig from '../../config/Action.mjs';
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from './action-config.mjs';
import DHBaseItemSheet from '../sheets/api/base-item.mjs';
import { actionsTypes } from '../../data/action/_module.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -40,24 +40,24 @@ export default class DHAdversarySettings extends HandlebarsApplicationMixin(Appl
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/header.hbs'
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/details.hbs'
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/details.hbs'
},
attack: {
id: 'attack',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/attack.hbs'
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/attack.hbs'
},
experiences: {
id: 'experiences',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/experiences.hbs'
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/experiences.hbs'
},
actions: {
id: 'actions',
template: 'systems/daggerheart/templates/sheets/applications/adversary-settings/actions.hbs'
template: 'systems/daggerheart/templates/sheets-settings/adversary-settings/actions.hbs'
}
};
@ -139,7 +139,7 @@ export default class DHAdversarySettings extends HandlebarsApplicationMixin(Appl
{
_id: foundry.utils.randomID(),
type: actionType,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
...cls.getSourceConfig(this.actor)
},
{

View file

@ -1,5 +1,5 @@
import { GMUpdateEvent, socketEvent } from '../../../helpers/socket.mjs';
import DhCompanionlevelUp from '../../levelup/companionLevelup.mjs';
import { GMUpdateEvent, socketEvent } from '../../systemRegistration/socket.mjs';
import DhCompanionlevelUp from '../levelup/companionLevelup.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -35,20 +35,20 @@ export default class DHCompanionSettings extends HandlebarsApplicationMixin(Appl
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets/applications/companion-settings/header.hbs'
template: 'systems/daggerheart/templates/sheets-settings/companion-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets/applications/companion-settings/details.hbs'
template: 'systems/daggerheart/templates/sheets-settings/companion-settings/details.hbs'
},
experiences: {
id: 'experiences',
template: 'systems/daggerheart/templates/sheets/applications/companion-settings/experiences.hbs'
template: 'systems/daggerheart/templates/sheets-settings/companion-settings/experiences.hbs'
},
attack: {
id: 'attack',
template: 'systems/daggerheart/templates/sheets/applications/companion-settings/attack.hbs'
template: 'systems/daggerheart/templates/sheets-settings/companion-settings/attack.hbs'
}
};
@ -120,7 +120,7 @@ export default class DHCompanionSettings extends HandlebarsApplicationMixin(Appl
const partnerUpdate = { 'system.companion': event.target.value ? this.actor.uuid : null };
if (!partnerDocument.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)) {
await game.socket.emit(`system.${SYSTEM.id}`, {
await game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateDocument,

View file

@ -1,6 +1,6 @@
import DHActionConfig from '../../config/Action.mjs';
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from './action-config.mjs';
import DHBaseItemSheet from '../sheets/api/base-item.mjs';
import { actionsTypes } from '../../data/action/_module.mjs';
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
@ -44,20 +44,20 @@ export default class DHEnvironmentSettings extends HandlebarsApplicationMixin(Ap
static PARTS = {
header: {
id: 'header',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/header.hbs'
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/header.hbs'
},
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
details: {
id: 'details',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/details.hbs'
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/details.hbs'
},
actions: {
id: 'actions',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/actions.hbs'
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/actions.hbs'
},
adversaries: {
id: 'adversaries',
template: 'systems/daggerheart/templates/sheets/applications/environment-settings/adversaries.hbs'
template: 'systems/daggerheart/templates/sheets-settings/environment-settings/adversaries.hbs'
}
};
@ -131,7 +131,7 @@ export default class DHEnvironmentSettings extends HandlebarsApplicationMixin(Ap
{
_id: foundry.utils.randomID(),
type: actionType,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
...cls.getSourceConfig(this.actor)
},
{
@ -200,7 +200,7 @@ export default class DHEnvironmentSettings extends HandlebarsApplicationMixin(Ap
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
const item = await fromUuid(data.uuid);
if (item.type === 'adversary') {
const target = event.target.closest('.category-container');

View file

@ -0,0 +1,3 @@
export * as actors from './actors/_module.mjs';
export * as api from './api/_modules.mjs';
export * as items from './items/_module.mjs';

View file

@ -0,0 +1,4 @@
export { default as Adversary } from './adversary.mjs';
export { default as Character } from './character.mjs';
export { default as Companion } from './companion.mjs';
export { default as Environment } from './environment.mjs';

View file

@ -1,6 +1,6 @@
import DHActionConfig from '../../config/Action.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
import DaggerheartSheet from '../daggerheart-sheet.mjs';
import DHAdversarySettings from '../applications/adversary-settings.mjs';
import DHAdversarySettings from '../../sheets-configs/adversary-settings.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
@ -92,7 +92,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
},
chatMessage: {
type: 'adversaryRoll',
template: 'systems/daggerheart/templates/chat/adversary-roll.hbs',
template: 'systems/daggerheart/templates/ui/chat/adversary-roll.hbs',
mute: true
}
};
@ -127,7 +127,7 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});

View file

@ -1,14 +1,12 @@
import { capitalize } from '../../../helpers/utils.mjs';
import DhpDeathMove from '../../deathMove.mjs';
import DhpDowntime from '../../downtime.mjs';
import AncestrySelectionDialog from '../../ancestrySelectionDialog.mjs';
import DhpDeathMove from '../../dialogs/deathMove.mjs';
import DhpDowntime from '../../dialogs/downtime.mjs';
import DaggerheartSheet from '.././daggerheart-sheet.mjs';
import { abilities } from '../../../config/actorConfig.mjs';
import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs';
import DhCharacterCreation from '../../characterCreation.mjs';
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
import FilterMenu from '../../ux/filter-menu.mjs';
import { DhBeastformAction } from '../../../data/action/action.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux;
@ -33,7 +31,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
useDomainCard: this.useDomainCard,
selectClass: this.selectClass,
selectSubclass: this.selectSubclass,
selectAncestry: this.selectAncestry,
selectCommunity: this.selectCommunity,
viewObject: this.viewObject,
useItem: this.useItem,
@ -338,13 +335,13 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
const context = await super._prepareContext(_options);
context.document = this.document;
context.tabs = super._getTabs(this.constructor.TABS);
context.config = SYSTEM;
context.config = CONFIG.DH;
context.attributes = Object.keys(this.document.system.traits).reduce((acc, key) => {
acc[key] = {
...this.document.system.traits[key],
name: game.i18n.localize(SYSTEM.ACTOR.abilities[key].name),
verbs: SYSTEM.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x))
name: game.i18n.localize(CONFIG.DH.ACTOR.abilities[key].name),
verbs: CONFIG.DH.ACTOR.abilities[key].verbs.map(x => game.i18n.localize(x))
};
return acc;
@ -360,7 +357,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
};
const homebrewCurrency = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).currency;
const homebrewCurrency = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).currency;
if (homebrewCurrency.enabled) {
context.inventory.currency = homebrewCurrency;
}
@ -631,13 +628,13 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
static async toggleLoadoutView(_, button) {
const newAbilityView = !(button.dataset.value === 'true');
await game.user.setFlag(SYSTEM.id, SYSTEM.FLAGS.displayDomainCardsAsList, newAbilityView);
await game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.displayDomainCardsAsList, newAbilityView);
this.render();
}
static async toggleLoadoutView(_, button) {
const newAbilityView = !(button.dataset.value === 'true');
await game.user.setFlag(SYSTEM.id, SYSTEM.FLAGS.displayDomainCardsAsList, newAbilityView);
await game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS.displayDomainCardsAsList, newAbilityView);
this.render();
}
@ -647,7 +644,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
const wasUsed = await weapon.use(event);
if (wasUsed) {
Hooks.callAll(SYSTEM.HOOKS.characterAttack, {});
Hooks.callAll(CONFIG.DH.HOOKS.characterAttack, {});
}
}
@ -689,7 +686,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
type: 'abilityUse',
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
),
system: systemData
@ -706,28 +703,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
(await game.packs.get('daggerheart.subclasses'))?.render(true);
}
static async selectAncestry() {
const dialogClosed = new Promise((resolve, _) => {
new AncestrySelectionDialog(resolve).render(true);
});
const result = await dialogClosed;
for (var ancestry of this.document.items.filter(x => x => x.type === 'ancestry')) {
await ancestry.delete();
}
const createdItems = [];
for (var feature of this.document.items.filter(
x => x.type === 'feature' && x.system.type === SYSTEM.ITEM.featureTypes.ancestry.id
)) {
await feature.delete();
}
createdItems.push(result.data);
await this.document.createEmbeddedDocuments('Item', createdItems);
}
static async selectCommunity() {
(await game.packs.get('daggerheart.communities'))?.render(true);
}
@ -744,7 +719,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
} else {
const wasUsed = await item.use(event);
if (wasUsed && item.type === 'weapon') {
Hooks.callAll(SYSTEM.HOOKS.characterAttack, {});
Hooks.callAll(CONFIG.DH.HOOKS.characterAttack, {});
}
}
}
@ -840,7 +815,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
type: 'abilityUse',
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
),
system: systemData
@ -862,7 +837,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});
@ -898,7 +873,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});
@ -921,7 +896,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});

View file

@ -1,5 +1,5 @@
import DaggerheartSheet from '../daggerheart-sheet.mjs';
import DHCompanionSettings from '../applications/companion-settings.mjs';
import DHCompanionSettings from '../../sheets-configs/companion-settings.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
@ -90,7 +90,7 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
systemData
)
});

View file

@ -1,5 +1,5 @@
import DaggerheartSheet from '../daggerheart-sheet.mjs';
import DHEnvironmentSettings from '../applications/environment-settings.mjs';
import DHEnvironmentSettings from '../../sheets-configs/environment-settings.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {

View file

@ -139,7 +139,7 @@ export default function DHApplicationMixin(Base) {
* @param {DragEvent} event
* @protected
*/
_onDrop(event) { }
_onDrop(event) {}
/* -------------------------------------------- */
/* Prepare Context */
@ -154,7 +154,7 @@ export default function DHApplicationMixin(Base) {
*/
async _prepareContext(options, objectPath = 'document') {
const context = await super._prepareContext(options);
context.config = CONFIG.daggerheart;
context.config = CONFIG.DH;
context.source = this[objectPath];
context.fields = this[objectPath].schema.fields;
context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {};

View file

@ -1,6 +1,6 @@
import DHApplicationMixin from './application-mixin.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
import { actionsTypes } from '../../../data/action/_module.mjs';
const { ItemSheetV2 } = foundry.applications.sheets;
@ -69,8 +69,8 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
*/
static async selectActionType() {
const content = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/views/actionType.hbs',
{ types: SYSTEM.ACTIONS.actionTypes }
'systems/daggerheart/templates/actionTypes/actionType.hbs',
{ types: CONFIG.DH.ACTIONS.actionTypes }
),
title = 'Select Action Type';
@ -98,7 +98,7 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
{
_id: foundry.utils.randomID(),
type: actionType,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
...cls.getSourceConfig(this.document)
},
{

View file

@ -0,0 +1,11 @@
export { default as Ancestry } from './ancestry.mjs';
export { default as Armor } from './armor.mjs';
export { default as Beastform } from './beastform.mjs';
export { default as Class } from './class.mjs';
export { default as Community } from './community.mjs';
export { default as Consumable } from './consumable.mjs';
export { default as DomainCard } from './domainCard.mjs';
export { default as Feature } from './feature.mjs';
export { default as Miscellaneous } from './miscellaneous.mjs';
export { default as Subclass } from './subclass.mjs';
export { default as Weapon } from './weapon.mjs';

View file

@ -8,7 +8,7 @@ export default class ArmorSheet extends DHBaseItemSheet {
tagifyConfigs: [
{
selector: '.features-input',
options: () => CONFIG.daggerheart.ITEM.armorFeatures,
options: () => CONFIG.DH.ITEM.armorFeatures,
callback: ArmorSheet.#onFeatureSelect
}
]

View file

@ -55,7 +55,7 @@ export default class BeastformSheet extends DHBaseItemSheet {
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
const item = await fromUuid(data.uuid);
if (item.type === 'feature') {
const current = this.document.system.features.map(x => x.uuid);

View file

@ -1,6 +1,6 @@
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
import { actionsTypes } from '../../../data/action/_module.mjs';
const { TextEditor } = foundry.applications.ux;
@ -20,7 +20,7 @@ export default class ClassSheet extends DHBaseItemSheet {
tagifyConfigs: [
{
selector: '.domain-input',
options: () => CONFIG.daggerheart.DOMAIN.domains,
options: () => CONFIG.DH.DOMAIN.domains,
callback: ClassSheet.#onDomainSelect
}
],
@ -172,8 +172,8 @@ export default class ClassSheet extends DHBaseItemSheet {
//TODO: redo this
async selectActionType() {
const content = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/views/actionType.hbs',
{ types: SYSTEM.ACTIONS.actionTypes }
'systems/daggerheart/templates/actionTypes/actionType.hbs',
{ types: CONFIG.DH.ACTIONS.actionTypes }
),
title = 'Select Action Type',
type = 'form',
@ -209,7 +209,7 @@ export default class ClassSheet extends DHBaseItemSheet {
_id: foundry.utils.randomID(),
systemPath: actionPath,
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
},
{

View file

@ -1,6 +1,6 @@
import DHBaseItemSheet from '../api/base-item.mjs';
import { actionsTypes } from '../../../data/_module.mjs';
import DHActionConfig from '../../config/Action.mjs';
import DHActionConfig from '../../sheets-configs/action-config.mjs';
import { actionsTypes } from '../../../data/action/_module.mjs';
export default class SubclassSheet extends DHBaseItemSheet {
/**@inheritdoc */
@ -58,8 +58,8 @@ export default class SubclassSheet extends DHBaseItemSheet {
async #selectActionType() {
const content = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/views/actionType.hbs',
{ types: SYSTEM.ACTIONS.actionTypes }
'systems/daggerheart/templates/actionTypes/actionType.hbs',
{ types: CONFIG.DH.ACTIONS.actionTypes }
),
title = 'Select Action Type',
type = 'form',
@ -87,7 +87,7 @@ export default class SubclassSheet extends DHBaseItemSheet {
_id: foundry.utils.randomID(),
systemPath: `${level}.actions`,
type: actionType.type,
name: game.i18n.localize(SYSTEM.ACTIONS.actionTypes[actionType.type].name),
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType.type].name),
...cls.getSourceConfig(this.document)
},
{

View file

@ -7,7 +7,7 @@ export default class WeaponSheet extends DHBaseItemSheet {
tagifyConfigs: [
{
selector: '.features-input',
options: () => CONFIG.daggerheart.ITEM.weaponFeatures,
options: () => CONFIG.DH.ITEM.weaponFeatures,
callback: WeaponSheet.#onFeatureSelect
}
]

View file

@ -1,16 +0,0 @@
export default class DhTooltipManager extends TooltipManager {
async activate(element, options = {}) {
let html = options.html;
if (element.dataset.tooltip.startsWith('#item#')) {
const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6));
if (item) {
html = await foundry.applications.handlebars.renderTemplate(
`systems/daggerheart/templates/tooltip/${item.type}.hbs`,
item
);
}
}
super.activate(element, { ...options, html: html });
}
}

View file

@ -0,0 +1,4 @@
export { default as DhChatLog } from './chatLog.mjs';
export { default as DhCombatTracker } from './combatTracker.mjs';
export * as DhCountdowns from './countdowns.mjs';
export { default as DhFearTracker } from './fearTracker.mjs';

View file

@ -0,0 +1,270 @@
export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLog {
constructor() {
super();
this.targetTemplate = {
activeLayer: undefined,
document: undefined,
object: undefined,
minimizedSheets: [],
config: undefined,
targets: undefined
};
this.setupHooks();
}
addChatListeners = async (app, html, data) => {
html.querySelectorAll('.duality-action-damage').forEach(element =>
element.addEventListener('click', event => this.onRollDamage(event, data.message))
);
html.querySelectorAll('.duality-action-healing').forEach(element =>
element.addEventListener('click', event => this.onRollHealing(event, data.message))
);
html.querySelectorAll('.target-save-container').forEach(element =>
element.addEventListener('click', event => this.onRollSave(event, data.message))
);
html.querySelectorAll('.roll-all-save-button').forEach(element =>
element.addEventListener('click', event => this.onRollAllSave(event, data.message))
);
html.querySelectorAll('.duality-action-effect').forEach(element =>
element.addEventListener('click', event => this.onApplyEffect(event, data.message))
);
html.querySelectorAll('.target-container').forEach(element => {
element.addEventListener('mouseenter', this.hoverTarget);
element.addEventListener('mouseleave', this.unhoverTarget);
element.addEventListener('click', this.clickTarget);
});
html.querySelectorAll('.button-target-selection').forEach(element => {
element.addEventListener('click', event => this.onTargetSelection(event, data.message));
});
html.querySelectorAll('.damage-button').forEach(element =>
element.addEventListener('click', event => this.onDamage(event, data.message))
);
html.querySelectorAll('.healing-button').forEach(element =>
element.addEventListener('click', event => this.onHealing(event, data.message))
);
html.querySelectorAll('.target-indicator').forEach(element =>
element.addEventListener('click', this.onToggleTargets)
);
html.querySelectorAll('.advantage').forEach(element =>
element.addEventListener('mouseenter', this.hoverAdvantage)
);
html.querySelectorAll('.advantage').forEach(element =>
element.addEventListener('click', event => this.selectAdvantage.bind(this)(event, data.message))
);
html.querySelectorAll('.ability-use-button').forEach(element =>
element.addEventListener('click', event => this.abilityUseButton.bind(this)(event, data.message))
);
html.querySelectorAll('.action-use-button').forEach(element =>
element.addEventListener('click', event => this.actionUseButton.bind(this)(event, data.message))
);
};
setupHooks() {
Hooks.on('renderChatMessageHTML', this.addChatListeners.bind());
}
close(options) {
Hooks.off('renderChatMessageHTML', this.addChatListeners);
super.close(options);
}
async getActor(id) {
// return game.actors.get(id);
return await fromUuid(id);
}
getAction(actor, itemId, actionId) {
const item = actor.items.get(itemId),
action =
actor.system.attack?._id === actionId
? actor.system.attack
: item?.system?.actions?.find(a => a._id === actionId);
return action;
}
onRollDamage = async (event, message) => {
event.stopPropagation();
const actor = await this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true;
if (message.system.source.item && message.system.source.action) {
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
if (!action || !action?.rollDamage) return;
await action.rollDamage(event, message);
}
};
onRollHealing = async (event, message) => {
event.stopPropagation();
const actor = await this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true;
if (message.system.source.item && message.system.source.action) {
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
if (!action || !action?.rollHealing) return;
await action.rollHealing(event, message);
}
};
onRollSave = async (event, message) => {
event.stopPropagation();
const actor = await this.getActor(message.system.source.actor),
tokenId = event.target.closest('[data-token]')?.dataset.token,
token = game.canvas.tokens.get(tokenId);
if (!token?.actor || !token.isOwner) return true;
if (message.system.source.item && message.system.source.action) {
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
if (!action || !action?.hasSave) return;
action.rollSave(token, event, message);
}
};
onRollAllSave = async (event, message) => {
event.stopPropagation();
const targets = event.target.parentElement.querySelectorAll(
'.target-section > [data-token] .target-save-container'
);
targets.forEach(el => {
el.dispatchEvent(new PointerEvent('click', { shiftKey: true }));
});
};
onApplyEffect = async (event, message) => {
event.stopPropagation();
const actor = await this.getActor(message.system.source.actor);
if (!actor || !game.user.isGM) return true;
if (message.system.source.item && message.system.source.action) {
const action = this.getAction(actor, message.system.source.item, message.system.source.action);
if (!action || !action?.applyEffects) return;
const { isHit, targets } = this.getTargetList(event, message);
if (targets.length === 0)
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
await action.applyEffects(event, message, targets);
}
};
onTargetSelection = async (event, message) => {
event.stopPropagation();
const targetSelection = Boolean(event.target.dataset.targetHit),
msg = ui.chat.collection.get(message._id);
if (msg.system.targetSelection === targetSelection) return;
if (targetSelection !== true && !Array.from(game.user.targets).length)
return ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
msg.system.targetSelection = targetSelection;
msg.system.prepareDerivedData();
ui.chat.updateMessage(msg);
};
getTargetList = (event, message) => {
const targetSelection = event.target
.closest('.message-content')
.querySelector('.button-target-selection.target-selected'),
isHit = Boolean(targetSelection.dataset.targetHit);
return {
isHit,
targets: isHit
? message.system.targets.filter(t => t.hit === true).map(target => game.canvas.tokens.get(target.id))
: Array.from(game.user.targets)
};
};
hoverTarget = event => {
event.stopPropagation();
const token = canvas.tokens.get(event.currentTarget.dataset.token);
if (!token?.controlled) token._onHoverIn(event, { hoverOutOthers: true });
};
unhoverTarget = event => {
const token = canvas.tokens.get(event.currentTarget.dataset.token);
if (!token?.controlled) token._onHoverOut(event);
};
clickTarget = event => {
event.stopPropagation();
const token = canvas.tokens.get(event.currentTarget.dataset.token);
if (!token) {
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.AttackTargetDoesNotExist'));
return;
}
game.canvas.pan(token);
};
onDamage = async (event, message) => {
event.stopPropagation();
const { isHit, targets } = this.getTargetList(event, message);
if (message.system.onSave && isHit) {
const pendingingSaves = message.system.targets.filter(
target => target.hit && target.saved.success === null
);
if (pendingingSaves.length) {
const confirm = await foundry.applications.api.DialogV2.confirm({
window: { title: 'Pending Reaction Rolls found' },
content: `<p>Some Tokens still need to roll their Reaction Roll.</p><p>Are you sure you want to continue ?</p><p><i>Undone reaction rolls will be considered as failed</i></p>`
});
if (!confirm) return;
}
}
if (targets.length === 0)
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
for (let target of targets) {
let damage = message.system.roll.total;
if (message.system.onSave && message.system.targets.find(t => t.id === target.id)?.saved?.success === true)
damage = Math.ceil(damage * (CONFIG.DH.ACTIONS.damageOnSave[message.system.onSave]?.mod ?? 1));
await target.actor.takeDamage(damage, message.system.roll.type);
}
};
onHealing = async (event, message) => {
event.stopPropagation();
const targets = Array.from(game.user.targets);
if (targets.length === 0)
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.NoTargetsSelected'));
for (var target of targets) {
await target.actor.takeHealing([{ value: message.system.roll.total, type: message.system.roll.type }]);
}
};
onToggleTargets = async event => {
event.stopPropagation();
$($(event.currentTarget).parent()).find('.target-container').toggleClass('hidden');
};
hoverAdvantage = event => {
$(event.currentTarget).siblings('.advantage').toggleClass('unused');
};
selectAdvantage = async (event, message) => {
event.stopPropagation();
const updateMessage = game.messages.get(message._id);
await updateMessage.update({ system: { advantageSelected: event.currentTarget.id === 'hope' ? 1 : 2 } });
$(event.currentTarget).siblings('.advantage').off('click');
$(event.currentTarget).off('click');
};
abilityUseButton = async (event, message) => {
event.stopPropagation();
const action = message.system.actions[Number.parseInt(event.currentTarget.dataset.index)];
const actor = game.actors.get(message.system.source.actor);
await actor.useAction(action);
};
actionUseButton = async (_, message) => {
const parent = await foundry.utils.fromUuid(message.system.actor);
const actionType = Object.values(message.system.moves)[0].actions[0];
const cls = CONFIG.DH.ACTIONS.actionTypes[actionType.type];
const action = new cls(
{ ...actionType, _id: foundry.utils.randomID(), name: game.i18n.localize(actionType.name) },
{ parent: parent }
);
action.use();
};
}

View file

@ -0,0 +1,109 @@
import { EncounterCountdowns } from '../ui/countdowns.mjs';
export default class DhCombatTracker extends foundry.applications.sidebar.tabs.CombatTracker {
static DEFAULT_OPTIONS = {
actions: {
requestSpotlight: this.requestSpotlight,
toggleSpotlight: this.toggleSpotlight,
setActionTokens: this.setActionTokens,
openCountdowns: this.openCountdowns
}
};
static PARTS = {
header: {
template: 'systems/daggerheart/templates/ui/combatTracker/combatTrackerHeader.hbs'
},
tracker: {
template: 'systems/daggerheart/templates/ui/combatTracker/combatTracker.hbs'
},
footer: {
template: 'systems/daggerheart/templates/ui/combatTracker/combatTrackerFooter.hbs'
}
};
async _prepareCombatContext(context, options) {
await super._prepareCombatContext(context, options);
Object.assign(context, {
fear: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear)
});
}
async _prepareTrackerContext(context, options) {
await super._prepareTrackerContext(context, options);
const adversaries = context.turns?.filter(x => x.isNPC) ?? [];
const characters = context.turns?.filter(x => !x.isNPC) ?? [];
Object.assign(context, {
actionTokens: game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).actionTokens,
adversaries,
characters
});
}
async _prepareTurnContext(combat, combatant, index) {
const turn = await super._prepareTurnContext(combat, combatant, index);
return { ...turn, isNPC: combatant.isNPC, system: combatant.system.toObject() };
}
_getCombatContextOptions() {
return [
{
name: 'COMBAT.ClearMovementHistories',
icon: '<i class="fa-solid fa-shoe-prints"></i>',
condition: () => game.user.isGM && this.viewed?.combatants.size > 0,
callback: () => this.viewed.clearMovementHistories()
},
{
name: 'COMBAT.Delete',
icon: '<i class="fa-solid fa-trash"></i>',
condition: () => game.user.isGM && !!this.viewed,
callback: () => this.viewed.endCombat()
}
];
}
static async requestSpotlight(_, target) {
const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {};
const combatant = this.viewed.combatants.get(combatantId);
await combatant.update({
'system.spotlight': {
requesting: !combatant.system.spotlight.requesting
}
});
this.render();
}
static async toggleSpotlight(_, target) {
const { combatantId } = target.closest('[data-combatant-id]')?.dataset ?? {};
const combatant = this.viewed.combatants.get(combatantId);
const toggleTurn = this.viewed.combatants.contents
.sort(this.viewed._sortCombatants)
.map(x => x.id)
.indexOf(combatantId);
if (this.viewed.turn !== toggleTurn) Hooks.callAll(CONFIG.DH.HOOKS.spotlight, {});
await this.viewed.update({ turn: this.viewed.turn === toggleTurn ? null : toggleTurn });
await combatant.update({ 'system.spotlight.requesting': false });
}
static async setActionTokens(_, target) {
const { combatantId, tokenIndex } = target.closest('[data-combatant-id]')?.dataset ?? {};
const combatant = this.viewed.combatants.get(combatantId);
const changeIndex = Number(tokenIndex);
const newIndex = combatant.system.actionTokens > changeIndex ? changeIndex : changeIndex + 1;
await combatant.update({ 'system.actionTokens': newIndex });
this.render();
}
static openCountdowns() {
new EncounterCountdowns().open();
}
}

View file

@ -1,7 +1,7 @@
import { countdownTypes } from '../config/generalConfig.mjs';
import { GMUpdateEvent, RefreshType, socketEvent } from '../helpers/socket.mjs';
import constructHTMLButton from '../helpers/utils.mjs';
import OwnershipSelection from './ownershipSelection.mjs';
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;
@ -41,7 +41,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
static PARTS = {
countdowns: {
template: 'systems/daggerheart/templates/views/countdowns.hbs',
template: 'systems/daggerheart/templates/ui/countdowns.hbs',
scrollable: ['.expanded-view']
}
};
@ -57,18 +57,18 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
async _preFirstRender(context, options) {
options.position =
game.user.getFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].position) ??
game.user.getFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].position) ??
Countdowns.DEFAULT_OPTIONS.position;
const viewSetting =
game.user.getFlag(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].simple) ?? !game.user.isGM;
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(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].position, position);
game.user.setFlag(CONFIG.DH.id, CONFIG.DH.FLAGS[`${this.basePath}Countdown`].position, position);
}
async _renderFrame(options) {
@ -90,7 +90,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
if (game.user.isGM) return true;
const settings =
altSettings ?? game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
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
@ -100,7 +100,9 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
const countdownData = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
const countdownData = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[
this.basePath
];
context.isGM = game.user.isGM;
context.base = this.basePath;
@ -131,19 +133,19 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
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(),
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns).toObject(),
data
);
if (game.user.isGM) {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, newSetting);
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, newSetting);
this.render();
} else {
await game.socket.emit(`system.${SYSTEM.id}`, {
await game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateSetting,
uuid: SYSTEM.SETTINGS.gameSettings.Countdowns,
uuid: CONFIG.DH.SETTINGS.gameSettings.Countdowns,
update: newSetting
}
});
@ -152,8 +154,8 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
async updateSetting(update) {
if (game.user.isGM) {
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, update);
await game.socket.emit(`system.${SYSTEM.id}`, {
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,
@ -163,11 +165,11 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
this.render();
} else {
await game.socket.emit(`system.${SYSTEM.id}`, {
await game.socket.emit(`system.${CONFIG.DH.id}`, {
action: socketEvent.GMUpdate,
data: {
action: GMUpdateEvent.UpdateSetting,
uuid: SYSTEM.SETTINGS.gameSettings.Countdowns,
uuid: CONFIG.DH.SETTINGS.gameSettings.Countdowns,
update: update,
refresh: { refreshType: RefreshType.Countdown, application: `${this.basePath}-countdowns` }
}
@ -176,7 +178,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
}
static onEditImage(_, target) {
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
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,
@ -189,7 +191,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
}
async updateImage(path, countdown) {
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
await setting.updateSource({
[`${this.basePath}.countdowns.${countdown}.img`]: path
});
@ -199,16 +201,16 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
static openOwnership(_, target) {
new Promise((resolve, reject) => {
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
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(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
const setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns);
await setting.updateSource({
[`${this.basePath}.ownership`]: ownership
});
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, setting.toObject());
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns, setting.toObject());
this.render();
});
}
@ -216,29 +218,29 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
static openCountdownOwnership(_, target) {
const countdownId = target.dataset.countdown;
new Promise((resolve, reject) => {
const countdown = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath]
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(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
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(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, setting);
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(SYSTEM.id, SYSTEM.FLAGS[`${this.basePath}Countdown`].simple, 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(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
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)) {
@ -260,7 +262,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
}
static async addCountdown() {
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
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'),
@ -278,7 +280,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
}
static async removeCountdown(_, target) {
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
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({
@ -297,8 +299,9 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
async open() {
await this.render(true);
if (
Object.keys(game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath].countdowns)
.length > 0
Object.keys(
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Countdowns)[this.basePath].countdowns
).length > 0
) {
this.minimize();
}
@ -327,8 +330,8 @@ export class EncounterCountdowns extends Countdowns {
export const registerCountdownApplicationHooks = () => {
const updateCountdowns = async shouldProgress => {
if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation).countdowns) {
const countdownSetting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns);
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) {
@ -339,7 +342,11 @@ export const registerCountdownApplicationHooks = () => {
[`${countdownCategoryKey}.countdowns.${countdownKey}.progress.current`]:
countdown.progress.current - 1
});
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns, countdownSetting);
await game.settings.set(
CONFIG.DH.id,
CONFIG.DH.SETTINGS.gameSettings.Countdowns,
countdownSetting
);
foundry.applications.instances.get(`${countdownCategoryKey}-countdowns`)?.render();
}
}
@ -347,7 +354,7 @@ export const registerCountdownApplicationHooks = () => {
}
};
Hooks.on(SYSTEM.HOOKS.characterAttack, async () => {
Hooks.on(CONFIG.DH.HOOKS.characterAttack, async () => {
updateCountdowns(countdown => {
return (
countdown.progress.type.value === countdownTypes.characterAttack.id && countdown.progress.current > 0
@ -355,7 +362,7 @@ export const registerCountdownApplicationHooks = () => {
});
});
Hooks.on(SYSTEM.HOOKS.spotlight, async () => {
Hooks.on(CONFIG.DH.HOOKS.spotlight, async () => {
updateCountdowns(countdown => {
return countdown.progress.type.value === countdownTypes.spotlight.id && countdown.progress.current > 0;
});

View file

@ -8,7 +8,7 @@ const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
* @mixes HandlebarsApplication
*/
export default class Resources extends HandlebarsApplicationMixin(ApplicationV2) {
export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV2) {
constructor(options = {}) {
super(options);
}
@ -26,8 +26,8 @@ export default class Resources extends HandlebarsApplicationMixin(ApplicationV2)
minimizable: false
},
actions: {
setFear: Resources.setFear,
increaseFear: Resources.increaseFear
setFear: FearTracker.setFear,
increaseFear: FearTracker.increaseFear
},
position: {
width: 222,
@ -41,16 +41,16 @@ export default class Resources extends HandlebarsApplicationMixin(ApplicationV2)
static PARTS = {
resources: {
root: true,
template: 'systems/daggerheart/templates/views/resources.hbs'
template: 'systems/daggerheart/templates/ui/fearTracker.hbs'
}
};
get currentFear() {
return game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
return game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear);
}
get maxFear() {
return game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Homebrew).maxFear;
return game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxFear;
}
/* -------------------------------------------- */
@ -59,7 +59,7 @@ export default class Resources extends HandlebarsApplicationMixin(ApplicationV2)
/** @override */
async _prepareContext(_options) {
const display = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear,
const display = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).displayFear,
current = this.currentFear,
max = this.maxFear,
percent = (current / max) * 100,
@ -70,17 +70,18 @@ export default class Resources extends HandlebarsApplicationMixin(ApplicationV2)
/** @override */
async _preFirstRender(context, options) {
options.position = game.user.getFlag(SYSTEM.id, 'app.resources.position') ?? Resources.DEFAULT_OPTIONS.position;
options.position =
game.user.getFlag(CONFIG.DH.id, 'app.resources.position') ?? FearTracker.DEFAULT_OPTIONS.position;
}
/** @override */
async _preRender(context, options) {
if (this.currentFear > this.maxFear)
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, this.maxFear);
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, this.maxFear);
}
_onPosition(position) {
game.user.setFlag(SYSTEM.id, 'app.resources.position', position);
game.user.setFlag(CONFIG.DH.id, 'app.resources.position', position);
}
async close(options = {}) {
@ -104,6 +105,6 @@ export default class Resources extends HandlebarsApplicationMixin(ApplicationV2)
async updateFear(value) {
if (!game.user.isGM) return;
value = Math.max(0, Math.min(this.maxFear, value));
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, value);
await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear, value);
}
}

View file

@ -1 +1,2 @@
export { default as FilterMenu } from './filter-menu.mjs';
export { default as ContextMenu } from './contextMenu.mjs';

View file

@ -19,7 +19,8 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
const mergedOptions = {
eventName: 'click',
fixed: true,
...options
...options,
jQuery: false
};
super(container, selector, menuItems, mergedOptions);
@ -176,7 +177,7 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
}
}));
const burdenFilter = Object.values(CONFIG.daggerheart.GENERAL.burden).map(({ value, label }) => ({
const burdenFilter = Object.values(CONFIG.DH.GENERAL.burden).map(({ value, label }) => ({
group: game.i18n.localize('DAGGERHEART.Sheets.Weapon.Burden'),
name: game.i18n.localize(label),
filter: {
@ -186,7 +187,7 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
}
}));
const damageTypeFilter = Object.values(CONFIG.daggerheart.GENERAL.damageTypes).map(({ id, abbreviation }) => ({
const damageTypeFilter = Object.values(CONFIG.DH.GENERAL.damageTypes).map(({ id, abbreviation }) => ({
group: 'Damage Type', //TODO localize
name: game.i18n.localize(abbreviation),
filter: {
@ -210,7 +211,7 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
static get cardsFilters() {
const { OPERATORS } = foundry.applications.ux.SearchFilter;
const typesFilters = Object.values(CONFIG.daggerheart.DOMAIN.cardTypes).map(({ id, label }) => ({
const typesFilters = Object.values(CONFIG.DH.DOMAIN.cardTypes).map(({ id, label }) => ({
group: game.i18n.localize('Type'),
name: game.i18n.localize(label),
filter: {
@ -220,7 +221,7 @@ export default class FilterMenu extends foundry.applications.ux.ContextMenu {
}
}));
const domainFilter = Object.values(CONFIG.daggerheart.DOMAIN.domains).map(({ id, label }) => ({
const domainFilter = Object.values(CONFIG.DH.DOMAIN.domains).map(({ id, label }) => ({
group: game.i18n.localize('DAGGERHEART.Sheets.DomainCard.Domain'),
name: game.i18n.localize(label),
filter: {