mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 07:59:03 +01:00
Action Refactor Part #1
This commit is contained in:
parent
42a705a870
commit
5243260b4d
23 changed files with 435 additions and 248 deletions
|
|
@ -13,7 +13,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio
|
||||||
this.action =
|
this.action =
|
||||||
config.data.attack?._id == config.source.action
|
config.data.attack?._id == config.source.action
|
||||||
? config.data.attack
|
? config.data.attack
|
||||||
: this.item.system.actions.find(a => a._id === config.source.action);
|
: this.item.system.actions.get(config.source.action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -175,19 +175,8 @@ export default class DHActionConfig extends DaggerheartSheet(ApplicationV2) {
|
||||||
|
|
||||||
static async updateForm(event, _, formData) {
|
static async updateForm(event, _, formData) {
|
||||||
const submitData = this._prepareSubmitData(event, formData),
|
const submitData = this._prepareSubmitData(event, formData),
|
||||||
data = foundry.utils.mergeObject(this.action.toObject(), submitData),
|
data = foundry.utils.mergeObject(this.action.toObject(), submitData);
|
||||||
container = foundry.utils.getProperty(this.action.parent, this.action.systemPath);
|
this.action = await this.action.update(data);
|
||||||
let newActions;
|
|
||||||
if (Array.isArray(container)) {
|
|
||||||
newActions = foundry.utils.getProperty(this.action.parent, this.action.systemPath).map(x => x.toObject());
|
|
||||||
if (!newActions.findSplice(x => x._id === data._id, data)) newActions.push(data);
|
|
||||||
} else newActions = data;
|
|
||||||
|
|
||||||
const updates = await this.action.parent.parent.update({ [`system.${this.action.systemPath}`]: newActions });
|
|
||||||
if (!updates) return;
|
|
||||||
this.action = Array.isArray(container)
|
|
||||||
? foundry.utils.getProperty(updates.system, this.action.systemPath)[this.action.index]
|
|
||||||
: foundry.utils.getProperty(updates.system, this.action.systemPath);
|
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -271,65 +271,8 @@ export default function DHApplicationMixin(Base) {
|
||||||
*/
|
*/
|
||||||
static #getActionContextOptions() {
|
static #getActionContextOptions() {
|
||||||
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
/**@type {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} */
|
||||||
const getAction = target => {
|
const options = [];
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
return [...options, ...this._getContextMenuCommonOptions.call(this, { usable: true, toChat: true })];
|
||||||
const { actions, attack } = this.document.system;
|
|
||||||
return attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
|
||||||
};
|
|
||||||
|
|
||||||
const options = [
|
|
||||||
{
|
|
||||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.useItem',
|
|
||||||
icon: 'fa-solid fa-burst',
|
|
||||||
condition:
|
|
||||||
this.document instanceof foundry.documents.Actor ||
|
|
||||||
(this.document instanceof foundry.documents.Item && this.document.parent),
|
|
||||||
callback: (target, event) => getAction(target).use(event)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'DAGGERHEART.APPLICATIONS.ContextMenu.sendToChat',
|
|
||||||
icon: 'fa-solid fa-message',
|
|
||||||
callback: target => getAction(target).toChat(this.document.id)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'CONTROLS.CommonEdit',
|
|
||||||
icon: 'fa-solid fa-pen-to-square',
|
|
||||||
callback: target => new DHActionConfig(getAction(target)).render({ force: true })
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'CONTROLS.CommonDelete',
|
|
||||||
icon: 'fa-solid fa-trash',
|
|
||||||
condition: target => {
|
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { attack } = this.document.system;
|
|
||||||
return attack?.id !== actionId;
|
|
||||||
},
|
|
||||||
callback: async target => {
|
|
||||||
const action = getAction(target);
|
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
|
||||||
window: {
|
|
||||||
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
|
||||||
type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
|
|
||||||
name: action.name
|
|
||||||
})
|
|
||||||
},
|
|
||||||
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', {
|
|
||||||
name: action.name
|
|
||||||
})
|
|
||||||
});
|
|
||||||
if (!confirmed) return;
|
|
||||||
|
|
||||||
return this.document.update({
|
|
||||||
'system.actions': this.document.system.actions.filter(a => a.id !== action.id)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
].map(option => ({
|
|
||||||
...option,
|
|
||||||
icon: `<i class="${option.icon}"></i>`
|
|
||||||
}));
|
|
||||||
|
|
||||||
return options;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -409,7 +352,7 @@ export default function DHApplicationMixin(Base) {
|
||||||
? getDocFromElement(extensibleElement)
|
? getDocFromElement(extensibleElement)
|
||||||
: this.document.system.attack?.id === actionId
|
: this.document.system.attack?.id === actionId
|
||||||
? this.document.system.attack
|
? this.document.system.attack
|
||||||
: this.document.system.actions?.find(a => a.id === actionId);
|
: this.document.system.actions?.get(actionId);
|
||||||
if (!doc) return;
|
if (!doc) return;
|
||||||
|
|
||||||
const description = doc.system?.description ?? doc.description;
|
const description = doc.system?.description ?? doc.description;
|
||||||
|
|
@ -435,57 +378,23 @@ export default function DHApplicationMixin(Base) {
|
||||||
static async #createDoc(event, target) {
|
static async #createDoc(event, target) {
|
||||||
const { documentClass, type, inVault, disabled } = target.dataset;
|
const { documentClass, type, inVault, disabled } = target.dataset;
|
||||||
const parentIsItem = this.document.documentName === 'Item';
|
const parentIsItem = this.document.documentName === 'Item';
|
||||||
const parent = parentIsItem && documentClass === 'Item' ? null : this.document;
|
const parent = parentIsItem && documentClass === 'Item' ? (type === 'action' ? this.document.system : null) : this.document;
|
||||||
|
|
||||||
if (type === 'action') {
|
const cls = type === 'action' ? game.system.api.models.actions.actionsTypes.base : getDocumentClass(documentClass);
|
||||||
const { type: actionType } =
|
const data = {
|
||||||
(await foundry.applications.api.DialogV2.input({
|
name: cls.defaultName({ type, parent }),
|
||||||
window: { title: 'Select Action Type' },
|
type
|
||||||
content: await foundry.applications.handlebars.renderTemplate(
|
};
|
||||||
'systems/daggerheart/templates/actionTypes/actionType.hbs',
|
if (inVault) data['system.inVault'] = true;
|
||||||
{ types: CONFIG.DH.ACTIONS.actionTypes }
|
if (disabled) data.disabled = true;
|
||||||
),
|
|
||||||
ok: {
|
const doc = await cls.create(data, { parent, renderSheet: !event.shiftKey });
|
||||||
label: game.i18n.format('DOCUMENT.Create', {
|
if (parentIsItem && type === 'feature') {
|
||||||
type: game.i18n.localize('DAGGERHEART.GENERAL.Action.single')
|
await this.document.update({
|
||||||
})
|
'system.features': this.document.system.toObject().features.concat(doc.uuid)
|
||||||
}
|
|
||||||
})) ?? {};
|
|
||||||
if (!actionType) return;
|
|
||||||
const cls = game.system.api.models.actions.actionsTypes[actionType];
|
|
||||||
const action = new cls(
|
|
||||||
{
|
|
||||||
_id: foundry.utils.randomID(),
|
|
||||||
type: actionType,
|
|
||||||
name: game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[actionType].name),
|
|
||||||
...cls.getSourceConfig(this.document)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
parent: this.document
|
|
||||||
}
|
|
||||||
);
|
|
||||||
await this.document.update({ 'system.actions': [...this.document.system.actions, action] });
|
|
||||||
await new DHActionConfig(this.document.system.actions[this.document.system.actions.length - 1]).render({
|
|
||||||
force: true
|
|
||||||
});
|
});
|
||||||
return action;
|
|
||||||
} else {
|
|
||||||
const cls = getDocumentClass(documentClass);
|
|
||||||
const data = {
|
|
||||||
name: cls.defaultName({ type, parent }),
|
|
||||||
type
|
|
||||||
};
|
|
||||||
if (inVault) data['system.inVault'] = true;
|
|
||||||
if (disabled) data.disabled = true;
|
|
||||||
|
|
||||||
const doc = await cls.create(data, { parent, renderSheet: !event.shiftKey });
|
|
||||||
if (parentIsItem && type === 'feature') {
|
|
||||||
await this.document.update({
|
|
||||||
'system.features': this.document.system.toObject().features.concat(doc.uuid)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return doc;
|
|
||||||
}
|
}
|
||||||
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -495,12 +404,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
static #editDoc(_event, target) {
|
static #editDoc(_event, target) {
|
||||||
const doc = getDocFromElement(target);
|
const doc = getDocFromElement(target);
|
||||||
if (doc) return doc.sheet.render({ force: true });
|
if (doc) return doc.sheet.render({ force: true });
|
||||||
|
|
||||||
// TODO: REDO this
|
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { actions, attack } = this.document.system;
|
|
||||||
const action = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
|
||||||
new DHActionConfig(action).render({ force: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -509,34 +412,10 @@ export default function DHApplicationMixin(Base) {
|
||||||
*/
|
*/
|
||||||
static async #deleteDoc(event, target) {
|
static async #deleteDoc(event, target) {
|
||||||
const doc = getDocFromElement(target);
|
const doc = getDocFromElement(target);
|
||||||
|
|
||||||
if (doc) {
|
if (doc) {
|
||||||
if (event.shiftKey) return doc.delete();
|
if (event.shiftKey) return doc.delete();
|
||||||
else return await doc.deleteDialog();
|
else return await doc.deleteDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: REDO this
|
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { actions, attack } = this.document.system;
|
|
||||||
if (attack?.id === actionId) return;
|
|
||||||
const action = actions.find(a => a.id === actionId);
|
|
||||||
|
|
||||||
if (!event.shiftKey) {
|
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
|
||||||
window: {
|
|
||||||
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
|
||||||
type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
|
|
||||||
name: action.name
|
|
||||||
})
|
|
||||||
},
|
|
||||||
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: action.name })
|
|
||||||
});
|
|
||||||
if (!confirmed) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.document.update({
|
|
||||||
'system.actions': actions.filter(a => a.id !== action.id)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -545,13 +424,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
*/
|
*/
|
||||||
static async #toChat(_event, target) {
|
static async #toChat(_event, target) {
|
||||||
let doc = getDocFromElement(target);
|
let doc = getDocFromElement(target);
|
||||||
|
|
||||||
// TODO: REDO this
|
|
||||||
if (!doc) {
|
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { actions, attack } = this.document.system;
|
|
||||||
doc = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
|
||||||
}
|
|
||||||
return doc.toChat(this.document.id);
|
return doc.toChat(this.document.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,14 +433,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
*/
|
*/
|
||||||
static async #useItem(event, target) {
|
static async #useItem(event, target) {
|
||||||
let doc = getDocFromElement(target);
|
let doc = getDocFromElement(target);
|
||||||
// TODO: REDO this
|
|
||||||
if (!doc) {
|
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { actions, attack } = this.document.system;
|
|
||||||
doc = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
|
||||||
if (this.document instanceof foundry.documents.Item && !this.document.parent) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await doc.use(event);
|
await doc.use(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -578,9 +442,6 @@ export default function DHApplicationMixin(Base) {
|
||||||
*/
|
*/
|
||||||
static async #useAction(event, target) {
|
static async #useAction(event, target) {
|
||||||
const doc = getDocFromElement(target);
|
const doc = getDocFromElement(target);
|
||||||
const { actionId } = target.closest('[data-action-id]').dataset;
|
|
||||||
const { actions, attack } = doc.system;
|
|
||||||
const action = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId);
|
|
||||||
await action.use(event);
|
await action.use(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
submitOnChange: true
|
submitOnChange: true
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
removeAction: DHBaseItemSheet.#removeAction,
|
|
||||||
addFeature: DHBaseItemSheet.#addFeature,
|
addFeature: DHBaseItemSheet.#addFeature,
|
||||||
deleteFeature: DHBaseItemSheet.#deleteFeature,
|
deleteFeature: DHBaseItemSheet.#deleteFeature,
|
||||||
addResource: DHBaseItemSheet.#addResource,
|
addResource: DHBaseItemSheet.#addResource,
|
||||||
|
|
@ -144,33 +143,6 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
|
||||||
/* Application Clicks Actions */
|
/* Application Clicks Actions */
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove an action from the item.
|
|
||||||
* @type {ApplicationClickAction}
|
|
||||||
*/
|
|
||||||
static async #removeAction(event, button) {
|
|
||||||
event.stopPropagation();
|
|
||||||
const actionIndex = button.closest('[data-index]').dataset.index;
|
|
||||||
const action = this.document.system.actions[actionIndex];
|
|
||||||
|
|
||||||
if (!event.shiftKey) {
|
|
||||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
|
||||||
window: {
|
|
||||||
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
|
||||||
type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
|
|
||||||
name: action.name
|
|
||||||
})
|
|
||||||
},
|
|
||||||
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: action.name })
|
|
||||||
});
|
|
||||||
if (!confirmed) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.document.update({
|
|
||||||
'system.actions': this.document.system.actions.filter((_, index) => index !== Number.parseInt(actionIndex))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new feature to the item, prompting the user for its type.
|
* Add a new feature to the item, prompting the user for its type.
|
||||||
* @type {ApplicationClickAction}
|
* @type {ApplicationClickAction}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
|
||||||
? actor.system.attack
|
? actor.system.attack
|
||||||
: item.system.attack?._id === actionId
|
: item.system.attack?._id === actionId
|
||||||
? item.system.attack
|
? item.system.attack
|
||||||
: item?.system?.actions?.find(a => a._id === actionId);
|
: item?.system?.actions?.get(actionId);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ export default class DhHotbar extends foundry.applications.ui.Hotbar {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const action = item.system.actions.find(x => x.id === actionId);
|
const action = item.system.actions.get(actionId);
|
||||||
if (!action) {
|
if (!action) {
|
||||||
return ui.notifications.warn('DAGGERHEART.UI.Notifications.actionIsMissing');
|
return ui.notifications.warn('DAGGERHEART.UI.Notifications.actionIsMissing');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export default class DHAttackAction extends DHDamageAction {
|
||||||
static extraSchemas = [...super.extraSchemas, ...['roll', 'save']];
|
static extraSchemas = [...super.extraSchemas, ...['roll', 'save']];
|
||||||
|
|
||||||
static getRollType(parent) {
|
static getRollType(parent) {
|
||||||
return parent.type === 'weapon' ? 'attack' : 'spellcast';
|
return parent.parent.type === 'weapon' ? 'attack' : 'spellcast';
|
||||||
}
|
}
|
||||||
|
|
||||||
get chatTemplate() {
|
get chatTemplate() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField, DHResourceData } from './actionDice.mjs';
|
import { DHActionDiceData, DHActionRollData, DHDamageData, DHDamageField, DHResourceData } from './actionDice.mjs';
|
||||||
import DhpActor from '../../documents/actor.mjs';
|
import DhpActor from '../../documents/actor.mjs';
|
||||||
import D20RollDialog from '../../applications/dialogs/d20RollDialog.mjs';
|
import D20RollDialog from '../../applications/dialogs/d20RollDialog.mjs';
|
||||||
|
import { ActionMixin } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
|
|
||||||
|
|
@ -16,12 +17,12 @@ const fields = foundry.data.fields;
|
||||||
- Summon Action create method
|
- Summon Action create method
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default class DHBaseAction extends foundry.abstract.DataModel {
|
export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel) {
|
||||||
static extraSchemas = [];
|
static extraSchemas = [];
|
||||||
|
|
||||||
static defineSchema() {
|
static defineSchema() {
|
||||||
return {
|
return {
|
||||||
_id: new fields.DocumentIdField(),
|
_id: new fields.DocumentIdField({ initial: () => foundry.utils.randomID() }),
|
||||||
systemPath: new fields.StringField({ required: true, initial: 'actions' }),
|
systemPath: new fields.StringField({ required: true, initial: 'actions' }),
|
||||||
type: new fields.StringField({ initial: undefined, readonly: true, required: true }),
|
type: new fields.StringField({ initial: undefined, readonly: true, required: true }),
|
||||||
name: new fields.StringField({ initial: undefined }),
|
name: new fields.StringField({ initial: undefined }),
|
||||||
|
|
@ -109,7 +110,10 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
||||||
return extraSchemas;
|
return extraSchemas;
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareData() {}
|
prepareData() {
|
||||||
|
this.name = this.name || game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[this.type].name);
|
||||||
|
this.img = this.img ?? this.parent?.parent?.img;
|
||||||
|
}
|
||||||
|
|
||||||
get index() {
|
get index() {
|
||||||
return foundry.utils.getProperty(this.parent, this.systemPath).indexOf(this);
|
return foundry.utils.getProperty(this.parent, this.systemPath).indexOf(this);
|
||||||
|
|
@ -141,22 +145,21 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
||||||
|
|
||||||
static getSourceConfig(parent) {
|
static getSourceConfig(parent) {
|
||||||
const updateSource = {};
|
const updateSource = {};
|
||||||
updateSource.img ??= parent?.img ?? parent?.system?.img;
|
if (parent?.parent?.type === 'weapon' && this === game.system.api.models.actions.actionsTypes.attack) {
|
||||||
if (parent?.type === 'weapon' && this === game.system.api.models.actions.actionsTypes.attack) {
|
|
||||||
updateSource['damage'] = { includeBase: true };
|
updateSource['damage'] = { includeBase: true };
|
||||||
updateSource['range'] = parent?.system?.attack?.range;
|
updateSource['range'] = parent?.attack?.range;
|
||||||
updateSource['roll'] = {
|
updateSource['roll'] = {
|
||||||
useDefault: true
|
useDefault: true
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
if (parent?.system?.trait) {
|
if (parent?.trait) {
|
||||||
updateSource['roll'] = {
|
updateSource['roll'] = {
|
||||||
type: this.getRollType(parent),
|
type: this.getRollType(parent),
|
||||||
trait: parent.system.trait
|
trait: parent.trait
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (parent?.system?.range) {
|
if (parent?.range) {
|
||||||
updateSource['range'] = parent?.system?.range;
|
updateSource['range'] = parent?.range;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return updateSource;
|
return updateSource;
|
||||||
|
|
@ -552,27 +555,4 @@ export default class DHBaseAction extends foundry.abstract.DataModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async toChat(origin) {
|
|
||||||
const cls = getDocumentClass('ChatMessage');
|
|
||||||
const systemData = {
|
|
||||||
title: game.i18n.localize('DAGGERHEART.CONFIG.ActionType.action'),
|
|
||||||
origin: origin,
|
|
||||||
img: this.img,
|
|
||||||
name: this.name,
|
|
||||||
description: this.description,
|
|
||||||
actions: []
|
|
||||||
};
|
|
||||||
const msg = new cls({
|
|
||||||
type: 'abilityUse',
|
|
||||||
user: game.user.id,
|
|
||||||
system: systemData,
|
|
||||||
content: await foundry.applications.handlebars.renderTemplate(
|
|
||||||
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
|
|
||||||
systemData
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
cls.create(msg.toObject());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs';
|
import DHAdversarySettings from '../../applications/sheets-configs/adversary-settings.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import BaseDataActor from './base.mjs';
|
import BaseDataActor from './base.mjs';
|
||||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import DhLevelData from '../levelData.mjs';
|
import DhLevelData from '../levelData.mjs';
|
||||||
import BaseDataActor from './base.mjs';
|
import BaseDataActor from './base.mjs';
|
||||||
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
import { attributeField, resourceField, stressDamageReductionRule, bonusField } from '../fields/actorField.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DhCharacter extends BaseDataActor {
|
export default class DhCharacter extends BaseDataActor {
|
||||||
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
|
static LOCALIZATION_PREFIXES = ['DAGGERHEART.ACTORS.Character'];
|
||||||
|
|
@ -334,6 +334,7 @@ export default class DhCharacter extends BaseDataActor {
|
||||||
return !primaryWeaponEquipped && !secondaryWeaponEquipped
|
return !primaryWeaponEquipped && !secondaryWeaponEquipped
|
||||||
? {
|
? {
|
||||||
...this.attack,
|
...this.attack,
|
||||||
|
uuid: this.attack.uuid,
|
||||||
id: this.attack.id,
|
id: this.attack.id,
|
||||||
name: this.activeBeastform ? 'DAGGERHEART.ITEMS.Beastform.attackName' : this.attack.name,
|
name: this.activeBeastform ? 'DAGGERHEART.ITEMS.Beastform.attackName' : this.attack.name,
|
||||||
img: this.activeBeastform ? 'icons/creatures/claws/claw-straight-brown.webp' : this.attack.img,
|
img: this.activeBeastform ? 'icons/creatures/claws/claw-straight-brown.webp' : this.attack.img,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import BaseDataActor from './base.mjs';
|
import BaseDataActor from './base.mjs';
|
||||||
import DhLevelData from '../levelData.mjs';
|
import DhLevelData from '../levelData.mjs';
|
||||||
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
import { adjustDice, adjustRange } from '../../helpers/utils.mjs';
|
||||||
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
|
import DHCompanionSettings from '../../applications/sheets-configs/companion-settings.mjs';
|
||||||
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
import { resourceField, bonusField } from '../fields/actorField.mjs';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,215 @@
|
||||||
export default class ActionField extends foundry.data.fields.ObjectField {
|
import DHActionConfig from "../../applications/sheets-configs/action-config.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialized collection type for stored actions.
|
||||||
|
* @param {DataModel} model The parent DataModel to which this ActionCollection belongs.
|
||||||
|
* @param {Action[]} entries The actions to store.
|
||||||
|
*/
|
||||||
|
export class ActionCollection extends Collection {
|
||||||
|
constructor(model, entries) {
|
||||||
|
super();
|
||||||
|
this.#model = model;
|
||||||
|
for ( const entry of entries ) {
|
||||||
|
if ( !(entry instanceof game.system.api.models.actions.actionsTypes.base) ) continue;
|
||||||
|
this.set(entry._id, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Properties */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parent DataModel to which this ActionCollection belongs.
|
||||||
|
* @type {DataModel}
|
||||||
|
*/
|
||||||
|
#model;
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Methods */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the given predicate against every entry in the Collection.
|
||||||
|
* @param {function(*, number, ActionCollection): boolean} predicate The predicate.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
every(predicate) {
|
||||||
|
return this.reduce((pass, v, i) => pass && predicate(v, i, this), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the ActionCollection to an array of simple objects.
|
||||||
|
* @param {boolean} [source=true] Draw data for contained Documents from the underlying data source?
|
||||||
|
* @returns {object[]} The extracted array of primitive objects.
|
||||||
|
*/
|
||||||
|
toObject(source=true) {
|
||||||
|
return this.map(doc => doc.toObject(source));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subclass of ObjectField that represents a mapping of keys to the provided DataField type.
|
||||||
|
*
|
||||||
|
* @param {DataField} model The class of DataField which should be embedded in this field.
|
||||||
|
* @param {MappingFieldOptions} [options={}] Options which configure the behavior of the field.
|
||||||
|
* @property {string[]} [initialKeys] Keys that will be created if no data is provided.
|
||||||
|
* @property {MappingFieldInitialValueBuilder} [initialValue] Function to calculate the initial value for a key.
|
||||||
|
* @property {boolean} [initialKeysOnly=false] Should the keys in the initialized data be limited to the keys provided
|
||||||
|
* by `options.initialKeys`?
|
||||||
|
*/
|
||||||
|
export class MappingField extends foundry.data.fields.ObjectField {
|
||||||
|
constructor(model, options) {
|
||||||
|
if ( !(model instanceof foundry.data.fields.DataField) ) {
|
||||||
|
throw new Error("MappingField must have a DataField as its contained element");
|
||||||
|
}
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The embedded DataField definition which is contained in this field.
|
||||||
|
* @type {DataField}
|
||||||
|
*/
|
||||||
|
this.model = model;
|
||||||
|
model.parent = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
static get _defaults() {
|
||||||
|
return foundry.utils.mergeObject(super._defaults, {
|
||||||
|
initialKeys: null,
|
||||||
|
initialValue: null,
|
||||||
|
initialKeysOnly: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_cleanType(value, options) {
|
||||||
|
Object.entries(value).forEach(([k, v]) => {
|
||||||
|
if ( k.startsWith("-=") ) return;
|
||||||
|
value[k] = this.model.clean(v, options);
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
getInitialValue(data) {
|
||||||
|
let keys = this.initialKeys;
|
||||||
|
const initial = super.getInitialValue(data);
|
||||||
|
if ( !keys || !foundry.utils.isEmpty(initial) ) return initial;
|
||||||
|
if ( !(keys instanceof Array) ) keys = Object.keys(keys);
|
||||||
|
for ( const key of keys ) initial[key] = this._getInitialValueForKey(key);
|
||||||
|
return initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the initial value for the provided key.
|
||||||
|
* @param {string} key Key within the object being built.
|
||||||
|
* @param {object} [object] Any existing mapping data.
|
||||||
|
* @returns {*} Initial value based on provided field type.
|
||||||
|
*/
|
||||||
|
_getInitialValueForKey(key, object) {
|
||||||
|
const initial = this.model.getInitialValue();
|
||||||
|
return this.initialValue?.(key, initial, object) ?? initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_validateType(value, options={}) {
|
||||||
|
if ( foundry.utils.getType(value) !== "Object" ) throw new Error("must be an Object");
|
||||||
|
const errors = this._validateValues(value, options);
|
||||||
|
if ( !foundry.utils.isEmpty(errors) ) {
|
||||||
|
const failure = new foundry.data.validation.DataModelValidationFailure();
|
||||||
|
failure.elements = Object.entries(errors).map(([id, failure]) => ({ id, failure }));
|
||||||
|
throw failure.asError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate each value of the object.
|
||||||
|
* @param {object} value The object to validate.
|
||||||
|
* @param {object} options Validation options.
|
||||||
|
* @returns {Record<string, Error>} An object of value-specific errors by key.
|
||||||
|
*/
|
||||||
|
_validateValues(value, options) {
|
||||||
|
const errors = {};
|
||||||
|
for ( const [k, v] of Object.entries(value) ) {
|
||||||
|
if ( k.startsWith("-=") ) continue;
|
||||||
|
const error = this.model.validate(v, options);
|
||||||
|
if ( error ) errors[k] = error;
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
initialize(value, model, options={}) {
|
||||||
|
if ( !value ) return value;
|
||||||
|
const obj = {};
|
||||||
|
const initialKeys = (this.initialKeys instanceof Array) ? this.initialKeys : Object.keys(this.initialKeys ?? {});
|
||||||
|
const keys = this.initialKeysOnly ? initialKeys : Object.keys(value);
|
||||||
|
for ( const key of keys ) {
|
||||||
|
const data = value[key] ?? this._getInitialValueForKey(key, value);
|
||||||
|
obj[key] = this.model.initialize(data, model, options);
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
_getField(path) {
|
||||||
|
if ( path.length === 0 ) return this;
|
||||||
|
else if ( path.length === 1 ) return this.model;
|
||||||
|
path.shift();
|
||||||
|
return this.model._getField(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field that stores actions.
|
||||||
|
*/
|
||||||
|
export class ActionsField extends MappingField {
|
||||||
|
constructor(options) {
|
||||||
|
super(new ActionField(), options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
initialize(value, model, options) {
|
||||||
|
const actions = Object.values(super.initialize(value, model, options));
|
||||||
|
return new ActionCollection(model, actions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Field that stores action data and swaps class based on action type.
|
||||||
|
*/
|
||||||
|
export class ActionField extends foundry.data.fields.ObjectField {
|
||||||
getModel(value) {
|
getModel(value) {
|
||||||
return game.system.api.models.actions.actionsTypes[value.type] ?? game.system.api.models.actions.actionsTypes.attack;
|
return game.system.api.models.actions.actionsTypes[value.type] ?? game.system.api.models.actions.actionsTypes.attack;
|
||||||
}
|
}
|
||||||
|
|
@ -35,3 +246,141 @@ export default class ActionField extends foundry.data.fields.ObjectField {
|
||||||
if (cls) cls.migrateDataSafe(fieldData);
|
if (cls) cls.migrateDataSafe(fieldData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
export function ActionMixin(Base) {
|
||||||
|
class Action extends Base {
|
||||||
|
static metadata = Object.freeze({
|
||||||
|
name: "Action",
|
||||||
|
label: "DAGGERHEART.GENERAL.Action.single",
|
||||||
|
sheetClass: DHActionConfig
|
||||||
|
});
|
||||||
|
|
||||||
|
static _sheets = new Map();
|
||||||
|
|
||||||
|
static get documentName() {
|
||||||
|
return this.metadata.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
get documentName() {
|
||||||
|
return this.constructor.documentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
static defaultName() {
|
||||||
|
return this.documentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
get relativeUUID() {
|
||||||
|
return `.Item.${this.item.id}.Action.${this.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get uuid() {
|
||||||
|
return `${this.item.uuid}.${this.documentName}.${this.id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get sheet() {
|
||||||
|
if(!this.constructor._sheets.has(this.uuid)) {
|
||||||
|
const sheet = new this.constructor.metadata.sheetClass(this);
|
||||||
|
this.constructor._sheets.set(this.uuid, sheet);
|
||||||
|
}
|
||||||
|
return this.constructor._sheets.get(this.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
get inCollection() {
|
||||||
|
return foundry.utils.getProperty(this.parent, this.systemPath) instanceof Collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async create(data, operation={}) {
|
||||||
|
const { parent, renderSheet } = operation;
|
||||||
|
let { type } = data;
|
||||||
|
if(!type || !game.system.api.models.actions.actionsTypes[type]) {
|
||||||
|
({ type } =
|
||||||
|
(await foundry.applications.api.DialogV2.input({
|
||||||
|
window: { title: 'Select Action Type' },
|
||||||
|
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')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})) ?? {});
|
||||||
|
}
|
||||||
|
if (!type) return;
|
||||||
|
|
||||||
|
const cls = game.system.api.models.actions.actionsTypes[type];
|
||||||
|
const action = new cls(
|
||||||
|
{
|
||||||
|
type,
|
||||||
|
...cls.getSourceConfig(parent)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
parent
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const created = await parent.parent.update({ [`system.actions.${action.id}`]: action.toObject() });
|
||||||
|
const newAction = parent.actions.get(action.id);
|
||||||
|
if(!newAction) return null;
|
||||||
|
if( renderSheet ) newAction.sheet.render({ force: true });
|
||||||
|
return newAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(updates, options={}) {
|
||||||
|
const path = this.inCollection ? `system.${this.systemPath}.${this.id}` : `system.${this.systemPath}`,
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete() {
|
||||||
|
if(!this.inCollection) return this.item;
|
||||||
|
const action = foundry.utils.getProperty(this.item, `system.${this.systemPath}`)?.get(this.id);
|
||||||
|
if ( !action ) return this.item;
|
||||||
|
this.item.update({ [`system.${this.systemPath}.-=${this.id}`]: null });
|
||||||
|
this.constructor._sheets.get(this.uuid)?.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteDialog() {
|
||||||
|
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||||
|
window: {
|
||||||
|
title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', {
|
||||||
|
type: game.i18n.localize(`DAGGERHEART.GENERAL.Action.single`),
|
||||||
|
name: this.name
|
||||||
|
})
|
||||||
|
},
|
||||||
|
content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', {
|
||||||
|
name: this.name
|
||||||
|
})
|
||||||
|
});
|
||||||
|
if (!confirmed) return;
|
||||||
|
return this.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
async toChat(origin) {
|
||||||
|
const cls = getDocumentClass('ChatMessage');
|
||||||
|
const systemData = {
|
||||||
|
title: game.i18n.localize('DAGGERHEART.CONFIG.ActionType.action'),
|
||||||
|
origin: origin,
|
||||||
|
img: this.img,
|
||||||
|
name: this.name,
|
||||||
|
description: this.description,
|
||||||
|
actions: []
|
||||||
|
};
|
||||||
|
const msg = {
|
||||||
|
type: 'abilityUse',
|
||||||
|
user: game.user.id,
|
||||||
|
system: systemData,
|
||||||
|
content: await foundry.applications.handlebars.renderTemplate(
|
||||||
|
'systems/daggerheart/templates/ui/chat/ability-use.hbs',
|
||||||
|
systemData
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
cls.create(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Action;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import AttachableItem from './attachableItem.mjs';
|
import AttachableItem from './attachableItem.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
import { armorFeatures } from '../../config/itemConfig.mjs';
|
import { armorFeatures } from '../../config/itemConfig.mjs';
|
||||||
import { actionsTypes } from '../action/_module.mjs';
|
import { actionsTypes } from '../action/_module.mjs';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHConsumable extends BaseDataItem {
|
export default class DHConsumable extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHDomainCard extends BaseDataItem {
|
export default class DHDomainCard extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHFeature extends BaseDataItem {
|
export default class DHFeature extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import BaseDataItem from './base.mjs';
|
import BaseDataItem from './base.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHMiscellaneous extends BaseDataItem {
|
export default class DHMiscellaneous extends BaseDataItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import AttachableItem from './attachableItem.mjs';
|
import AttachableItem from './attachableItem.mjs';
|
||||||
import { actionsTypes } from '../action/_module.mjs';
|
import { actionsTypes } from '../action/_module.mjs';
|
||||||
import ActionField from '../fields/actionField.mjs';
|
import { ActionsField, ActionField } from '../fields/actionField.mjs';
|
||||||
|
|
||||||
export default class DHWeapon extends AttachableItem {
|
export default class DHWeapon extends AttachableItem {
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
|
|
@ -65,7 +65,8 @@ export default class DHWeapon extends AttachableItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
actions: new fields.ArrayField(new ActionField())
|
actions: new ActionsField()
|
||||||
|
// actions: new fields.ArrayField(new ActionField())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,23 @@ export default class DhpActor extends Actor {
|
||||||
return this.system.metadata.isNPC;
|
return this.system.metadata.isNPC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
getEmbeddedDocument(embeddedName, id, options) {
|
||||||
|
let doc;
|
||||||
|
switch ( embeddedName ) {
|
||||||
|
case "Action":
|
||||||
|
doc = this.system.actions?.get(id);
|
||||||
|
if(!doc && this.system.attack?.id === id) doc = this.system.attack;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return super.getEmbeddedDocument(embeddedName, id, options);
|
||||||
|
}
|
||||||
|
if ( options?.strict && !doc ) {
|
||||||
|
throw new Error(`The key ${id} does not exist in the ${embeddedName} Collection`);
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
async _preCreate(data, options, user) {
|
async _preCreate(data, options, user) {
|
||||||
if ((await super._preCreate(data, options, user)) === false) return false;
|
if ((await super._preCreate(data, options, user)) === false) return false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,23 @@ export default class DHItem extends foundry.documents.Item {
|
||||||
for (const action of this.system.actions ?? []) action.prepareData();
|
for (const action of this.system.actions ?? []) action.prepareData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
getEmbeddedDocument(embeddedName, id, options) {
|
||||||
|
let doc;
|
||||||
|
switch ( embeddedName ) {
|
||||||
|
case "Action":
|
||||||
|
doc = this.system.actions?.get(id);
|
||||||
|
if(!doc && this.system.attack?.id === id) doc = this.system.attack;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return super.getEmbeddedDocument(embeddedName, id, options);
|
||||||
|
}
|
||||||
|
if ( options?.strict && !doc ) {
|
||||||
|
throw new Error(`The key ${id} does not exist in the ${embeddedName} Collection`);
|
||||||
|
}
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* @param {object} options - Options which modify the getRollData method.
|
* @param {object} options - Options which modify the getRollData method.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.Toolti
|
||||||
const actionId = splitValues.length > 1 ? splitValues[1] : null;
|
const actionId = splitValues.length > 1 ? splitValues[1] : null;
|
||||||
|
|
||||||
const baseItem = await foundry.utils.fromUuid(itemUuid);
|
const baseItem = await foundry.utils.fromUuid(itemUuid);
|
||||||
const item = actionId ? baseItem.system.actions.find(x => x.id === actionId) : baseItem;
|
const item = actionId ? baseItem.system.actions.get(actionId) : baseItem;
|
||||||
if (item) {
|
if (item) {
|
||||||
const type = actionId ? 'action' : item.type;
|
const type = actionId ? 'action' : item.type;
|
||||||
const description = await TextEditor.enrichHTML(item.system.description);
|
const description = await TextEditor.enrichHTML(item.system.description);
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ Parameters:
|
||||||
{{#if (and showActions (eq item.type 'feature'))}}
|
{{#if (and showActions (eq item.type 'feature'))}}
|
||||||
<div class="item-buttons">
|
<div class="item-buttons">
|
||||||
{{#each item.system.actions as | action |}}
|
{{#each item.system.actions as | action |}}
|
||||||
<button type="button" data-action="useAction" data-action-id="{{action.id}}">
|
<button type="button" data-action="useAction" data-item-uuid="{{action.uuid}}">
|
||||||
{{action.name}}
|
{{action.name}}
|
||||||
</button>
|
</button>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<fieldset class="dice-roll daggerheart chat roll expanded{{#unless damage.roll}} hidden{{/unless}}" data-action="expandRoll">
|
<fieldset class="dice-roll daggerheart chat roll expanded{{#unless damage.roll}} hidden{{/unless}}" data-action="expandRoll">
|
||||||
<legend class="dice-flavor">{{localize "DAGGEHEART.GENERAL.damage"}}</legend>
|
<legend class="dice-flavor">{{localize "DAGGERHEART.GENERAL.damage"}}</legend>
|
||||||
<div class="dice-result">
|
<div class="dice-result">
|
||||||
<div class="dice-tooltip">
|
<div class="dice-tooltip">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue