mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-19 00:19:03 +01:00
Merged with main
This commit is contained in:
commit
a5b656f533
51 changed files with 650 additions and 1032 deletions
|
|
@ -7,3 +7,4 @@ export { default as DeathMove } from './deathMove.mjs';
|
|||
export { default as Downtime } from './downtime.mjs';
|
||||
export { default as OwnershipSelection } from './ownershipSelection.mjs';
|
||||
export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
|
||||
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
|
||||
|
|
|
|||
87
module/applications/dialogs/actionSelectionDialog.mjs
Normal file
87
module/applications/dialogs/actionSelectionDialog.mjs
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
const { ApplicationV2, HandlebarsApplicationMixin } = foundry.applications.api;
|
||||
|
||||
export default class ActionSelectionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(item, event, options = {}) {
|
||||
super(options);
|
||||
this.#item = item;
|
||||
this.#event = event;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['daggerheart', 'dh-style', 'dialog'],
|
||||
actions: {
|
||||
choose: ActionSelectionDialog.#onChooseAction
|
||||
},
|
||||
position: {
|
||||
width: 400
|
||||
}
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static PARTS = {
|
||||
actions: {
|
||||
template: 'systems/daggerheart/templates/dialogs/actionSelect.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
#item;
|
||||
|
||||
get item() {
|
||||
return this.#item;
|
||||
}
|
||||
|
||||
#event;
|
||||
|
||||
get event() {
|
||||
return this.#event;
|
||||
}
|
||||
|
||||
#action;
|
||||
|
||||
get action() {
|
||||
return this.#action ?? null;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
get title() {
|
||||
return game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectAction');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritDoc */
|
||||
async _prepareContext(options) {
|
||||
const actions = this.#item.system.actionsList,
|
||||
itemName = this.#item.name;
|
||||
return {
|
||||
...(await super._prepareContext(options)),
|
||||
actions,
|
||||
itemName
|
||||
};
|
||||
}
|
||||
|
||||
static async #onChooseAction(event, button) {
|
||||
const { actionId } = button.dataset;
|
||||
this.#action = this.#item.system.actionsList.find(a => a._id === actionId);
|
||||
Object.defineProperty(this.#event, 'shiftKey', {
|
||||
get() {
|
||||
return event.shiftKey;
|
||||
}
|
||||
});
|
||||
this.close();
|
||||
}
|
||||
|
||||
static create(item, event, options) {
|
||||
return new Promise(resolve => {
|
||||
const dialog = new this(item, event, options);
|
||||
dialog.addEventListener('close', () => resolve(dialog.action), { once: true });
|
||||
dialog.render({ force: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -64,8 +64,8 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
context.selectedActivity = this.selectedActivity;
|
||||
context.moveData = this.moveData;
|
||||
|
||||
const shortRestMovesSelected = this.#nrSelectedMoves('shortRest');
|
||||
const longRestMovesSelected = this.#nrSelectedMoves('longRest');
|
||||
const shortRestMovesSelected = this.nrSelectedMoves('shortRest');
|
||||
const longRestMovesSelected = this.nrSelectedMoves('longRest');
|
||||
context.nrChoices = {
|
||||
...this.nrChoices,
|
||||
shortRest: {
|
||||
|
|
@ -89,7 +89,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
static selectMove(_, target) {
|
||||
const { category, move } = target.dataset;
|
||||
|
||||
const nrSelected = this.#nrSelectedMoves(category);
|
||||
const nrSelected = this.nrSelectedMoves(category);
|
||||
|
||||
if (nrSelected + this.nrChoices[category].taken >= this.nrChoices[category].max) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.noMoreMoves'));
|
||||
|
|
@ -176,7 +176,7 @@ export default class DhpDowntime extends HandlebarsApplicationMixin(ApplicationV
|
|||
this.render();
|
||||
}
|
||||
|
||||
#nrSelectedMoves(category) {
|
||||
nrSelectedMoves(category) {
|
||||
return Object.values(this.moveData[category].moves).reduce((acc, x) => acc + (x.selected ?? 0), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,10 +36,37 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
}
|
||||
};
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
diceSoNice: {
|
||||
tabs: [
|
||||
{ id: 'hope', label: 'DAGGERHEART.GENERAL.hope' },
|
||||
{ id: 'fear', label: 'DAGGERHEART.GENERAL.fear' },
|
||||
{ id: 'advantage', label: 'DAGGERHEART.GENERAL.Advantage.full' },
|
||||
{ id: 'disadvantage', label: 'DAGGERHEART.GENERAL.Advantage.full' }
|
||||
],
|
||||
initial: 'hope'
|
||||
}
|
||||
};
|
||||
|
||||
changeTab(tab, group, options) {
|
||||
super.changeTab(tab, group, options);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.settingFields = this.settings;
|
||||
|
||||
context.diceSoNiceTextures = game.dice3d?.exports?.TEXTURELIST ?? {};
|
||||
context.diceSoNiceColorsets = game.dice3d?.exports?.COLORSETS ?? {};
|
||||
context.diceTab = {
|
||||
key: this.tabGroups.diceSoNice,
|
||||
source: this.settings._source.diceSoNice[this.tabGroups.diceSoNice],
|
||||
fields: this.settings.schema.fields.diceSoNice.fields[this.tabGroups.diceSoNice].fields
|
||||
};
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -65,4 +92,13 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App
|
|||
|
||||
this.close();
|
||||
}
|
||||
|
||||
_getTabs(tabs) {
|
||||
for (const v of Object.values(tabs)) {
|
||||
v.active = this.tabGroups[v.group] ? this.tabGroups[v.group] === v.id : v.active;
|
||||
v.cssClass = v.active ? 'active' : '';
|
||||
}
|
||||
|
||||
return tabs;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,148 +0,0 @@
|
|||
import { actionsTypes } from '../../../data/action/_module.mjs';
|
||||
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export default class DhSettingsActionView extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(resolve, reject, title, name, icon, img, description, actions) {
|
||||
super({});
|
||||
|
||||
this.resolve = resolve;
|
||||
this.reject = reject;
|
||||
this.viewTitle = title;
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
this.img = img;
|
||||
this.description = description;
|
||||
this.actions = actions;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.viewTitle;
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'setting', 'dh-style'],
|
||||
position: { width: 440, height: 'auto' },
|
||||
actions: {
|
||||
editImage: this.onEditImage,
|
||||
addItem: this.addItem,
|
||||
editItem: this.editItem,
|
||||
removeItem: this.removeItem,
|
||||
resetMoves: this.resetMoves,
|
||||
saveForm: this.saveForm
|
||||
},
|
||||
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
header: { template: 'systems/daggerheart/templates/settings/components/action-view-header.hbs' },
|
||||
main: {
|
||||
template: 'systems/daggerheart/templates/settings/components/action-view.hbs'
|
||||
},
|
||||
footer: { template: 'systems/daggerheart/templates/settings/components/action-view-footer.hbs' }
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.name = this.name;
|
||||
context.icon = this.icon;
|
||||
context.img = this.img;
|
||||
context.description = this.description;
|
||||
context.enrichedDescription = await foundry.applications.ux.TextEditor.enrichHTML(context.description);
|
||||
context.actions = this.actions;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateData(event, element, formData) {
|
||||
const { name, icon, description } = foundry.utils.expandObject(formData.object);
|
||||
this.name = name;
|
||||
this.icon = icon;
|
||||
this.description = description;
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async saveForm(event) {
|
||||
this.resolve({
|
||||
name: this.name,
|
||||
icon: this.icon,
|
||||
img: this.img,
|
||||
description: this.description,
|
||||
actions: this.actions
|
||||
});
|
||||
this.close(true);
|
||||
}
|
||||
|
||||
static close(fromSave) {
|
||||
if (!fromSave) {
|
||||
this.reject();
|
||||
}
|
||||
|
||||
super.close();
|
||||
}
|
||||
|
||||
static onEditImage() {
|
||||
const fp = new foundry.applications.apps.FilePicker.implementation({
|
||||
current: this.img,
|
||||
type: 'image',
|
||||
callback: async path => {
|
||||
this.img = path;
|
||||
this.render();
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10
|
||||
});
|
||||
return fp.browse();
|
||||
}
|
||||
|
||||
async selectActionType() {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/actionTypes/actionType.hbs',
|
||||
{ types: CONFIG.DH.ACTIONS.actionTypes }
|
||||
),
|
||||
title = 'Select Action Type',
|
||||
type = 'form',
|
||||
data = {};
|
||||
return Dialog.prompt({
|
||||
title,
|
||||
label: title,
|
||||
content,
|
||||
type,
|
||||
callback: html => {
|
||||
const form = html[0].querySelector('form'),
|
||||
fd = new foundry.applications.ux.FormDataExtended(form);
|
||||
foundry.utils.mergeObject(data, fd.object, { inplace: true });
|
||||
return data;
|
||||
},
|
||||
rejectClose: false
|
||||
});
|
||||
}
|
||||
|
||||
static async addItem() {
|
||||
const actionType = await this.selectActionType();
|
||||
const cls = actionsTypes[actionType?.type] ?? actionsTypes.attack,
|
||||
action = new cls({
|
||||
_id: foundry.utils.randomID(),
|
||||
type: actionType.type,
|
||||
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType.type].name),
|
||||
...cls.getSourceConfig(this.document)
|
||||
});
|
||||
|
||||
this.actions.push(action);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async editItem(_, button) {
|
||||
await new DHActionConfig(this.actions[button.dataset.id]).render(true);
|
||||
}
|
||||
|
||||
static removeItem(event, button) {
|
||||
this.actions = this.actions.filter((_, index) => index !== Number.parseInt(button.dataset.id));
|
||||
this.render();
|
||||
}
|
||||
|
||||
static resetMoves() {}
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
import { DhHomebrew } from '../../data/settings/_module.mjs';
|
||||
import DhSettingsActionView from './components/settingsActionsView.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export default class DhHomebrewSettings extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
|
@ -73,23 +71,21 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
|||
|
||||
static async editItem(_, target) {
|
||||
const move = this.settings.restMoves[target.dataset.type].moves[target.dataset.id];
|
||||
new Promise((resolve, reject) => {
|
||||
new DhSettingsActionView(
|
||||
resolve,
|
||||
reject,
|
||||
game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMoves'),
|
||||
move.name,
|
||||
move.icon,
|
||||
move.img,
|
||||
move.description,
|
||||
move.actions
|
||||
).render(true);
|
||||
}).then(data => this.updateAction.bind(this)(data, target.dataset.type, target.dataset.id));
|
||||
const path = `restMoves.${target.dataset.type}.moves.${target.dataset.id}`;
|
||||
const editedMove = await game.system.api.applications.sheetConfigs.DowntimeConfig.configure(
|
||||
move,
|
||||
path,
|
||||
this.settings
|
||||
);
|
||||
if (!editedMove) return;
|
||||
|
||||
await this.updateAction.bind(this)(editedMove, target.dataset.type, target.dataset.id);
|
||||
}
|
||||
|
||||
async updateAction(data, type, id) {
|
||||
await this.settings.updateSource({
|
||||
[`restMoves.${type}.moves.${id}`]: {
|
||||
actions: data.actions,
|
||||
name: data.name,
|
||||
icon: data.icon,
|
||||
img: data.img,
|
||||
|
|
@ -139,7 +135,11 @@ export default class DhHomebrewSettings extends HandlebarsApplicationMixin(Appli
|
|||
acc[key] = {
|
||||
...move,
|
||||
name: game.i18n.localize(move.name),
|
||||
description: game.i18n.localize(move.description)
|
||||
description: game.i18n.localize(move.description),
|
||||
actions: move.actions.map(action => ({
|
||||
...action,
|
||||
name: game.i18n.localize(action.name)
|
||||
}))
|
||||
};
|
||||
|
||||
return acc;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
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 DowntimeConfig } from './downtimeConfig.mjs';
|
||||
export { default as EnvironmentSettings } from './environment-settings.mjs';
|
||||
export { default as ActiveEffectConfig } from './activeEffectConfig.mjs';
|
||||
export { default as DhTokenConfig } from './token-config.mjs';
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import DaggerheartSheet from '../sheets/daggerheart-sheet.mjs';
|
|||
|
||||
const { ApplicationV2 } = foundry.applications.api;
|
||||
export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||
constructor(action) {
|
||||
constructor(action, sheetUpdate) {
|
||||
super({});
|
||||
|
||||
this.action = action;
|
||||
this.sheetUpdate = sheetUpdate;
|
||||
this.openSection = null;
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +172,8 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
|||
const submitData = this._prepareSubmitData(event, formData),
|
||||
data = foundry.utils.mergeObject(this.action.toObject(), submitData);
|
||||
this.action = await this.action.update(data);
|
||||
|
||||
this.sheetUpdate?.(this.action);
|
||||
this.render();
|
||||
}
|
||||
|
||||
|
|
@ -236,7 +239,7 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
|||
if (!this.action.effects) return;
|
||||
const index = button.dataset.index,
|
||||
effectId = this.action.effects[index]._id;
|
||||
this.constructor.removeElement.bind(this)(event);
|
||||
this.constructor.removeElement.bind(this)(event, button);
|
||||
this.action.item.deleteEmbeddedDocuments('ActiveEffect', [effectId]);
|
||||
}
|
||||
|
||||
|
|
|
|||
162
module/applications/sheets-configs/downtimeConfig.mjs
Normal file
162
module/applications/sheets-configs/downtimeConfig.mjs
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
import { actionsTypes } from '../../data/action/_module.mjs';
|
||||
import DHActionConfig from './action-config.mjs';
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export default class DowntimeConfig extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(move, movePath, settings, options) {
|
||||
super(options);
|
||||
|
||||
this.move = move;
|
||||
|
||||
this.movePath = movePath;
|
||||
this.actionsPath = `${movePath}.actions`;
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.localize('DAGGERHEART.SETTINGS.Homebrew.downtimeMoves');
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'setting', 'dh-style'],
|
||||
position: { width: 440, height: 'auto' },
|
||||
window: {
|
||||
icon: 'fa-solid fa-gears'
|
||||
},
|
||||
actions: {
|
||||
editImage: this.onEditImage,
|
||||
addItem: this.addItem,
|
||||
editItem: this.editItem,
|
||||
removeItem: this.removeItem,
|
||||
resetMoves: this.resetMoves,
|
||||
saveForm: this.saveForm
|
||||
},
|
||||
form: { handler: this.updateData, submitOnChange: true, closeOnSubmit: false }
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
header: { template: 'systems/daggerheart/templates/settings/downtime-config/header.hbs' },
|
||||
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
|
||||
main: { template: 'systems/daggerheart/templates/settings/downtime-config/main.hbs' },
|
||||
actions: { template: 'systems/daggerheart/templates/settings/downtime-config/actions.hbs' },
|
||||
footer: { template: 'systems/daggerheart/templates/settings/downtime-config/footer.hbs' }
|
||||
};
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
primary: {
|
||||
tabs: [{ id: 'main' }, { id: 'actions' }],
|
||||
initial: 'main',
|
||||
labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.move = this.move;
|
||||
context.move.enrichedDescription = await foundry.applications.ux.TextEditor.enrichHTML(
|
||||
context.move.description
|
||||
);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateData(event, element, formData) {
|
||||
const data = foundry.utils.expandObject(formData.object);
|
||||
foundry.utils.mergeObject(this.move, data);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async saveForm() {
|
||||
this.close({ submitted: true });
|
||||
}
|
||||
|
||||
static onEditImage() {
|
||||
const fp = new foundry.applications.apps.FilePicker.implementation({
|
||||
current: this.img,
|
||||
type: 'image',
|
||||
callback: async path => {
|
||||
this.move.img = path;
|
||||
this.render();
|
||||
},
|
||||
top: this.position.top + 40,
|
||||
left: this.position.left + 10
|
||||
});
|
||||
return fp.browse();
|
||||
}
|
||||
|
||||
async selectActionType() {
|
||||
return (
|
||||
(await foundry.applications.api.DialogV2.input({
|
||||
window: { title: game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectType') },
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/actionTypes/actionType.hbs',
|
||||
{ types: CONFIG.DH.ACTIONS.actionTypes }
|
||||
),
|
||||
ok: {
|
||||
label: game.i18n.format('DOCUMENT.Create', {
|
||||
type: game.i18n.localize('DAGGERHEART.GENERAL.Action.single')
|
||||
})
|
||||
}
|
||||
})) ?? {}
|
||||
);
|
||||
}
|
||||
|
||||
static async addItem() {
|
||||
const { type: actionType } = await this.selectActionType();
|
||||
if (!actionType) return;
|
||||
|
||||
const cls = actionsTypes[actionType] ?? actionsTypes.attack,
|
||||
action = new cls(
|
||||
{
|
||||
type: actionType,
|
||||
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
|
||||
img: 'icons/magic/life/cross-worn-green.webp',
|
||||
actionType: 'action',
|
||||
systemPath: this.actionsPath
|
||||
},
|
||||
{
|
||||
parent: this.settings
|
||||
}
|
||||
);
|
||||
|
||||
await this.settings.updateSource({ [`${this.actionsPath}.${action.id}`]: action });
|
||||
this.move = foundry.utils.getProperty(this.settings, this.movePath);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async editItem(_, target) {
|
||||
const actionId = target.dataset.id;
|
||||
const action = this.move.actions.get(actionId);
|
||||
await new DHActionConfig(action, async updatedMove => {
|
||||
await this.settings.updateSource({ [`${this.actionsPath}.${actionId}`]: updatedMove });
|
||||
this.move = foundry.utils.getProperty(this.settings, this.movePath);
|
||||
this.render();
|
||||
}).render(true);
|
||||
}
|
||||
|
||||
static async removeItem(_, target) {
|
||||
await this.settings.updateSource({ [`${this.actionsPath}.-=${target.dataset.id}`]: null });
|
||||
this.move = foundry.utils.getProperty(this.settings, this.movePath);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static resetMoves() {}
|
||||
|
||||
/** @override */
|
||||
_onClose(options = {}) {
|
||||
if (!options.submitted) this.move = null;
|
||||
}
|
||||
|
||||
static async configure(move, movePath, settings, options = {}) {
|
||||
return new Promise(resolve => {
|
||||
const app = new this(move, movePath, settings, options);
|
||||
app.addEventListener('close', () => resolve(app.move), { once: true });
|
||||
app.render({ force: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -517,9 +517,10 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
const item = getDocFromElement(event.currentTarget);
|
||||
if (!item) return;
|
||||
|
||||
const max = item.system.resource.max ? itemAbleRollParse(item.system.resource.max, this.document, item) : null;
|
||||
const max = event.currentTarget.max ? Number(event.currentTarget.max) : null;
|
||||
const value = max ? Math.min(Number(event.currentTarget.value), max) : event.currentTarget.value;
|
||||
await item.update({ 'system.resource.value': value });
|
||||
this.render();
|
||||
}
|
||||
|
||||
async updateItemQuantity(event) {
|
||||
|
|
@ -527,6 +528,7 @@ export default class CharacterSheet extends DHBaseActorSheet {
|
|||
if (!item) return;
|
||||
|
||||
await item.update({ 'system.quantity': event.currentTarget.value });
|
||||
this.render();
|
||||
}
|
||||
|
||||
async updateArmorMarks(event) {
|
||||
|
|
|
|||
|
|
@ -2,37 +2,44 @@ export const actionTypes = {
|
|||
attack: {
|
||||
id: 'attack',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.attack.name',
|
||||
icon: 'fa-swords'
|
||||
icon: 'fa-khanda',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.attack.tooltip'
|
||||
},
|
||||
healing: {
|
||||
id: 'healing',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.healing.name',
|
||||
icon: 'fa-kit-medical'
|
||||
icon: 'fa-kit-medical',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.healing.tooltip'
|
||||
},
|
||||
damage: {
|
||||
id: 'damage',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.damage.name',
|
||||
icon: 'fa-bone-break'
|
||||
},
|
||||
summon: {
|
||||
id: 'summon',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.summon.name',
|
||||
icon: 'fa-ghost'
|
||||
},
|
||||
effect: {
|
||||
id: 'effect',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.effect.name',
|
||||
icon: 'fa-person-rays'
|
||||
},
|
||||
macro: {
|
||||
id: 'macro',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.macro.name',
|
||||
icon: 'fa-scroll'
|
||||
icon: 'fa-heart-crack',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.damage.tooltip'
|
||||
},
|
||||
beastform: {
|
||||
id: 'beastform',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.beastform.name',
|
||||
icon: 'fa-paw'
|
||||
icon: 'fa-paw',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.beastform.tooltip'
|
||||
},
|
||||
summon: {
|
||||
id: 'summon',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.summon.name',
|
||||
icon: 'fa-ghost',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.summon.tooltip'
|
||||
},
|
||||
effect: {
|
||||
id: 'effect',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.effect.name',
|
||||
icon: 'fa-person-rays',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.effect.tooltip'
|
||||
},
|
||||
macro: {
|
||||
id: 'macro',
|
||||
name: 'DAGGERHEART.ACTIONS.TYPES.macro.name',
|
||||
icon: 'fa-scroll',
|
||||
tooltip: 'DAGGERHEART.ACTIONS.TYPES.macro.tooltip'
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -138,8 +138,8 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-bandage',
|
||||
img: 'icons/magic/life/cross-worn-green.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.tendToWounds.description'),
|
||||
actions: [
|
||||
{
|
||||
actions: {
|
||||
tendToWounds: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.tendToWounds.name'),
|
||||
img: 'icons/magic/life/cross-worn-green.webp',
|
||||
|
|
@ -154,7 +154,7 @@ export const defaultRestOptions = {
|
|||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
clearStress: {
|
||||
id: 'clearStress',
|
||||
|
|
@ -162,8 +162,8 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-regular fa-face-surprise',
|
||||
img: 'icons/magic/perception/eye-ringed-green.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.clearStress.description'),
|
||||
actions: [
|
||||
{
|
||||
actions: {
|
||||
clearStress: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.clearStress.name'),
|
||||
img: 'icons/magic/perception/eye-ringed-green.webp',
|
||||
|
|
@ -178,7 +178,7 @@ export const defaultRestOptions = {
|
|||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
repairArmor: {
|
||||
id: 'repairArmor',
|
||||
|
|
@ -186,8 +186,8 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-hammer',
|
||||
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.repairArmor.description'),
|
||||
actions: [
|
||||
{
|
||||
actions: {
|
||||
repairArmor: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.repairArmor.name'),
|
||||
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
|
||||
|
|
@ -202,7 +202,7 @@ export const defaultRestOptions = {
|
|||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
prepare: {
|
||||
id: 'prepare',
|
||||
|
|
@ -210,7 +210,7 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-dumbbell',
|
||||
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.shortRest.prepare.description'),
|
||||
actions: []
|
||||
actions: {}
|
||||
}
|
||||
}),
|
||||
longRest: () => ({
|
||||
|
|
@ -220,7 +220,23 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-bandage',
|
||||
img: 'icons/magic/life/cross-worn-green.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.tendToWounds.description'),
|
||||
actions: []
|
||||
actions: {
|
||||
tendToWounds: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.tendToWounds.name'),
|
||||
img: 'icons/magic/life/cross-worn-green.webp',
|
||||
actionType: 'action',
|
||||
healing: {
|
||||
applyTo: healingTypes.hitPoints.id,
|
||||
value: {
|
||||
custom: {
|
||||
enabled: true,
|
||||
formula: '@system.resources.hitPoints.max'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
clearStress: {
|
||||
id: 'clearStress',
|
||||
|
|
@ -228,7 +244,23 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-regular fa-face-surprise',
|
||||
img: 'icons/magic/perception/eye-ringed-green.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.clearStress.description'),
|
||||
actions: []
|
||||
actions: {
|
||||
clearStress: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.clearStress.name'),
|
||||
img: 'icons/magic/perception/eye-ringed-green.webp',
|
||||
actionType: 'action',
|
||||
healing: {
|
||||
applyTo: healingTypes.stress.id,
|
||||
value: {
|
||||
custom: {
|
||||
enabled: true,
|
||||
formula: '@system.resources.stress.max'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
repairArmor: {
|
||||
id: 'repairArmor',
|
||||
|
|
@ -236,7 +268,23 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-hammer',
|
||||
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.repairArmor.description'),
|
||||
actions: []
|
||||
actions: {
|
||||
repairArmor: {
|
||||
type: 'healing',
|
||||
name: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.repairArmor.name'),
|
||||
img: 'icons/skills/trades/smithing-anvil-silver-red.webp',
|
||||
actionType: 'action',
|
||||
healing: {
|
||||
applyTo: healingTypes.armorStack.id,
|
||||
value: {
|
||||
custom: {
|
||||
enabled: true,
|
||||
formula: '@system.armorScore'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
prepare: {
|
||||
id: 'prepare',
|
||||
|
|
@ -244,7 +292,7 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-dumbbell',
|
||||
img: 'icons/skills/trades/academics-merchant-scribe.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.prepare.description'),
|
||||
actions: []
|
||||
actions: {}
|
||||
},
|
||||
workOnAProject: {
|
||||
id: 'workOnAProject',
|
||||
|
|
@ -252,7 +300,7 @@ export const defaultRestOptions = {
|
|||
icon: 'fa-solid fa-diagram-project',
|
||||
img: 'icons/skills/social/thumbsup-approval-like.webp',
|
||||
description: game.i18n.localize('DAGGERHEART.APPLICATIONS.Downtime.longRest.workOnAProject.description'),
|
||||
actions: []
|
||||
actions: {}
|
||||
}
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
|||
async use(event, ...args) {
|
||||
if (!this.actor) throw new Error("An Action can't be used outside of an Actor context.");
|
||||
|
||||
if (this.chatDisplay) this.toChat();
|
||||
|
||||
let config = this.prepareConfig(event);
|
||||
for (let i = 0; i < this.constructor.extraSchemas.length; i++) {
|
||||
let clsField = this.constructor.getActionField(this.constructor.extraSchemas[i]);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default class DHHealingAction extends DHBaseAction {
|
|||
healing: game.i18n.localize(CONFIG.DH.GENERAL.healingTypes[this.healing.applyTo].label)
|
||||
}),
|
||||
roll: formulas,
|
||||
targets: (data.system?.targets ?? data.targets).filter(t => t.hit),
|
||||
targets: systemData.targets?.filter(t => t.hit),
|
||||
messageType: 'healing',
|
||||
source: systemData.source,
|
||||
data: this.getRollData(),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import DHBaseAction from '../../data/action/baseAction.mjs';
|
||||
|
||||
const fields = foundry.data.fields;
|
||||
|
||||
export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
||||
|
|
@ -44,7 +42,9 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
|
|||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||
this.currentTargets =
|
||||
this.targetSelection !== true
|
||||
? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t))
|
||||
? Array.from(game.user.targets).map(t =>
|
||||
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||
)
|
||||
: this.targets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
import DHBaseAction from "../action/baseAction.mjs";
|
||||
|
||||
export default class DHApplyEffect extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields;
|
||||
|
|
@ -27,7 +25,9 @@ export default class DHApplyEffect extends foundry.abstract.TypeDataModel {
|
|||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||
this.currentTargets =
|
||||
this.targetSelection !== true
|
||||
? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t))
|
||||
? Array.from(game.user.targets).map(t =>
|
||||
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||
)
|
||||
: this.targets;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,9 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
|
|||
this.hasHitTarget = this.targets.filter(t => t.hit === true).length > 0;
|
||||
this.currentTargets =
|
||||
this.targetSelection !== true
|
||||
? Array.from(game.user.targets).map(t => DHBaseAction.formatTarget(t))
|
||||
? Array.from(game.user.targets).map(t =>
|
||||
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
|
||||
)
|
||||
: this.targets;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,7 +170,9 @@ export function ActionMixin(Base) {
|
|||
if (!type || !game.system.api.models.actions.actionsTypes[type]) {
|
||||
({ type } =
|
||||
(await foundry.applications.api.DialogV2.input({
|
||||
window: { title: 'Select Action Type' },
|
||||
window: { title: game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectType') },
|
||||
position: { width: 300 },
|
||||
classes: ['daggerheart', 'dh-style'],
|
||||
content: await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/actionTypes/actionType.hbs',
|
||||
{ types: CONFIG.DH.ACTIONS.actionTypes }
|
||||
|
|
@ -202,11 +204,20 @@ export function ActionMixin(Base) {
|
|||
}
|
||||
|
||||
async update(updates, options = {}) {
|
||||
const path = this.inCollection ? `system.${this.systemPath}.${this.id}` : `system.${this.systemPath}`,
|
||||
const isSetting = !this.parent.parent;
|
||||
const basePath = isSetting ? this.systemPath : `system.${this.systemPath}`;
|
||||
const path = this.inCollection ? `${basePath}.${this.id}` : basePath;
|
||||
let result = null;
|
||||
if (isSetting) {
|
||||
await this.parent.updateSource({ [path]: updates }, options);
|
||||
result = this.parent;
|
||||
} else {
|
||||
result = await this.item.update({ [path]: updates }, options);
|
||||
}
|
||||
|
||||
return this.inCollection
|
||||
? foundry.utils.getProperty(result, `system.${this.systemPath}`).get(this.id)
|
||||
: foundry.utils.getProperty(result, `system.${this.systemPath}`);
|
||||
? foundry.utils.getProperty(result, basePath).get(this.id)
|
||||
: foundry.utils.getProperty(result, basePath);
|
||||
}
|
||||
|
||||
delete() {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const attributeField = label =>
|
|||
|
||||
const resourceField = (max = 0, label, reverse = false) =>
|
||||
new fields.SchemaField({
|
||||
value: new fields.NumberField({ initial: 0, integer: true, label }),
|
||||
value: new fields.NumberField({ initial: 0, min: 0, integer: true, label }),
|
||||
max: new fields.NumberField({ initial: max, integer: true }),
|
||||
isReversed: new fields.BooleanField({ initial: reverse })
|
||||
});
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ export default class DhAppearance extends foundry.abstract.DataModel {
|
|||
dualityColorScheme: new fields.StringField({
|
||||
required: true,
|
||||
choices: DualityRollColor,
|
||||
initial: DualityRollColor.normal.value
|
||||
initial: DualityRollColor.normal.value,
|
||||
label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.dualityColorScheme.label'
|
||||
}),
|
||||
diceSoNice: new fields.SchemaField({
|
||||
hope: new fields.SchemaField({
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { defaultRestOptions } from '../../config/generalConfig.mjs';
|
||||
import { ActionsField } from '../fields/actionField.mjs';
|
||||
|
||||
export default class DhHomebrew extends foundry.abstract.DataModel {
|
||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Homebrew']; // Doesn't work for some reason
|
||||
|
|
@ -61,7 +62,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
base64: false
|
||||
}),
|
||||
description: new fields.HTMLField(),
|
||||
actions: new fields.ArrayField(new fields.ObjectField())
|
||||
actions: new ActionsField()
|
||||
}),
|
||||
{ initial: defaultRestOptions.longRest() }
|
||||
)
|
||||
|
|
@ -78,7 +79,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel {
|
|||
base64: false
|
||||
}),
|
||||
description: new fields.HTMLField(),
|
||||
actions: new fields.ArrayField(new fields.ObjectField())
|
||||
actions: new ActionsField()
|
||||
}),
|
||||
{ initial: defaultRestOptions.shortRest() }
|
||||
)
|
||||
|
|
|
|||
|
|
@ -568,13 +568,7 @@ export default class DhpActor extends Actor {
|
|||
}
|
||||
|
||||
convertDamageToThreshold(damage) {
|
||||
return damage >= this.system.damageThresholds.severe
|
||||
? 3
|
||||
: damage >= this.system.damageThresholds.major
|
||||
? 2
|
||||
: damage >= this.system.damageThresholds.minor
|
||||
? 1
|
||||
: 0;
|
||||
return damage >= this.system.damageThresholds.severe ? 3 : damage >= this.system.damageThresholds.major ? 2 : 1;
|
||||
}
|
||||
|
||||
convertStressDamageToHP(resources) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import ActionSelectionDialog from '../applications/dialogs/actionSelectionDialog.mjs';
|
||||
|
||||
/**
|
||||
* Override and extend the basic Item implementation.
|
||||
* @extends {foundry.documents.Item}
|
||||
|
|
@ -94,46 +96,16 @@ export default class DHItem extends foundry.documents.Item {
|
|||
});
|
||||
}
|
||||
|
||||
async selectActionDialog(prevEvent) {
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
'systems/daggerheart/templates/dialogs/actionSelect.hbs',
|
||||
{
|
||||
actions: this.system.actionsList,
|
||||
itemName: this.name
|
||||
}
|
||||
),
|
||||
title = game.i18n.localize('DAGGERHEART.CONFIG.SelectAction.selectAction');
|
||||
|
||||
return foundry.applications.api.DialogV2.prompt({
|
||||
window: { title },
|
||||
classes: ['daggerheart', 'dh-style'],
|
||||
content,
|
||||
ok: {
|
||||
label: title,
|
||||
callback: (event, button, dialog) => {
|
||||
Object.defineProperty(prevEvent, 'shiftKey', {
|
||||
get() {
|
||||
return event.shiftKey;
|
||||
}
|
||||
});
|
||||
return this.system.actionsList.find(a => a._id === button.form.elements.actionId.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async use(event) {
|
||||
const actions = new Set(this.system.actionsList);
|
||||
if (actions?.size) {
|
||||
let action = actions.first();
|
||||
if (actions.size > 1 && !event?.shiftKey) {
|
||||
// Actions Choice Dialog
|
||||
action = await this.selectActionDialog(event);
|
||||
action = await ActionSelectionDialog.create(this, event);
|
||||
}
|
||||
if (action) return action.use(event);
|
||||
}
|
||||
|
||||
return this.toChat();
|
||||
}
|
||||
|
||||
async toChat(origin) {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ export default class RegisterHandlebarsHelpers {
|
|||
|
||||
static rollParsed(value, actor, item, numerical) {
|
||||
const isNumerical = typeof numerical === 'boolean' ? numerical : false;
|
||||
const result = itemAbleRollParse(value, actor, item);
|
||||
return isNumerical && !result ? 0 : result;
|
||||
const result = itemAbleRollParse(value, actor.getRollData(), item);
|
||||
return isNumerical ? (!result ? 0 : Number(result)) : result;
|
||||
}
|
||||
|
||||
static setVar(name, value, context) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue