mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
[PR] [Feature] 590 - Daggerheart Menu (#1007)
* Added menu with refresh tools * Replaced menu icon
This commit is contained in:
parent
eefb28c312
commit
f1b6d3851d
53 changed files with 730 additions and 350 deletions
|
|
@ -44,12 +44,14 @@ We encourage contributors to leave comments or open Discussions when proposing s
|
|||
## 🧾 Issue & PR Best Practices
|
||||
|
||||
**For Issues:**
|
||||
|
||||
- Use clear, descriptive titles
|
||||
- Provide a concise explanation of the problem or idea
|
||||
- Include reproduction steps or example scenarios if it's a bug
|
||||
- Add screenshots or logs if helpful
|
||||
|
||||
**For Pull Requests:**
|
||||
|
||||
- Use a clear title summarizing the change
|
||||
- Provide a brief description of what your code does and why
|
||||
- Link to any related Issues
|
||||
|
|
@ -71,6 +73,6 @@ Discussions are currently happening on GitHub — in Issues, PRs, and [GitHub Di
|
|||
|
||||
## 🤗 Thank You!
|
||||
|
||||
Whether you're fixing a typo or designing entire mechanics — every contribution matters. Thank you for helping bring *Daggerheart* to life in FoundryVTT through **Foundryborne**!
|
||||
Whether you're fixing a typo or designing entire mechanics — every contribution matters. Thank you for helping bring _Daggerheart_ to life in FoundryVTT through **Foundryborne**!
|
||||
|
||||
🐸🛠️
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ Hooks.once('init', () => {
|
|||
CONFIG.ui.combat = applications.ui.DhCombatTracker;
|
||||
CONFIG.ui.chat = applications.ui.DhChatLog;
|
||||
CONFIG.ui.hotbar = applications.ui.DhHotbar;
|
||||
CONFIG.ui.sidebar = applications.sidebar.DhSidebar;
|
||||
CONFIG.ui.daggerheartMenu = applications.sidebar.DaggerheartMenu;
|
||||
CONFIG.Token.rulerClass = placeables.DhTokenRuler;
|
||||
|
||||
CONFIG.ui.resources = applications.ui.DhFearTracker;
|
||||
|
|
@ -309,5 +311,5 @@ Hooks.on('moveToken', async (movedToken, data) => {
|
|||
}
|
||||
});
|
||||
|
||||
Hooks.on("renderCompendiumDirectory", (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
|
||||
Hooks.on("renderDocumentDirectory", (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
|
||||
Hooks.on('renderCompendiumDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
|
||||
Hooks.on('renderDocumentDirectory', (app, html) => applications.ui.ItemBrowser.injectSidebarButton(html));
|
||||
|
|
|
|||
12
lang/en.json
12
lang/en.json
|
|
@ -2420,6 +2420,10 @@
|
|||
"heal": "Heal",
|
||||
"applyHealing": "Apply Healing"
|
||||
},
|
||||
"refreshMessage": {
|
||||
"title": "Feature Refresh",
|
||||
"header": "Refreshed"
|
||||
},
|
||||
"reroll": {
|
||||
"confirmTitle": "Reroll Dice",
|
||||
"confirmText": "Are you sure you want to reroll?"
|
||||
|
|
@ -2534,8 +2538,16 @@
|
|||
"multiclassAlreadyPresent": "You already have a class and multiclass",
|
||||
"subclassesAlreadyPresent": "You already have a class and multiclass subclass",
|
||||
"noDiceSystem": "Your selected dice {system} does not have a {faces} dice",
|
||||
"gmMenuRefresh": "You refreshed all actions and resources {types}",
|
||||
"subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class."
|
||||
},
|
||||
"Sidebar": {
|
||||
"daggerheartMenu": {
|
||||
"title": "Daggerheart Menu",
|
||||
"startSession": "Start Session",
|
||||
"startScene": "Start Scene"
|
||||
}
|
||||
},
|
||||
"Tooltip": {
|
||||
"disableEffect": "Disable Effect",
|
||||
"enableEffect": "Enable Effect",
|
||||
|
|
|
|||
|
|
@ -6,5 +6,6 @@ export * as scene from './scene/_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 sidebar from './sidebar/_module.mjs';
|
||||
export * as ui from './ui/_module.mjs';
|
||||
export * as ux from './ux/_module.mjs';
|
||||
|
|
|
|||
|
|
@ -7,19 +7,18 @@ export default class DhSceneConfigSettings extends foundry.applications.sheets.S
|
|||
const { footer, ...parts } = super.PARTS;
|
||||
const tmpParts = {
|
||||
...parts,
|
||||
dh: { template: "systems/daggerheart/templates/scene/dh-config.hbs" },
|
||||
dh: { template: 'systems/daggerheart/templates/scene/dh-config.hbs' },
|
||||
footer
|
||||
}
|
||||
};
|
||||
return tmpParts;
|
||||
}
|
||||
|
||||
static PARTS = DhSceneConfigSettings.buildParts();
|
||||
|
||||
static buildTabs() {
|
||||
super.TABS.sheet.tabs.push({ id: "dh", icon: "fa-solid" });
|
||||
super.TABS.sheet.tabs.push({ id: 'dh', icon: 'fa-solid' });
|
||||
return super.TABS;
|
||||
}
|
||||
|
||||
static TABS = DhSceneConfigSettings.buildTabs();
|
||||
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
main: { template: 'systems/daggerheart/templates/settings/appearance-settings/main.hbs' },
|
||||
diceSoNice: { template: 'systems/daggerheart/templates/settings/appearance-settings/diceSoNice.hbs' },
|
||||
footer: { template: "templates/generic/form-footer.hbs" }
|
||||
footer: { template: 'templates/generic/form-footer.hbs' }
|
||||
};
|
||||
|
||||
/** @inheritdoc */
|
||||
|
|
@ -41,7 +41,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
general: {
|
||||
tabs: [
|
||||
{ id: 'main', label: 'DAGGERHEART.GENERAL.Tabs.general' },
|
||||
{ id: 'diceSoNice', label: 'DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.title' },
|
||||
{ id: 'diceSoNice', label: 'DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.title' }
|
||||
],
|
||||
initial: 'main'
|
||||
},
|
||||
|
|
@ -83,7 +83,8 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
/**@inheritdoc */
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
if (options.isFirstRender) this.setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
||||
if (options.isFirstRender)
|
||||
this.setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance);
|
||||
|
||||
context.setting = this.setting;
|
||||
context.fields = this.setting.schema.fields;
|
||||
|
|
@ -99,18 +100,17 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
const partContext = await super._preparePartContext(partId, context, options);
|
||||
if (partId in context.tabs) partContext.tab = partContext.tabs[partId];
|
||||
switch (partId) {
|
||||
case "diceSoNice":
|
||||
case 'diceSoNice':
|
||||
await this.prepareDiceSoNiceContext(partContext);
|
||||
break;
|
||||
case "footer":
|
||||
case 'footer':
|
||||
partContext.buttons = [
|
||||
{ type: "button", action: "reset", icon: "fa-solid fa-arrow-rotate-left", label: "Reset" },
|
||||
{ type: "submit", icon: "fa-solid fa-floppy-disk", label: "Save Changes" }
|
||||
{ type: 'button', action: 'reset', icon: 'fa-solid fa-arrow-rotate-left', label: 'Reset' },
|
||||
{ type: 'submit', icon: 'fa-solid fa-floppy-disk', label: 'Save Changes' }
|
||||
];
|
||||
break;
|
||||
}
|
||||
return partContext;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -120,32 +120,44 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
* @protected
|
||||
*/
|
||||
async prepareDiceSoNiceContext(context) {
|
||||
context.diceSoNiceTextures = Object.entries(game.dice3d.exports.TEXTURELIST).reduce((acc, [k, v]) => ({
|
||||
context.diceSoNiceTextures = Object.entries(game.dice3d.exports.TEXTURELIST).reduce(
|
||||
(acc, [k, v]) => ({
|
||||
...acc,
|
||||
[k]: v.name
|
||||
}), {});
|
||||
context.diceSoNiceColorsets = Object.values(game.dice3d.exports.COLORSETS).reduce((acc, v) => ({
|
||||
}),
|
||||
{}
|
||||
);
|
||||
context.diceSoNiceColorsets = Object.values(game.dice3d.exports.COLORSETS).reduce(
|
||||
(acc, v) => ({
|
||||
...acc,
|
||||
[v.id]: v.description
|
||||
}), {});
|
||||
context.diceSoNiceMaterials = Object.keys(game.dice3d.DiceFactory.material_options).reduce((acc, key) => ({
|
||||
}),
|
||||
{}
|
||||
);
|
||||
context.diceSoNiceMaterials = Object.keys(game.dice3d.DiceFactory.material_options).reduce(
|
||||
(acc, key) => ({
|
||||
...acc,
|
||||
[key]: `DICESONICE.Material${key.capitalize()}`
|
||||
}), {});
|
||||
context.diceSoNiceSystems = Object.fromEntries([...game.dice3d.DiceFactory.systems].map(([k, v]) => [k, v.name]));
|
||||
}),
|
||||
{}
|
||||
);
|
||||
context.diceSoNiceSystems = Object.fromEntries(
|
||||
[...game.dice3d.DiceFactory.systems].map(([k, v]) => [k, v.name])
|
||||
);
|
||||
|
||||
foundry.utils.mergeObject(context.dsnTabs, [
|
||||
"hope",
|
||||
"fear",
|
||||
"advantage",
|
||||
"disadvantage",
|
||||
].reduce((acc, key) => ({
|
||||
foundry.utils.mergeObject(
|
||||
context.dsnTabs,
|
||||
['hope', 'fear', 'advantage', 'disadvantage'].reduce(
|
||||
(acc, key) => ({
|
||||
...acc,
|
||||
[key]: {
|
||||
values: this.setting.diceSoNice[key],
|
||||
fields: this.setting.schema.getField(`diceSoNice.${key}`).fields,
|
||||
fields: this.setting.schema.getField(`diceSoNice.${key}`).fields
|
||||
}
|
||||
}), {}));
|
||||
}),
|
||||
{}
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -169,7 +181,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
* @type {ApplicationClickAction}
|
||||
*/
|
||||
static async #onPreview(_, target) {
|
||||
const formData = new foundry.applications.ux.FormDataExtended(target.closest("form"));
|
||||
const formData = new foundry.applications.ux.FormDataExtended(target.closest('form'));
|
||||
const { diceSoNice } = foundry.utils.expandObject(formData.object);
|
||||
const { key } = target.dataset;
|
||||
const faces = ['advantage', 'disadvantage'].includes(key) ? 'd6' : 'd12';
|
||||
|
|
|
|||
|
|
@ -416,9 +416,12 @@ export default function DHApplicationMixin(Base) {
|
|||
icon: 'fa-solid fa-ban',
|
||||
condition: target => {
|
||||
const doc = getDocFromElementSync(target);
|
||||
return doc && doc.system?.actions?.some(a => a.type === "beastform");
|
||||
return doc && doc.system?.actions?.some(a => a.type === 'beastform');
|
||||
},
|
||||
callback: async target => game.system.api.fields.ActionFields.BeastformField.handleActiveTransformations.call(await getDocFromElement(target))
|
||||
callback: async target =>
|
||||
game.system.api.fields.ActionFields.BeastformField.handleActiveTransformations.call(
|
||||
await getDocFromElement(target)
|
||||
)
|
||||
});
|
||||
|
||||
options.unshift({
|
||||
|
|
@ -433,7 +436,7 @@ export default function DHApplicationMixin(Base) {
|
|||
action = doc?.system?.attack ?? doc;
|
||||
const config = action.prepareConfig(event);
|
||||
config.hasRoll = false;
|
||||
return action && action.workflow.get("damage").execute(config, null, true);
|
||||
return action && action.workflow.get('damage').execute(config, null, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
2
module/applications/sidebar/_module.mjs
Normal file
2
module/applications/sidebar/_module.mjs
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export { default as DaggerheartMenu } from './tabs/daggerheartMenu.mjs';
|
||||
export { default as DhSidebar } from './sidebar.mjs';
|
||||
33
module/applications/sidebar/sidebar.mjs
Normal file
33
module/applications/sidebar/sidebar.mjs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
export default class DhSidebar extends Sidebar {
|
||||
/** @override */
|
||||
static TABS = {
|
||||
...super.TABS,
|
||||
daggerheartMenu: {
|
||||
tooltip: 'DAGGERHEART.UI.Sidebar.daggerheartMenu.title',
|
||||
img: 'systems/daggerheart/assets/logos/FoundryBorneLogoWhite.svg'
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
tabs: {
|
||||
id: 'tabs',
|
||||
template: 'systems/daggerheart/templates/sidebar/tabs.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
async _prepareTabContext(context, options) {
|
||||
context.tabs = Object.entries(this.constructor.TABS).reduce((obj, [k, v]) => {
|
||||
let { documentName, gmOnly, tooltip, icon, img } = v;
|
||||
if (gmOnly && !game.user.isGM) return obj;
|
||||
if (documentName) {
|
||||
tooltip ??= getDocumentClass(documentName).metadata.labelPlural;
|
||||
icon ??= CONFIG[documentName]?.sidebarIcon;
|
||||
}
|
||||
obj[k] = { tooltip, icon, img };
|
||||
obj[k].active = this.tabGroups.primary === k;
|
||||
return obj;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
160
module/applications/sidebar/tabs/daggerheartMenu.mjs
Normal file
160
module/applications/sidebar/tabs/daggerheartMenu.mjs
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
const { HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
const { AbstractSidebarTab } = foundry.applications.sidebar;
|
||||
/**
|
||||
* The daggerheart menu tab.
|
||||
* @extends {AbstractSidebarTab}
|
||||
* @mixes HandlebarsApplication
|
||||
*/
|
||||
export default class DaggerheartMenu extends HandlebarsApplicationMixin(AbstractSidebarTab) {
|
||||
constructor(options) {
|
||||
super(options);
|
||||
|
||||
this.refreshSelections = DaggerheartMenu.#defaultRefreshSelections();
|
||||
}
|
||||
|
||||
static #defaultRefreshSelections() {
|
||||
return {
|
||||
session: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.session') },
|
||||
scene: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.scene') },
|
||||
longRest: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.longrest') },
|
||||
shortRest: { selected: false, label: game.i18n.localize('DAGGERHEART.GENERAL.RefreshType.shortrest') }
|
||||
};
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['dh-style'],
|
||||
window: {
|
||||
title: 'SIDEBAR.TabSettings'
|
||||
},
|
||||
actions: {
|
||||
selectRefreshable: DaggerheartMenu.#selectRefreshable,
|
||||
refreshActors: DaggerheartMenu.#refreshActors
|
||||
}
|
||||
};
|
||||
|
||||
/** @override */
|
||||
static tabName = 'daggerheartMenu';
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: { template: 'systems/daggerheart/templates/sidebar/daggerheart-menu/main.hbs' }
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.refreshables = this.refreshSelections;
|
||||
context.disableRefresh = Object.values(this.refreshSelections).every(x => !x.selected);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
async getRefreshables(types) {
|
||||
const refreshedActors = {};
|
||||
for (let actor of game.actors) {
|
||||
if (['character', 'adversary'].includes(actor.type) && actor.prototypeToken.actorLink) {
|
||||
const updates = {};
|
||||
for (let item of actor.items) {
|
||||
if (item.system.metadata.hasResource && types.includes(item.system.resource?.recovery)) {
|
||||
if (!refreshedActors[actor.id])
|
||||
refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() };
|
||||
refreshedActors[actor.id].refreshed.add(
|
||||
game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[item.system.resource.recovery].label)
|
||||
);
|
||||
|
||||
if (!updates[item.id]?.system) updates[item.id] = { system: {} };
|
||||
|
||||
const increasing =
|
||||
item.system.resource.progression === CONFIG.DH.ITEM.itemResourceProgression.increasing.id;
|
||||
updates[item.id].system = {
|
||||
...updates[item.id].system,
|
||||
'resource.value': increasing
|
||||
? 0
|
||||
: Roll.replaceFormulaData(item.system.resource.max, actor.getRollData())
|
||||
};
|
||||
}
|
||||
if (item.system.metadata.hasActions) {
|
||||
const refreshTypes = new Set();
|
||||
const actions = item.system.actions.filter(action => {
|
||||
if (types.includes(action.uses.recovery)) {
|
||||
refreshTypes.add(action.uses.recovery);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
if (actions.length === 0) continue;
|
||||
|
||||
if (!refreshedActors[actor.id])
|
||||
refreshedActors[actor.id] = { name: actor.name, img: actor.img, refreshed: new Set() };
|
||||
refreshedActors[actor.id].refreshed.add(
|
||||
...refreshTypes.map(type => game.i18n.localize(CONFIG.DH.GENERAL.refreshTypes[type].label))
|
||||
);
|
||||
|
||||
if (!updates[item.id]?.system) updates[item.id] = { system: {} };
|
||||
|
||||
updates[item.id].system = {
|
||||
...updates[item.id].system,
|
||||
...actions.reduce(
|
||||
(acc, action) => {
|
||||
acc.actions[action.id] = { 'uses.value': 0 };
|
||||
return acc;
|
||||
},
|
||||
{ actions: updates[item.id].system.actions ?? {} }
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
for (let key in updates) {
|
||||
const update = updates[key];
|
||||
await actor.items.get(key).update(update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return refreshedActors;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Application Clicks Actions */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static async #selectRefreshable(_event, button) {
|
||||
const { type } = button.dataset;
|
||||
this.refreshSelections[type].selected = !this.refreshSelections[type].selected;
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async #refreshActors() {
|
||||
const refreshKeys = Object.keys(this.refreshSelections).filter(key => this.refreshSelections[key].selected);
|
||||
await this.getRefreshables(refreshKeys);
|
||||
const types = refreshKeys.map(x => this.refreshSelections[x].label).join(', ');
|
||||
ui.notifications.info(
|
||||
game.i18n.format('DAGGERHEART.UI.Notifications.gmMenuRefresh', {
|
||||
types: `[${types}]`
|
||||
})
|
||||
);
|
||||
this.refreshSelections = DaggerheartMenu.#defaultRefreshSelections();
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
const msg = {
|
||||
user: game.user.id,
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/chat/refreshMessage.hbs',
|
||||
{
|
||||
types: types
|
||||
}
|
||||
),
|
||||
title: game.i18n.localize('DAGGERHEART.UI.Chat.refreshMessage.title'),
|
||||
speaker: cls.getSpeaker()
|
||||
};
|
||||
|
||||
cls.create(msg);
|
||||
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
|||
if (event.currentTarget.dataset.directDamage) {
|
||||
const config = action.prepareConfig(event);
|
||||
config.hasRoll = false;
|
||||
action.workflow.get("damage").execute(config, null, true);
|
||||
action.workflow.get('damage').execute(config, null, true);
|
||||
} else action.use(event);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { emitAsGM, GMUpdateEvent, socketEvent } from "../../systemRegistration/socket.mjs";
|
||||
import { emitAsGM, GMUpdateEvent, socketEvent } from '../../systemRegistration/socket.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
|
|
@ -106,6 +106,10 @@ export default class FearTracker extends HandlebarsApplicationMixin(ApplicationV
|
|||
}
|
||||
|
||||
async updateFear(value) {
|
||||
return emitAsGM(GMUpdateEvent.UpdateFear, game.settings.set.bind(game.settings, CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear), value);
|
||||
return emitAsGM(
|
||||
GMUpdateEvent.UpdateFear,
|
||||
game.settings.set.bind(game.settings, CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Resources.Fear),
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -86,10 +86,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
this.presets = options.presets ?? {};
|
||||
|
||||
const width = this.presets?.render?.noFolder === true || this.presets?.render?.lite === true ? 600 : 850;
|
||||
if(this.rendered)
|
||||
this.setPosition({ width });
|
||||
else
|
||||
options.position.width = width;
|
||||
if (this.rendered) this.setPosition({ width });
|
||||
else options.position.width = width;
|
||||
|
||||
await super._preRender(context, options);
|
||||
}
|
||||
|
|
@ -100,7 +98,9 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
|
||||
this.element
|
||||
.querySelectorAll('[data-action="selectFolder"]')
|
||||
.forEach(element => element.classList.toggle('is-selected', element.dataset.folderId === this.selectedMenu.path.join('.')));
|
||||
.forEach(element =>
|
||||
element.classList.toggle('is-selected', element.dataset.folderId === this.selectedMenu.path.join('.'))
|
||||
);
|
||||
|
||||
this._createSearchFilter();
|
||||
|
||||
|
|
@ -108,7 +108,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
this.element.classList.toggle('no-folder', this.presets?.render?.noFolder === true);
|
||||
this.element.classList.toggle('no-filter', this.presets?.render?.noFilter === true);
|
||||
this.element.querySelectorAll('.folder-list > [data-action="selectFolder"]').forEach(element => {
|
||||
element.hidden = this.presets.render?.folders?.length && !this.presets.render.folders.includes(element.dataset.folderId);
|
||||
element.hidden =
|
||||
this.presets.render?.folders?.length && !this.presets.render.folders.includes(element.dataset.folderId);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -157,7 +158,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
: [];
|
||||
folders.push(folder);
|
||||
});
|
||||
folders.sort((a, b) => a.label.localeCompare(b.label))
|
||||
folders.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
return folders;
|
||||
}
|
||||
|
|
@ -181,8 +182,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
|
||||
await this.render({ force: true, presets: this.presets });
|
||||
|
||||
if(this.selectedMenu?.data?.type?.length)
|
||||
this.loadItems();
|
||||
if (this.selectedMenu?.data?.type?.length) this.loadItems();
|
||||
}
|
||||
|
||||
_replaceHTML(result, content, options) {
|
||||
|
|
@ -201,24 +201,26 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
const items = await pack.getDocuments({ type__in: this.selectedMenu?.data?.type });
|
||||
resolve(items);
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
Promise.all(promises).then(async result => {
|
||||
this.items = ItemBrowser.sortBy(result.flatMap(r => r), 'name');
|
||||
this.items = ItemBrowser.sortBy(
|
||||
result.flatMap(r => r),
|
||||
'name'
|
||||
);
|
||||
this.fieldFilter = this._createFieldFilter();
|
||||
|
||||
if (this.presets?.filter) {
|
||||
Object.entries(this.presets.filter).forEach(
|
||||
([k, v]) => {
|
||||
const filter = this.fieldFilter.find(c => c.name === k)
|
||||
Object.entries(this.presets.filter).forEach(([k, v]) => {
|
||||
const filter = this.fieldFilter.find(c => c.name === k);
|
||||
if (filter) filter.value = v.value;
|
||||
}
|
||||
);
|
||||
});
|
||||
// await this._onInputFilterBrowser();
|
||||
}
|
||||
|
||||
const filterList = await foundry.applications.handlebars.renderTemplate('systems/daggerheart/templates/ui/itemBrowser/filterContainer.hbs',
|
||||
const filterList = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/itemBrowser/filterContainer.hbs',
|
||||
{
|
||||
fieldFilter: this.fieldFilter,
|
||||
presets: this.presets,
|
||||
|
|
@ -228,12 +230,11 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
|
||||
this.element.querySelector('.filter-content .wrapper').innerHTML = filterList;
|
||||
const filterContainer = this.element.querySelector('.filter-header > [data-action="expandContent"]');
|
||||
if(this.fieldFilter.length === 0)
|
||||
filterContainer.setAttribute('disabled', '');
|
||||
else
|
||||
filterContainer.removeAttribute('disabled');
|
||||
if (this.fieldFilter.length === 0) filterContainer.setAttribute('disabled', '');
|
||||
else filterContainer.removeAttribute('disabled');
|
||||
|
||||
const itemList = await foundry.applications.handlebars.renderTemplate('systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
|
||||
const itemList = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
|
||||
{
|
||||
items: this.items,
|
||||
menu: this.selectedMenu,
|
||||
|
|
@ -255,7 +256,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
toggleLoader(state) {
|
||||
const container = this.element.querySelector('.item-list');
|
||||
return setTimeout(() => {
|
||||
container.classList.toggle("loader", state);
|
||||
container.classList.toggle('loader', state);
|
||||
}, 100);
|
||||
}
|
||||
|
||||
|
|
@ -509,13 +510,13 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
const sectionId = html.dataset.tab,
|
||||
menus = {
|
||||
actors: {
|
||||
folder: "adversaries",
|
||||
folder: 'adversaries',
|
||||
render: {
|
||||
folders: ["adversaries", "characters", "environments"]
|
||||
folders: ['adversaries', 'characters', 'environments']
|
||||
}
|
||||
},
|
||||
items: {
|
||||
folder: "equipments",
|
||||
folder: 'equipments',
|
||||
render: {
|
||||
noFolder: true
|
||||
}
|
||||
|
|
@ -524,16 +525,16 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
};
|
||||
|
||||
if (Object.keys(menus).includes(sectionId)) {
|
||||
const headerActions = html.querySelector(".header-actions");
|
||||
const headerActions = html.querySelector('.header-actions');
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.classList.add("open-compendium-browser");
|
||||
const button = document.createElement('button');
|
||||
button.type = 'button';
|
||||
button.classList.add('open-compendium-browser');
|
||||
button.innerHTML = `
|
||||
<i class="fa-solid fa-book-atlas"></i>
|
||||
${game.i18n.localize("DAGGERHEART.UI.Tooltip.compendiumBrowser")}
|
||||
${game.i18n.localize('DAGGERHEART.UI.Tooltip.compendiumBrowser')}
|
||||
`;
|
||||
button.addEventListener("click", event => {
|
||||
button.addEventListener('click', event => {
|
||||
ui.compendiumBrowser.open(menus[sectionId]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -199,8 +199,7 @@ export const typeConfig = {
|
|||
key: 'system.itemFeatures',
|
||||
label: 'DAGGERHEART.GENERAL.features',
|
||||
choices: () =>
|
||||
Object.entries(CONFIG.DH.ITEM.weaponFeatures)
|
||||
.map(([k, v]) => ({ value: k, label: v.label })),
|
||||
Object.entries(CONFIG.DH.ITEM.weaponFeatures).map(([k, v]) => ({ value: k, label: v.label })),
|
||||
operator: 'contains3'
|
||||
}
|
||||
]
|
||||
|
|
@ -241,8 +240,7 @@ export const typeConfig = {
|
|||
key: 'system.itemFeatures',
|
||||
label: 'DAGGERHEART.GENERAL.features',
|
||||
choices: () =>
|
||||
Object.entries(CONFIG.DH.ITEM.armorFeatures)
|
||||
.map(([k, v]) => ({ value: k, label: v.label })),
|
||||
Object.entries(CONFIG.DH.ITEM.armorFeatures).map(([k, v]) => ({ value: k, label: v.label })),
|
||||
operator: 'contains3'
|
||||
}
|
||||
]
|
||||
|
|
@ -372,14 +370,30 @@ export const typeConfig = {
|
|||
label: 'DAGGERHEART.ITEMS.Subclass.spellcastingTrait'
|
||||
}
|
||||
],
|
||||
filters: []
|
||||
},
|
||||
beastforms: {
|
||||
columns: [
|
||||
{
|
||||
key: 'system.tier',
|
||||
label: 'DAGGERHEART.GENERAL.Tiers.singular'
|
||||
},
|
||||
{
|
||||
key: 'system.mainTrait',
|
||||
label: 'DAGGERHEART.GENERAL.Trait.single'
|
||||
}
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
key: 'system.linkedClass.uuid',
|
||||
label: 'Class',
|
||||
choices: (items) => {
|
||||
const list = items.map(item => ({ value: item.system.linkedClass.uuid, label: item.system.linkedClass.name }));
|
||||
choices: items => {
|
||||
const list = items.map(item => ({
|
||||
value: item.system.linkedClass.uuid,
|
||||
label: item.system.linkedClass.name
|
||||
}));
|
||||
return list.reduce((a, c) => {
|
||||
if(!(a.find(i => i.value === c.value))) a.push(c);
|
||||
if (!a.find(i => i.value === c.value)) a.push(c);
|
||||
return a;
|
||||
}, []);
|
||||
}
|
||||
|
|
@ -417,7 +431,7 @@ export const compendiumConfig = {
|
|||
id: 'characters',
|
||||
keys: ['characters'],
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.folders.characters',
|
||||
type: ['character'],
|
||||
type: ['character']
|
||||
// listType: 'characters'
|
||||
},
|
||||
adversaries: {
|
||||
|
|
@ -431,7 +445,7 @@ export const compendiumConfig = {
|
|||
id: 'ancestries',
|
||||
keys: ['ancestries'],
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.folders.ancestries',
|
||||
type: ['ancestry'],
|
||||
type: ['ancestry']
|
||||
/* folders: {
|
||||
features: {
|
||||
id: 'features',
|
||||
|
|
@ -516,7 +530,7 @@ export const compendiumConfig = {
|
|||
id: 'communities',
|
||||
keys: ['communities'],
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.folders.communities',
|
||||
type: ['community'],
|
||||
type: ['community']
|
||||
/* folders: {
|
||||
features: {
|
||||
id: 'features',
|
||||
|
|
@ -537,7 +551,7 @@ export const compendiumConfig = {
|
|||
keys: ['beastforms'],
|
||||
label: 'DAGGERHEART.UI.ItemBrowser.folders.beastforms',
|
||||
type: ['beastform'],
|
||||
listType: 'beastforms',
|
||||
listType: 'beastforms'
|
||||
/* folders: {
|
||||
features: {
|
||||
id: 'features',
|
||||
|
|
|
|||
|
|
@ -32,19 +32,19 @@ export const gameSettings = {
|
|||
|
||||
export const actionAutomationChoices = {
|
||||
never: {
|
||||
id: "never",
|
||||
label: "Never"
|
||||
id: 'never',
|
||||
label: 'Never'
|
||||
},
|
||||
showDialog: {
|
||||
id: "showDialog",
|
||||
label: "Show Dialog only"
|
||||
id: 'showDialog',
|
||||
label: 'Show Dialog only'
|
||||
},
|
||||
// npcOnly: {
|
||||
// id: "npcOnly",
|
||||
// label: "Always for non-characters"
|
||||
// },
|
||||
always: {
|
||||
id: "always",
|
||||
label: "Always"
|
||||
}
|
||||
id: 'always',
|
||||
label: 'Always'
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,8 +34,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
|
||||
this.extraSchemas.forEach(s => {
|
||||
let clsField = this.getActionField(s);
|
||||
if (clsField)
|
||||
schemaFields[s] = new clsField();
|
||||
if (clsField) schemaFields[s] = new clsField();
|
||||
});
|
||||
|
||||
return schemaFields;
|
||||
|
|
@ -54,7 +53,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
let clsField = this.constructor.getActionField(s);
|
||||
if (clsField?.execute) {
|
||||
workflow.set(s, { order: clsField.order, execute: clsField.execute.bind(this) });
|
||||
if( s === "damage" ) workflow.set("applyDamage", { order: 75, execute: clsField.applyDamage.bind(this) } );
|
||||
if (s === 'damage')
|
||||
workflow.set('applyDamage', { order: 75, execute: clsField.applyDamage.bind(this) });
|
||||
}
|
||||
});
|
||||
return new Map([...workflow.entries()].sort(([aKey, aValue], [bKey, bValue]) => aValue.order - bValue.order));
|
||||
|
|
@ -64,9 +64,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
* Getter returning the workflow property or creating it the first time the property is called
|
||||
*/
|
||||
get workflow() {
|
||||
if ( this.hasOwnProperty("_workflow") ) return this._workflow;
|
||||
if (this.hasOwnProperty('_workflow')) return this._workflow;
|
||||
const workflow = Object.freeze(this.defineWorkflow());
|
||||
Object.defineProperty(this, "_workflow", {value: workflow, writable: false});
|
||||
Object.defineProperty(this, '_workflow', { value: workflow, writable: false });
|
||||
return workflow;
|
||||
}
|
||||
|
||||
|
|
@ -169,7 +169,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
async executeWorkflow(config) {
|
||||
for (const [key, part] of this.workflow) {
|
||||
if (Hooks.call(`${CONFIG.DH.id}.pre${key.capitalize()}Action`, this, config) === false) return;
|
||||
if(await part.execute(config) === false) return;
|
||||
if ((await part.execute(config)) === false) return;
|
||||
if (Hooks.call(`${CONFIG.DH.id}.post${key.capitalize()}Action`, this, config) === false) return;
|
||||
}
|
||||
}
|
||||
|
|
@ -241,8 +241,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
prepareConfig(event) {
|
||||
const config = this.prepareBaseConfig(event);
|
||||
for (const clsField of Object.values(this.schema.fields)) {
|
||||
if (clsField?.prepareConfig)
|
||||
if(clsField.prepareConfig.call(this, config) === false) return false;
|
||||
if (clsField?.prepareConfig) if (clsField.prepareConfig.call(this, config) === false) return false;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
|
@ -263,8 +262,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
* @param {boolean} successCost
|
||||
*/
|
||||
async consume(config, successCost = false) {
|
||||
await this.workflow.get("cost")?.execute(config, successCost);
|
||||
await this.workflow.get("uses")?.execute(config, successCost);
|
||||
await this.workflow.get('cost')?.execute(config, successCost);
|
||||
await this.workflow.get('uses')?.execute(config, successCost);
|
||||
|
||||
if (config.roll && !config.roll.success && successCost) {
|
||||
setTimeout(() => {
|
||||
|
|
@ -291,11 +290,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
}
|
||||
|
||||
get hasDamage() {
|
||||
return this.damage?.parts?.length && this.type !== 'healing'
|
||||
return this.damage?.parts?.length && this.type !== 'healing';
|
||||
}
|
||||
|
||||
get hasHealing() {
|
||||
return this.damage?.parts?.length && this.type === 'healing'
|
||||
return this.damage?.parts?.length && this.type === 'healing';
|
||||
}
|
||||
|
||||
get hasSave() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import DHAbilityUse from "./abilityUse.mjs";
|
||||
import DHActorRoll from "./actorRoll.mjs";
|
||||
import DHAbilityUse from './abilityUse.mjs';
|
||||
import DHActorRoll from './actorRoll.mjs';
|
||||
|
||||
export const config = {
|
||||
abilityUse: DHAbilityUse,
|
||||
|
|
|
|||
|
|
@ -58,10 +58,8 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel {
|
|||
const actionActor = this.actionActor,
|
||||
actionItem = this.actionItem;
|
||||
if (!this.source.action) return null;
|
||||
if(actionItem)
|
||||
return actionItem.system.actionsList?.find(a => a.id === this.source.action);
|
||||
else if(actionActor?.system.attack?._id === this.source.action)
|
||||
return actionActor.system.attack
|
||||
if (actionItem) return actionItem.system.actionsList?.find(a => a.id === this.source.action);
|
||||
else if (actionActor?.system.attack?._id === this.source.action) return actionActor.system.attack;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import BeastformDialog from "../../../applications/dialogs/beastformDialog.mjs";
|
||||
import BeastformDialog from '../../../applications/dialogs/beastformDialog.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,12 @@ export default class DamageField extends fields.SchemaField {
|
|||
*/
|
||||
static async execute(config, messageId = null, force = false) {
|
||||
if (!this.hasDamage && !this.hasHealing) return;
|
||||
if((this.hasRoll && DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id) && !force) return;
|
||||
if (
|
||||
this.hasRoll &&
|
||||
DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id &&
|
||||
!force
|
||||
)
|
||||
return;
|
||||
|
||||
let formulas = this.damage.parts.map(p => ({
|
||||
formula: DamageField.getFormulaValue.call(this, p, config).getFormula(this.actor),
|
||||
|
|
@ -51,7 +56,8 @@ export default class DamageField extends fields.SchemaField {
|
|||
};
|
||||
delete damageConfig.evaluate;
|
||||
|
||||
if(DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.always.id) damageConfig.dialog.configure = false;
|
||||
if (DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.always.id)
|
||||
damageConfig.dialog.configure = false;
|
||||
if (config.hasSave) config.onSave = damageConfig.onSave = this.save.damageMod;
|
||||
|
||||
damageConfig.source.message = config.message?._id ?? messageId;
|
||||
|
|
@ -78,11 +84,7 @@ export default class DamageField extends fields.SchemaField {
|
|||
for (let target of targets) {
|
||||
const actor = fromUuidSync(target.actorId);
|
||||
if (!actor) continue;
|
||||
if (
|
||||
!config.hasHealing &&
|
||||
config.onSave &&
|
||||
target.saved?.success === true
|
||||
) {
|
||||
if (!config.hasHealing && config.onSave && target.saved?.success === true) {
|
||||
const mod = CONFIG.DH.ACTIONS.damageOnSave[config.onSave]?.mod ?? 1;
|
||||
Object.entries(config.damage).forEach(([k, v]) => {
|
||||
v.total = 0;
|
||||
|
|
@ -145,16 +147,25 @@ export default class DamageField extends fields.SchemaField {
|
|||
* @returns {string} Id from settingsConfig.mjs actionAutomationChoices
|
||||
*/
|
||||
static getAutomation() {
|
||||
return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.players)
|
||||
return (
|
||||
(game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.gm) ||
|
||||
(!game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.players)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the automation setting for applyDamage method for current user role
|
||||
* @returns {boolean} If applyDamage should be triggered automatically
|
||||
*/
|
||||
static getApplyAutomation() {
|
||||
return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.players)
|
||||
return (
|
||||
(game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.gm) ||
|
||||
(!game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.players)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { emitAsGM, GMUpdateEvent } from "../../../systemRegistration/socket.mjs";
|
||||
import { emitAsGM, GMUpdateEvent } from '../../../systemRegistration/socket.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
|
|
@ -34,12 +34,7 @@ export default class EffectsField extends fields.ArrayField {
|
|||
}
|
||||
if (EffectsField.getAutomation() || force) {
|
||||
targets ??= (message.system?.targets ?? config.targets).filter(t => !config.hasRoll || t.hit);
|
||||
await emitAsGM(
|
||||
GMUpdateEvent.UpdateEffect,
|
||||
EffectsField.applyEffects.bind(this),
|
||||
targets,
|
||||
this.uuid
|
||||
);
|
||||
await emitAsGM(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid);
|
||||
// EffectsField.applyEffects.call(this, config.targets.filter(t => !config.hasRoll || t.hit));
|
||||
}
|
||||
}
|
||||
|
|
@ -53,8 +48,7 @@ export default class EffectsField extends fields.ArrayField {
|
|||
if (!this.effects?.length || !targets?.length) return;
|
||||
let effects = this.effects;
|
||||
targets.forEach(async token => {
|
||||
if (this.hasSave && token.saved.success === true)
|
||||
effects = this.effects.filter(e => e.onSave === true);
|
||||
if (this.hasSave && token.saved.success === true) effects = this.effects.filter(e => e.onSave === true);
|
||||
if (!effects.length) return;
|
||||
effects.forEach(async e => {
|
||||
const actor = canvas.tokens.get(token.id)?.actor,
|
||||
|
|
@ -96,6 +90,11 @@ export default class EffectsField extends fields.ArrayField {
|
|||
* @returns {boolean} If execute should be triggered automatically
|
||||
*/
|
||||
static getAutomation() {
|
||||
return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.players)
|
||||
return (
|
||||
(game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.gm) ||
|
||||
(!game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.players)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ export default class MacroField extends fields.DocumentUUIDField {
|
|||
|
||||
/** @inheritDoc */
|
||||
constructor(context = {}) {
|
||||
super({ type: "Macro" }, context);
|
||||
super({ type: 'Macro' }, context);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,14 +1,13 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
export default class RangeField extends fields.StringField {
|
||||
|
||||
/** @inheritDoc */
|
||||
constructor(context = {}) {
|
||||
const options = {
|
||||
choices: CONFIG.DH.GENERAL.range,
|
||||
required: false,
|
||||
blank: true,
|
||||
label: "DAGGERHEART.GENERAL.range"
|
||||
label: 'DAGGERHEART.GENERAL.range'
|
||||
};
|
||||
super(options, context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,12 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
|||
static defineSchema() {
|
||||
return {
|
||||
type: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.GENERAL.rollTypes }),
|
||||
trait: new fields.StringField({ nullable: true, initial: null, choices: CONFIG.DH.ACTOR.abilities, label: "DAGGERHEART.GENERAL.Trait.single" }),
|
||||
trait: new fields.StringField({
|
||||
nullable: true,
|
||||
initial: null,
|
||||
choices: CONFIG.DH.ACTOR.abilities,
|
||||
label: 'DAGGERHEART.GENERAL.Trait.single'
|
||||
}),
|
||||
difficulty: new fields.NumberField({ nullable: true, initial: null, integer: true, min: 0 }),
|
||||
bonus: new fields.NumberField({ nullable: true, initial: null, integer: true }),
|
||||
advState: new fields.StringField({
|
||||
|
|
@ -86,14 +91,14 @@ export class DHActionRollData extends foundry.abstract.DataModel {
|
|||
}
|
||||
|
||||
get rollTrait() {
|
||||
if(this.parent?.actor?.type !== "character") return null;
|
||||
if (this.parent?.actor?.type !== 'character') return null;
|
||||
switch (this.type) {
|
||||
case CONFIG.DH.GENERAL.rollTypes.spellcast.id:
|
||||
return this.parent.actor?.system?.spellcastModifierTrait?.key ?? 'agility';
|
||||
case CONFIG.DH.GENERAL.rollTypes.attack.id:
|
||||
case CONFIG.DH.GENERAL.rollTypes.trait.id:
|
||||
return this.useDefault || !this.trait
|
||||
? this.parent.item.system.attack?.roll?.trait ?? 'agility'
|
||||
? (this.parent.item.system.attack?.roll?.trait ?? 'agility')
|
||||
: this.trait;
|
||||
default:
|
||||
return null;
|
||||
|
|
@ -152,6 +157,11 @@ export default class RollField extends fields.EmbeddedDataField {
|
|||
* @returns {boolean} If execute should be triggered automatically
|
||||
*/
|
||||
static getAutomation() {
|
||||
return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.players)
|
||||
return (
|
||||
(game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.gm) ||
|
||||
(!game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.players)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { abilities } from "../../../config/actorConfig.mjs";
|
||||
import { abilities } from '../../../config/actorConfig.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
|
|
@ -63,10 +63,10 @@ export default class SaveField extends fields.SchemaField {
|
|||
new Promise(async subResolve => {
|
||||
const actor = fromUuidSync(target.actorId);
|
||||
if (actor) {
|
||||
const rollSave = game.user === actor.owner ?
|
||||
SaveField.rollSave.call(this, actor, event)
|
||||
: actor.owner
|
||||
.query('reactionRoll', {
|
||||
const rollSave =
|
||||
game.user === actor.owner
|
||||
? SaveField.rollSave.call(this, actor, event)
|
||||
: actor.owner.query('reactionRoll', {
|
||||
actionId: this.uuid,
|
||||
actorId: actor.uuid,
|
||||
event,
|
||||
|
|
@ -77,10 +77,10 @@ export default class SaveField extends fields.SchemaField {
|
|||
subResolve();
|
||||
} else subResolve();
|
||||
})
|
||||
)
|
||||
);
|
||||
});
|
||||
Promise.all(aPromise).then(result => resolve());
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -109,7 +109,8 @@ export default class SaveField extends fields.SchemaField {
|
|||
hasRoll: true,
|
||||
data: actor.getRollData()
|
||||
};
|
||||
if(SaveField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.always.id) rollConfig.dialog = { configure: false };
|
||||
if (SaveField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.always.id)
|
||||
rollConfig.dialog = { configure: false };
|
||||
return actor.diceRoll(rollConfig);
|
||||
}
|
||||
|
||||
|
|
@ -128,8 +129,7 @@ export default class SaveField extends fields.SchemaField {
|
|||
flags: {
|
||||
[game.system.id]: {
|
||||
reactionRolls: {
|
||||
[targetId]:
|
||||
{
|
||||
[targetId]: {
|
||||
result: result.roll.total,
|
||||
success: result.roll.success
|
||||
}
|
||||
|
|
@ -141,7 +141,9 @@ export default class SaveField extends fields.SchemaField {
|
|||
// }, 100);
|
||||
};
|
||||
if (game.modules.get('dice-so-nice')?.active)
|
||||
game.dice3d.waitFor3DAnimationByMessageID(result.message.id ?? result.message._id).then(async () => await updateMsg(message, targetId, result));
|
||||
game.dice3d
|
||||
.waitFor3DAnimationByMessageID(result.message.id ?? result.message._id)
|
||||
.then(async () => await updateMsg(message, targetId, result));
|
||||
else await updateMsg(message, targetId, result);
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +152,12 @@ export default class SaveField extends fields.SchemaField {
|
|||
* @returns {string} Id from settingsConfig.mjs actionAutomationChoices
|
||||
*/
|
||||
static getAutomation() {
|
||||
return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.players)
|
||||
return (
|
||||
(game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.gm) ||
|
||||
(!game.user.isGM &&
|
||||
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.players)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -167,8 +174,7 @@ export default class SaveField extends fields.SchemaField {
|
|||
const actor = await fromUuid(actorId),
|
||||
action = await fromUuid(actionId);
|
||||
if (!actor || !actor?.isOwner) reject();
|
||||
SaveField.rollSave.call(action, actor, event, message)
|
||||
.then(result => resolve(result));
|
||||
SaveField.rollSave.call(action, actor, event, message).then(result => resolve(result));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
const fields = foundry.data.fields;
|
||||
|
||||
export default class TargetField extends fields.SchemaField {
|
||||
|
||||
/** @inheritDoc */
|
||||
constructor(options = {}, context = {}) {
|
||||
const targetFields = {
|
||||
|
|
@ -21,7 +20,7 @@ export default class TargetField extends fields.SchemaField {
|
|||
* @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods.
|
||||
*/
|
||||
prepareConfig(config) {
|
||||
if (!this.target?.type) return config.targets = [];
|
||||
if (!this.target?.type) return (config.targets = []);
|
||||
config.hasTarget = true;
|
||||
let targets;
|
||||
// If the Action is configured as self-targeted, set targets as the owner.
|
||||
|
|
@ -62,15 +61,11 @@ export default class TargetField extends fields.SchemaField {
|
|||
* @returns {boolean} If both actors respect the provided type.
|
||||
*/
|
||||
static isTargetFriendly(actor, target, type) {
|
||||
const actorDisposition = actor.token
|
||||
? actor.token.disposition
|
||||
: actor.prototypeToken.disposition,
|
||||
const actorDisposition = actor.token ? actor.token.disposition : actor.prototypeToken.disposition,
|
||||
targetDisposition = target.document.disposition;
|
||||
return (
|
||||
(type === CONFIG.DH.GENERAL.targetTypes.friendly.id &&
|
||||
actorDisposition === targetDisposition) ||
|
||||
(type === CONFIG.DH.GENERAL.targetTypes.hostile.id &&
|
||||
actorDisposition + targetDisposition === 0)
|
||||
(type === CONFIG.DH.GENERAL.targetTypes.friendly.id && actorDisposition === targetDisposition) ||
|
||||
(type === CONFIG.DH.GENERAL.targetTypes.hostile.id && actorDisposition + targetDisposition === 0)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
export default class DhAppearance extends foundry.abstract.DataModel {
|
||||
static LOCALIZATION_PREFIXES = ["DAGGERHEART.SETTINGS.Appearance"];
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Appearance'];
|
||||
|
||||
static defineSchema() {
|
||||
const { StringField, ColorField, BooleanField, SchemaField } = foundry.data.fields;
|
||||
|
||||
// helper to create dice style schema
|
||||
const diceStyle = ({ fg, bg, outline, edge }) => new SchemaField({
|
||||
const diceStyle = ({ fg, bg, outline, edge }) =>
|
||||
new SchemaField({
|
||||
foreground: new ColorField({ required: true, initial: fg }),
|
||||
background: new ColorField({ required: true, initial: bg }),
|
||||
outline: new ColorField({ required: true, initial: outline }),
|
||||
|
|
@ -20,7 +21,7 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
displayFear: new StringField({
|
||||
required: true,
|
||||
choices: CONFIG.DH.GENERAL.fearDisplay,
|
||||
initial: CONFIG.DH.GENERAL.fearDisplay.token.value,
|
||||
initial: CONFIG.DH.GENERAL.fearDisplay.token.value
|
||||
}),
|
||||
diceSoNice: new SchemaField({
|
||||
hope: diceStyle({ fg: '#ffffff', bg: '#ffe760', outline: '#000000', edge: '#ffffff' }),
|
||||
|
|
@ -39,7 +40,7 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
target: new BooleanField()
|
||||
}),
|
||||
hideAttribution: new BooleanField(),
|
||||
showGenericStatusEffects: new BooleanField({ initial: true }),
|
||||
showGenericStatusEffects: new BooleanField({ initial: true })
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,13 +97,13 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
damage: new fields.SchemaField({
|
||||
gm: new fields.StringField({
|
||||
required: true,
|
||||
initial: "never",
|
||||
initial: 'never',
|
||||
choices: CONFIG.DH.SETTINGS.actionAutomationChoices,
|
||||
label: 'DAGGERHEART.GENERAL.gm'
|
||||
}),
|
||||
players: new fields.StringField({
|
||||
required: true,
|
||||
initial: "never",
|
||||
initial: 'never',
|
||||
choices: CONFIG.DH.SETTINGS.actionAutomationChoices,
|
||||
label: 'DAGGERHEART.GENERAL.player.plurial'
|
||||
})
|
||||
|
|
@ -111,13 +111,13 @@ export default class DhAutomation extends foundry.abstract.DataModel {
|
|||
save: new fields.SchemaField({
|
||||
gm: new fields.StringField({
|
||||
required: true,
|
||||
initial: "never",
|
||||
initial: 'never',
|
||||
choices: CONFIG.DH.SETTINGS.actionAutomationChoices,
|
||||
label: 'DAGGERHEART.GENERAL.gm'
|
||||
}),
|
||||
players: new fields.StringField({
|
||||
required: true,
|
||||
initial: "never",
|
||||
initial: 'never',
|
||||
choices: CONFIG.DH.SETTINGS.actionAutomationChoices,
|
||||
label: 'DAGGERHEART.GENERAL.player.plurial'
|
||||
})
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ export default class DamageRoll extends DHRoll {
|
|||
);
|
||||
}
|
||||
await super.buildPost(roll, config, message);
|
||||
if (config.source?.message)
|
||||
chatMessage.update({ 'system.damage': config.damage });
|
||||
if (config.source?.message) chatMessage.update({ 'system.damage': config.damage });
|
||||
}
|
||||
|
||||
static unifyDamageRoll(rolls) {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ export default class DHRoll extends Roll {
|
|||
}
|
||||
|
||||
for (const hook of config.hooks) {
|
||||
if (Hooks.call(`${CONFIG.DH.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false) return [];
|
||||
if (
|
||||
Hooks.call(`${CONFIG.DH.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false
|
||||
)
|
||||
return [];
|
||||
}
|
||||
return roll;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,10 @@ export default class DualityRoll extends D20Roll {
|
|||
|
||||
if (this.options.roll.trait && this.data.traits?.[this.options.roll.trait])
|
||||
modifiers.unshift({
|
||||
label: this.options.roll.type === CONFIG.DH.GENERAL.rollTypes.spellcast.id ? "DAGGERHEART.CONFIG.RollTypes.spellcast.name" : `DAGGERHEART.CONFIG.Traits.${this.options.roll.trait}.name`,
|
||||
label:
|
||||
this.options.roll.type === CONFIG.DH.GENERAL.rollTypes.spellcast.id
|
||||
? 'DAGGERHEART.CONFIG.RollTypes.spellcast.name'
|
||||
: `DAGGERHEART.CONFIG.Traits.${this.options.roll.trait}.name`,
|
||||
value: this.data.traits[this.options.roll.trait].value
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { emitAsGM, GMUpdateEvent } from "../systemRegistration/socket.mjs";
|
||||
import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs';
|
||||
|
||||
export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
||||
targetHook = null;
|
||||
|
|
@ -106,9 +106,9 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
}
|
||||
|
||||
if (!this.isAuthor && !this.speakerActor?.isOwner) {
|
||||
const applyButtons = html.querySelector(".apply-buttons");
|
||||
const applyButtons = html.querySelector('.apply-buttons');
|
||||
applyButtons?.remove();
|
||||
const buttons = html.querySelectorAll(".ability-card-footer > .ability-use-button");
|
||||
const buttons = html.querySelectorAll('.ability-card-footer > .ability-use-button');
|
||||
buttons.forEach(b => b.remove());
|
||||
}
|
||||
}
|
||||
|
|
@ -149,7 +149,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
event.stopPropagation();
|
||||
const config = foundry.utils.deepClone(this.system);
|
||||
config.event = event;
|
||||
this.system.action?.workflow.get("damage")?.execute(config, this._id, true);
|
||||
this.system.action?.workflow.get('damage')?.execute(config, this._id, true);
|
||||
}
|
||||
|
||||
async onApplyDamage(event) {
|
||||
|
|
@ -173,7 +173,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));
|
||||
|
||||
this.consumeOnSuccess();
|
||||
this.system.action?.workflow.get("applyDamage")?.execute(config, targets, true);
|
||||
this.system.action?.workflow.get('applyDamage')?.execute(config, targets, true);
|
||||
}
|
||||
|
||||
async onRollSave(event) {
|
||||
|
|
@ -187,7 +187,12 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
game.system.api.fields.ActionFields.SaveField.rollSave.call(action, token.actor, event).then(result =>
|
||||
emitAsGM(
|
||||
GMUpdateEvent.UpdateSaveMessage,
|
||||
game.system.api.fields.ActionFields.SaveField.updateSaveMessage.bind(action, result, this, token.id),
|
||||
game.system.api.fields.ActionFields.SaveField.updateSaveMessage.bind(
|
||||
action,
|
||||
result,
|
||||
this,
|
||||
token.id
|
||||
),
|
||||
{
|
||||
action: action.uuid,
|
||||
message: this._id,
|
||||
|
|
@ -205,7 +210,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
const targets = this.system.hitTargets,
|
||||
config = foundry.utils.deepClone(this.system);
|
||||
config.event = event;
|
||||
this.system.action?.workflow.get("save")?.execute(config, targets, true);
|
||||
this.system.action?.workflow.get('save')?.execute(config, targets, true);
|
||||
}
|
||||
|
||||
async onApplyEffect(event) {
|
||||
|
|
@ -216,16 +221,15 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
|
|||
if (targets.length === 0)
|
||||
ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));
|
||||
this.consumeOnSuccess();
|
||||
this.system.action?.workflow.get("effects")?.execute(config, targets, true);
|
||||
this.system.action?.workflow.get('effects')?.execute(config, targets, true);
|
||||
}
|
||||
|
||||
filterPermTargets(targets) {
|
||||
return targets.filter(t => fromUuidSync(t.actorId)?.canUserModify(game.user, "update"))
|
||||
return targets.filter(t => fromUuidSync(t.actorId)?.canUserModify(game.user, 'update'));
|
||||
}
|
||||
|
||||
consumeOnSuccess() {
|
||||
if (!this.system.successConsumed && !this.targetSelection)
|
||||
this.system.action?.consume(this.system, true);
|
||||
if (!this.system.successConsumed && !this.targetSelection) this.system.action?.consume(this.system, true);
|
||||
}
|
||||
|
||||
hoverTarget(event) {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default class DHItem extends foundry.documents.Item {
|
|||
|
||||
/** @inheritDoc */
|
||||
static migrateData(source) {
|
||||
if(source.system?.attack && !source.system.attack.type) source.system.attack.type = "attack";
|
||||
if (source.system?.attack && !source.system.attack.type) source.system.attack.type = 'attack';
|
||||
return super.migrateData(source);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,10 +34,7 @@ export const preloadHandlebarsTemplates = async function () {
|
|||
'systems/daggerheart/templates/ui/chat/parts/damage-part.hbs',
|
||||
'systems/daggerheart/templates/ui/chat/parts/target-part.hbs',
|
||||
'systems/daggerheart/templates/ui/chat/parts/button-part.hbs',
|
||||
|
||||
'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs',
|
||||
|
||||
'systems/daggerheart/templates/scene/dh-config.hbs',
|
||||
|
||||
'systems/daggerheart/templates/scene/dh-config.hbs'
|
||||
]);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ export const registerSocketHooks = () => {
|
|||
const document = data.uuid ? await fromUuid(data.uuid) : null;
|
||||
switch (data.action) {
|
||||
case GMUpdateEvent.UpdateDocument:
|
||||
if (document && data.update)
|
||||
await document.update(data.update);
|
||||
if (document && data.update) await document.update(data.update);
|
||||
break;
|
||||
case GMUpdateEvent.UpdateEffect:
|
||||
if (document && data.update)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
---
|
||||
name: Pull Request
|
||||
about: Create a new pull request
|
||||
title: "[PR] <Insert Title here>"
|
||||
title: '[PR] <Insert Title here>'
|
||||
labels: pr
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
Is this a community PR? Please go to preview tab and click [here](?expand=1&template=community_pull_request_template.md). If not, delete this line.
|
||||
|
||||
## Description
|
||||
|
|
|
|||
|
|
@ -603,7 +603,7 @@
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: .25rem .5rem;
|
||||
gap: 0.25rem 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
label {
|
||||
|
|
@ -620,7 +620,7 @@
|
|||
&.setting-two-values {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: .25rem .5rem;
|
||||
gap: 0.25rem 0.5rem;
|
||||
|
||||
.form-group {
|
||||
justify-content: end;
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@
|
|||
overflow: hidden !important;
|
||||
|
||||
div {
|
||||
opacity: .5;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:before {
|
||||
font-family: "Font Awesome 6 Pro";
|
||||
font-family: 'Font Awesome 6 Pro';
|
||||
content: '\f110';
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
|
|
@ -46,6 +46,8 @@
|
|||
}
|
||||
|
||||
@keyframes spinner {
|
||||
to { transform: rotate(360deg); }
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ body.game:is(.performance-low, .noblur) {
|
|||
.themed.theme-dark.application.daggerheart.sheet.dh-style,
|
||||
&.theme-dark .application.daggerheart {
|
||||
background: @dark-blue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
.application.sheet.dh-style {
|
||||
|
|
|
|||
13
styles/less/ui/chat/refresh-message.less
Normal file
13
styles/less/ui/chat/refresh-message.less
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
.daggerheart.chat.refresh-message {
|
||||
header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 2px;
|
||||
|
||||
.subtitle {
|
||||
font-size: 18;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
@import './chat/action.less';
|
||||
@import './chat/chat.less';
|
||||
@import './chat/downtime.less';
|
||||
@import './chat/refresh-message.less';
|
||||
@import './chat/sheet.less';
|
||||
|
||||
@import './combat-sidebar/combat-sidebar.less';
|
||||
|
|
@ -19,6 +20,8 @@
|
|||
@import './resources/resources.less';
|
||||
|
||||
@import './settings/settings.less';
|
||||
|
||||
@import './settings/homebrew-settings/domains.less';
|
||||
@import './settings/homebrew-settings/types.less';
|
||||
|
||||
@import './sidebar/tabs.less';
|
||||
@import './sidebar/daggerheartMenu.less';
|
||||
|
|
|
|||
|
|
@ -409,7 +409,8 @@
|
|||
|
||||
&.lite,
|
||||
&.no-folder {
|
||||
.compendium-sidebar, .menu-path {
|
||||
.compendium-sidebar,
|
||||
.menu-path {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
fieldset {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: .5rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
&.two-columns {
|
||||
display: grid;
|
||||
|
|
|
|||
38
styles/less/ui/sidebar/daggerheartMenu.less
Normal file
38
styles/less/ui/sidebar/daggerheartMenu.less
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
.tab.sidebar-tab.daggerheartMenu-sidebar {
|
||||
padding: 0 4px;
|
||||
|
||||
.menu-refresh-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.menu-refresh-inner-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
|
||||
.experience-chip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
width: fit-content;
|
||||
gap: 5px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
background: light-dark(@dark-blue-10, @golden-10);
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
|
||||
.label {
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background: light-dark(@dark-blue-40, @golden-40);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
styles/less/ui/sidebar/tabs.less
Normal file
8
styles/less/ui/sidebar/tabs.less
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#interface #ui-right #sidebar {
|
||||
menu li button {
|
||||
img {
|
||||
width: 22px;
|
||||
max-width: unset;
|
||||
}
|
||||
}
|
||||
}
|
||||
22
templates/sidebar/daggerheart-menu/main.hbs
Normal file
22
templates/sidebar/daggerheart-menu/main.hbs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<div>
|
||||
<fieldset>
|
||||
<legend>{{localize "Refresh Features"}}</legend>
|
||||
|
||||
<div class="menu-refresh-container">
|
||||
<div class="menu-refresh-inner-container">
|
||||
{{#each refreshables as |type key|}}
|
||||
<div class="experience-chip {{#if type.selected}}selected{{/if}}" data-action="selectRefreshable" data-type="{{key}}">
|
||||
{{#if type.selected}}
|
||||
<span><i class="fa-solid fa-circle"></i></span>
|
||||
{{else}}
|
||||
<span><i class="fa-regular fa-circle"></i></span>
|
||||
{{/if}}
|
||||
<span>{{type.label}}</span>
|
||||
</div>
|
||||
|
||||
{{/each}}
|
||||
</div>
|
||||
<button data-action="refreshActors" {{disabled disableRefresh}}>{{localize "Refresh"}}</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
18
templates/sidebar/tabs.hbs
Normal file
18
templates/sidebar/tabs.hbs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<nav class="tabs faded-ui" role="tablist" data-tooltip-direction="LEFT">
|
||||
<menu class="flexcol">
|
||||
{{#each tabs}}
|
||||
<li>
|
||||
<button type="button" class="ui-control plain icon {{#if icon}}{{icon}}{{/if}}" data-action="tab" data-tab="{{ @key }}"
|
||||
role="tab" aria-pressed="{{ active }}" data-group="primary" aria-label="{{ localize tooltip }}"
|
||||
aria-controls="{{ @key }}" data-tooltip>
|
||||
{{#if img}}<img src="{{img}}" />{{/if}}
|
||||
</button>
|
||||
<div class="notification-pip"></div>
|
||||
</li>
|
||||
{{/each}}
|
||||
<li>
|
||||
<button type="button" class="collapse ui-control plain icon fas fa-caret-left" data-tooltip
|
||||
aria-label="{{ localize "Expand" }}" data-action="toggleState"></button>
|
||||
</li>
|
||||
</menu>
|
||||
</nav>
|
||||
6
templates/ui/chat/refreshMessage.hbs
Normal file
6
templates/ui/chat/refreshMessage.hbs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
<div class="daggerheart chat refresh-message">
|
||||
<header>
|
||||
<div class="subtitle">{{localize "DAGGERHEART.UI.Chat.refreshMessage.header"}}</div>
|
||||
<div class="types">{{types}}</div>
|
||||
</header>
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue