mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-03-07 14:36:13 +01:00
FEAT: create isNPC geeter and add the prop on metada on actors
FEAT: create common method for documents sheets FEAT: create BaseActorSheet and implementation
This commit is contained in:
parent
608920c193
commit
98fee6096d
11 changed files with 302 additions and 418 deletions
|
|
@ -1,12 +1,10 @@
|
|||
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
||||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHAdversarySettings from '../../sheets-configs/adversary-settings.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
||||
export default class AdversarySheet extends DHBaseActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'adversary'],
|
||||
classes: ['adversary'],
|
||||
position: { width: 660, height: 766 },
|
||||
actions: {
|
||||
reactionRoll: this.reactionRoll,
|
||||
|
|
@ -19,11 +17,6 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
toggleStress: this.toggleStress,
|
||||
openSettings: this.openSettings
|
||||
},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -34,40 +27,20 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
effects: { template: 'systems/daggerheart/templates/sheets/actors/adversary/effects.hbs' }
|
||||
};
|
||||
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
features: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'features',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.General.tabs.features'
|
||||
},
|
||||
notes: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'notes',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Adversary.Tabs.notes'
|
||||
},
|
||||
effects: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'effects',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Adversary.Tabs.effects'
|
||||
primary: {
|
||||
tabs: [{ id: 'features' }, { id: 'notes'}, { id: 'effects'}],
|
||||
initial: 'features',
|
||||
labelPrefix: 'DAGGERHEART.Sheets.Adversary.Tabs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
/**@inheritdoc */
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.systemFields.attack.fields = this.document.system.attack.schema.fields;
|
||||
context.getEffectDetails = this.getEffectDetails.bind(this);
|
||||
context.isNPC = true;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -77,11 +50,6 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
return item;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async reactionRoll(event) {
|
||||
const config = {
|
||||
event: event,
|
||||
|
|
@ -100,10 +68,6 @@ export default class AdversarySheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
this.actor.diceRoll(config);
|
||||
}
|
||||
|
||||
getEffectDetails(id) {
|
||||
return {};
|
||||
}
|
||||
|
||||
static async openSettings() {
|
||||
await new DHAdversarySettings(this.document).render(true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,19 @@
|
|||
import { capitalize } from '../../../helpers/utils.mjs';
|
||||
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||
import DhpDeathMove from '../../dialogs/deathMove.mjs';
|
||||
import DhpDowntime from '../../dialogs/downtime.mjs';
|
||||
import DaggerheartSheet from '.././daggerheart-sheet.mjs';
|
||||
import { abilities } from '../../../config/actorConfig.mjs';
|
||||
import DhCharacterlevelUp from '../../levelup/characterLevelup.mjs';
|
||||
import DhCharacterCreation from '../../characterCreation/characterCreation.mjs';
|
||||
import FilterMenu from '../../ux/filter-menu.mjs';
|
||||
import DHActionConfig from '../../sheets-configs/action-config.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
const { TextEditor } = foundry.applications.ux;
|
||||
export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
export default class CharacterSheet extends DHBaseActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'daggerheart', 'character'],
|
||||
classes: ['character'],
|
||||
position: { width: 850, height: 800 },
|
||||
actions: {
|
||||
triggerContextMenu: CharacterSheet.#triggerContextMenu,
|
||||
attributeRoll: this.rollAttribute,
|
||||
toggleMarks: this.toggleMarks,
|
||||
toggleHP: this.toggleHP,
|
||||
|
|
@ -37,7 +31,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
useFeature: this.useFeature,
|
||||
takeShortRest: this.takeShortRest,
|
||||
takeLongRest: this.takeLongRest,
|
||||
deleteItem: this.deleteItem,
|
||||
addScar: this.addScar,
|
||||
deleteScar: this.deleteScar,
|
||||
makeDeathMove: this.makeDeathMove,
|
||||
|
|
@ -50,16 +43,22 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
toggleVault: this.toggleVault,
|
||||
levelManagement: this.levelManagement,
|
||||
editImage: this._onEditImage,
|
||||
triggerContextMenu: this.triggerContextMenu
|
||||
},
|
||||
window: {
|
||||
resizable: true
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
},
|
||||
dragDrop: []
|
||||
dragDrop: [],
|
||||
contextMenus: [
|
||||
{
|
||||
handler: CharacterSheet._getContextMenuOptions,
|
||||
selector: '[data-item-id]',
|
||||
options: {
|
||||
parentClassHooks: false,
|
||||
fixed: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -93,217 +92,42 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
features: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'features',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.Features'
|
||||
},
|
||||
loadout: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'loadout',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.Loadout'
|
||||
},
|
||||
inventory: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'inventory',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.Inventory'
|
||||
},
|
||||
biography: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'biography',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.biography'
|
||||
},
|
||||
effects: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'effects',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.effects'
|
||||
primary: {
|
||||
tabs: [{
|
||||
id: 'features',
|
||||
label: "DAGGERHEART.Sheets.PC.Tabs.Features"
|
||||
}, {
|
||||
id: 'loadout',
|
||||
label: "DAGGERHEART.Sheets.PC.Tabs.Loadout"
|
||||
}, {
|
||||
id: 'inventory',
|
||||
label: "DAGGERHEART.Sheets.PC.Tabs.Inventory"
|
||||
}, {
|
||||
id: 'biography',
|
||||
label: "DAGGERHEART.Sheets.PC.Tabs.biography"
|
||||
}, {
|
||||
id: 'effects',
|
||||
label: "DAGGERHEART.Sheets.PC.Tabs.effects"
|
||||
}],
|
||||
initial: 'features',
|
||||
}
|
||||
};
|
||||
|
||||
_getTabs() {
|
||||
const setActive = 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' : '';
|
||||
}
|
||||
};
|
||||
|
||||
const primaryTabs = {
|
||||
features: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'features',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Features')
|
||||
},
|
||||
loadout: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'loadout',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout')
|
||||
},
|
||||
inventory: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'inventory',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Inventory')
|
||||
},
|
||||
story: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'story',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Story')
|
||||
}
|
||||
};
|
||||
const secondaryTabs = {
|
||||
foundation: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'secondary',
|
||||
id: 'foundation',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Foundation')
|
||||
},
|
||||
loadout: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'secondary',
|
||||
id: 'loadout',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Loadout')
|
||||
},
|
||||
vault: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'secondary',
|
||||
id: 'vault',
|
||||
icon: null,
|
||||
label: game.i18n.localize('DAGGERHEART.Sheets.PC.Tabs.Vault')
|
||||
}
|
||||
};
|
||||
|
||||
setActive(primaryTabs);
|
||||
setActive(secondaryTabs);
|
||||
|
||||
return { primary: primaryTabs, secondary: secondaryTabs };
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
async _onFirstRender(context, options) {
|
||||
await super._onFirstRender(context, options);
|
||||
|
||||
this._createContextMenues();
|
||||
}
|
||||
|
||||
/** @inheritDoc */
|
||||
async _onRender(context, options) {
|
||||
await super._onRender(context, options);
|
||||
|
||||
this.element.querySelector('.level-value')?.addEventListener('change', this.onLevelChange.bind(this));
|
||||
|
||||
this._createFilterMenus();
|
||||
this._createSearchFilter();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
_createContextMenues() {
|
||||
const allOptions = {
|
||||
useItem: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.UseItem',
|
||||
icon: '<i class="fa-solid fa-burst"></i>',
|
||||
condition: el => {
|
||||
const item = this.getItem(el);
|
||||
return !['class', 'subclass'].includes(item.type);
|
||||
},
|
||||
callback: (button, event) => this.constructor.useItem.bind(this)(event, button)
|
||||
},
|
||||
equip: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Equip',
|
||||
icon: '<i class="fa-solid fa-hands"></i>',
|
||||
condition: el => {
|
||||
const item = this.getItem(el);
|
||||
return ['weapon', 'armor'].includes(item.type) && !item.system.equipped;
|
||||
},
|
||||
callback: this.constructor.toggleEquipItem.bind(this)
|
||||
},
|
||||
unequip: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Unequip',
|
||||
icon: '<i class="fa-solid fa-hands"></i>',
|
||||
condition: el => {
|
||||
const item = this.getItem(el);
|
||||
return ['weapon', 'armor'].includes(item.type) && item.system.equipped;
|
||||
},
|
||||
callback: this.constructor.toggleEquipItem.bind(this)
|
||||
},
|
||||
sendToLoadout: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToLoadout',
|
||||
icon: '<i class="fa-solid fa-arrow-up"></i>',
|
||||
condition: el => {
|
||||
const item = this.getItem(el);
|
||||
return ['domainCard'].includes(item.type) && item.system.inVault;
|
||||
},
|
||||
callback: this.constructor.toggleVault.bind(this)
|
||||
},
|
||||
sendToVault: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToVault',
|
||||
icon: '<i class="fa-solid fa-arrow-down"></i>',
|
||||
condition: el => {
|
||||
const item = this.getItem(el);
|
||||
return ['domainCard'].includes(item.type) && !item.system.inVault;
|
||||
},
|
||||
callback: this.constructor.toggleVault.bind(this)
|
||||
},
|
||||
sendToChat: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.SendToChat',
|
||||
icon: '<i class="fa-regular fa-message"></i>',
|
||||
callback: this.constructor.toChat.bind(this)
|
||||
},
|
||||
edit: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Edit',
|
||||
icon: '<i class="fa-solid fa-pen-to-square"></i>',
|
||||
callback: this.constructor.viewObject.bind(this)
|
||||
},
|
||||
delete: {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Delete',
|
||||
icon: '<i class="fa-solid fa-trash"></i>',
|
||||
callback: this.constructor.deleteItem.bind(this)
|
||||
}
|
||||
};
|
||||
|
||||
this._createContextMenu(() => Object.values(allOptions), `[data-item-id]`, {
|
||||
parentClassHooks: false,
|
||||
fixed: true
|
||||
});
|
||||
}
|
||||
|
||||
_attachPartListeners(partId, htmlElement, options) {
|
||||
super._attachPartListeners(partId, htmlElement, options);
|
||||
|
||||
htmlElement.querySelector('.level-value')?.addEventListener('change', this.onLevelChange.bind(this));
|
||||
}
|
||||
|
||||
getItem(element) {
|
||||
const listElement = (element.target ?? element).closest('[data-item-id]');
|
||||
const itemId = listElement.dataset.itemId;
|
||||
|
|
@ -316,10 +140,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
}
|
||||
}
|
||||
|
||||
static triggerContextMenu(event, button) {
|
||||
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
|
||||
}
|
||||
|
||||
static _onEditImage() {
|
||||
const fp = new foundry.applications.apps.FilePicker.implementation({
|
||||
current: this.document.img,
|
||||
|
|
@ -334,9 +154,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
context.config = CONFIG.DH;
|
||||
|
||||
context.attributes = Object.keys(this.document.system.traits).reduce((acc, key) => {
|
||||
acc[key] = {
|
||||
|
|
@ -370,6 +187,78 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
return context;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Context Menu */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the set of ContextMenu options.
|
||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]} The Array of context options passed to the ContextMenu instance
|
||||
* @protected
|
||||
*/
|
||||
static _getContextMenuOptions() {
|
||||
|
||||
/**
|
||||
* Get the item from the element.
|
||||
* @param {HTMLElement} el
|
||||
* @returns {foundry.documents.Item?}
|
||||
*/
|
||||
const getItem = (el) => this.actor.items.get(el.closest('[data-item-id]')?.dataset.itemId);
|
||||
|
||||
return [{
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.UseItem',
|
||||
icon: '<i class="fa-solid fa-burst"></i>',
|
||||
condition: el => {
|
||||
const item = getItem(el);
|
||||
return !['class', 'subclass'].includes(item.type);
|
||||
},
|
||||
callback: (button, event) => CharacterSheet.useItem.call(this, event, button)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Equip',
|
||||
icon: '<i class="fa-solid fa-hands"></i>',
|
||||
condition: el => {
|
||||
const item = getItem(el);
|
||||
return ['weapon', 'armor'].includes(item.type) && !item.system.equipped;
|
||||
},
|
||||
callback: CharacterSheet.toggleEquipItem.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Unequip',
|
||||
icon: '<i class="fa-solid fa-hands"></i>',
|
||||
condition: el => {
|
||||
const item = getItem(el);
|
||||
return ['weapon', 'armor'].includes(item.type) && item.system.equipped;
|
||||
},
|
||||
callback: CharacterSheet.toggleEquipItem.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToLoadout',
|
||||
icon: '<i class="fa-solid fa-arrow-up"></i>',
|
||||
condition: (el) => {
|
||||
const item = getItem(el);
|
||||
return ['domainCard'].includes(item.type) && item.system.inVault;
|
||||
},
|
||||
callback: CharacterSheet.toggleVault.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToVault',
|
||||
icon: '<i class="fa-solid fa-arrow-down"></i>',
|
||||
condition: el => {
|
||||
const item = getItem(el);
|
||||
return ['domainCard'].includes(item.type) && !item.system.inVault;
|
||||
},
|
||||
callback: CharacterSheet.toggleVault.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.SendToChat',
|
||||
icon: '<i class="fa-regular fa-message"></i>',
|
||||
callback: CharacterSheet.toChat.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Edit',
|
||||
icon: '<i class="fa-solid fa-pen-to-square"></i>',
|
||||
callback: CharacterSheet.viewObject.bind(this)
|
||||
}, {
|
||||
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Delete',
|
||||
icon: '<i class="fa-solid fa-trash"></i>',
|
||||
callback: (el) => getItem(el).delete()
|
||||
}];
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
/* Filter Tracking */
|
||||
/* -------------------------------------------- */
|
||||
|
|
@ -804,13 +693,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
this.render();
|
||||
}
|
||||
|
||||
static async deleteItem(event) {
|
||||
const item = this.getItem(event);
|
||||
if (!item) return;
|
||||
|
||||
await item.delete();
|
||||
}
|
||||
|
||||
static async setItemQuantity(button, value) {
|
||||
const item = this.getItem(button);
|
||||
if (!item) return;
|
||||
|
|
@ -876,7 +758,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
: this.document.system.class.subclass;
|
||||
const ability = item.system[`${button.dataset.key}Feature`];
|
||||
const title = `${item.name} - ${game.i18n.localize(
|
||||
`DAGGERHEART.Sheets.PC.DomainCard.${capitalize(button.dataset.key)}Title`
|
||||
`DAGGERHEART.Sheets.PC.DomainCard.${button.dataset.key.capitalize()}Title`
|
||||
)}`;
|
||||
|
||||
const cls = getDocumentClass('ChatMessage');
|
||||
|
|
@ -982,4 +864,14 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
itemData = itemData instanceof Array ? itemData : [itemData];
|
||||
return this.document.createEmbeddedDocuments('Item', itemData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the context menu.
|
||||
* @param {PointerEvent} event -
|
||||
* @param {HTMLElement} _ -
|
||||
* @returns
|
||||
*/
|
||||
static #triggerContextMenu(event, _) {
|
||||
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||
import DHCompanionSettings from '../../sheets-configs/companion-settings.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
||||
export default class DhCompanionSheet extends DHBaseActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'companion'],
|
||||
classes: ['actor', 'companion'],
|
||||
position: { width: 300 },
|
||||
actions: {
|
||||
viewActor: this.viewActor,
|
||||
|
|
@ -13,11 +11,6 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
useItem: this.useItem,
|
||||
toChat: this.toChat
|
||||
},
|
||||
form: {
|
||||
handler: this.updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
}
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
|
|
@ -26,38 +19,17 @@ export default class DhCompanionSheet extends DaggerheartSheet(ActorSheetV2) {
|
|||
effects: { template: 'systems/daggerheart/templates/sheets/actors/companion/effects.hbs' }
|
||||
};
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
details: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'details',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.General.tabs.details'
|
||||
},
|
||||
effects: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'effects',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.PC.Tabs.effects'
|
||||
primary: {
|
||||
tabs: [{ id: 'details' }, { id: 'effects', label: 'DAGGERHEART.Sheets.TABS.effects' }],
|
||||
initial: 'details',
|
||||
labelPrefix: 'DAGGERHEART.General.tabs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
static async updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
static async viewActor(_, button) {
|
||||
const target = button.closest('[data-item-uuid]');
|
||||
const actor = await foundry.utils.fromUuid(target.dataset.itemUuid);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import DaggerheartSheet from '../daggerheart-sheet.mjs';
|
||||
import DHBaseActorSheet from '../api/base-actor.mjs';
|
||||
import DHEnvironmentSettings from '../../sheets-configs/environment-settings.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
|
||||
export default class DhpEnvironment extends DHBaseActorSheet {
|
||||
static DEFAULT_OPTIONS = {
|
||||
tag: 'form',
|
||||
classes: ['daggerheart', 'sheet', 'actor', 'dh-style', 'environment'],
|
||||
classes: ['environment'],
|
||||
position: {
|
||||
width: 500
|
||||
},
|
||||
|
|
@ -16,11 +14,6 @@ export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
|
|||
useItem: this.useItem,
|
||||
toChat: this.toChat
|
||||
},
|
||||
form: {
|
||||
handler: this._updateForm,
|
||||
submitOnChange: true,
|
||||
closeOnSubmit: false
|
||||
},
|
||||
dragDrop: [{ dragSelector: '.action-section .inventory-item', dropSelector: null }]
|
||||
};
|
||||
|
||||
|
|
@ -33,38 +26,17 @@ export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
|
|||
notes: { template: 'systems/daggerheart/templates/sheets/actors/environment/notes.hbs' }
|
||||
};
|
||||
|
||||
/** @inheritdoc */
|
||||
static TABS = {
|
||||
features: {
|
||||
active: true,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'features',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.General.tabs.features'
|
||||
},
|
||||
potentialAdversaries: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'potentialAdversaries',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.General.tabs.potentialAdversaries'
|
||||
},
|
||||
notes: {
|
||||
active: false,
|
||||
cssClass: '',
|
||||
group: 'primary',
|
||||
id: 'notes',
|
||||
icon: null,
|
||||
label: 'DAGGERHEART.Sheets.Adversary.Tabs.notes'
|
||||
primary: {
|
||||
tabs: [{ id: 'features' }, { id: 'potentialAdversaries' }, { id: 'notes', label: "DAGGERHEART.Sheets.Adversary.Tabs.notes" }],
|
||||
initial: 'features',
|
||||
labelPrefix: 'DAGGERHEART.General.tabs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.document = this.document;
|
||||
context.tabs = super._getTabs(this.constructor.TABS);
|
||||
context.getEffectDetails = this.getEffectDetails.bind(this);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
|
@ -79,15 +51,6 @@ export default class DhpEnvironment extends DaggerheartSheet(ActorSheetV2) {
|
|||
await new DHEnvironmentSettings(this.document).render(true);
|
||||
}
|
||||
|
||||
static async _updateForm(event, _, formData) {
|
||||
await this.document.update(formData.object);
|
||||
this.render();
|
||||
}
|
||||
|
||||
getEffectDetails(id) {
|
||||
return {};
|
||||
}
|
||||
|
||||
static async addAdversary() {
|
||||
await this.document.update({
|
||||
[`system.potentialAdversaries.${foundry.utils.randomID()}.label`]: game.i18n.localize(
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
export { default as DHApplicationMixin } from './application-mixin.mjs';
|
||||
export { default as DHBaseItemSheet } from './base-item.mjs';
|
||||
export { default as DHHeritageSheet } from './heritage-sheet.mjs';
|
||||
export { default as DHBaseActorSheet } from "./base-actor.mjs";
|
||||
|
|
|
|||
|
|
@ -5,6 +5,14 @@ import { tagifyElement } from '../../../helpers/utils.mjs';
|
|||
* @typedef {object} DragDropConfig
|
||||
* @property {string} [dragSelector] - A CSS selector that identifies draggable elements.
|
||||
* @property {string} [dropSelector] - A CSS selector that identifies drop targets.
|
||||
*
|
||||
* @typedef {object} ContextMenuConfig
|
||||
* @property {() => ContextMenuEntry[]} handler - A handler function that provides initial context options
|
||||
* @property {string} selector - A CSS selector to which the ContextMenu will be bound
|
||||
* @property {object} [options] - Additional options which affect ContextMenu construction
|
||||
* @property {HTMLElement} [options.container] - A parent HTMLElement which contains the selector target
|
||||
* @property {string} [options.hookName] - The hook name
|
||||
* @property {boolean} [options.parentClassHooks=true] - Whether to call hooks for the parent classes in the inheritance chain.
|
||||
*
|
||||
* @typedef {Object} TagOption
|
||||
* @property {string} label
|
||||
|
|
@ -24,11 +32,21 @@ import { tagifyElement } from '../../../helpers/utils.mjs';
|
|||
*
|
||||
* @typedef {Object} TagifyOptions
|
||||
* @property {number} [maxTags] - Maximum number of allowed tags
|
||||
*
|
||||
* @typedef {import("@client/applications/api/handlebars-application.mjs").HandlebarsRenderOptions} HandlebarsRenderOptions
|
||||
* @typedef {foundry.applications.types.ApplicationConfiguration & HandlebarsRenderOptions & { dragDrop?: DragDropConfig[], tagifyConfigs?: TagifyConfig[] }} DHSheetV2Configuration
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import("@client/applications/api/handlebars-application.mjs").HandlebarsRenderOptions} HandlebarsRenderOptions
|
||||
* @typedef {foundry.applications.types.ApplicationConfiguration} FoundryAppConfig
|
||||
*
|
||||
* @typedef {FoundryAppConfig & HandlebarsRenderOptions & {
|
||||
* dragDrop?: DragDropConfig[],
|
||||
* tagifyConfigs?: TagifyConfig[],
|
||||
* contextMenus?: ContextMenuConfig[],
|
||||
* }} DHSheetV2Configuration
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @template {Constructor<foundry.applications.api.DocumentSheet>} BaseDocumentSheet
|
||||
* @param {BaseDocumentSheet} Base - The base class to extend.
|
||||
|
|
@ -54,15 +72,12 @@ export default function DHApplicationMixin(Base) {
|
|||
*/
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['daggerheart', 'sheet', 'dh-style'],
|
||||
position: {
|
||||
width: 480,
|
||||
height: 'auto'
|
||||
},
|
||||
actions: {
|
||||
addEffect: DHSheetV2.#addEffect,
|
||||
editEffect: DHSheetV2.#editEffect,
|
||||
removeEffect: DHSheetV2.#removeEffect
|
||||
createDoc: DHSheetV2.#createDoc,
|
||||
editDoc: DHSheetV2.#editDoc,
|
||||
deleteDoc: DHSheetV2.#deleteDoc
|
||||
},
|
||||
contextMenus: [],
|
||||
dragDrop: [],
|
||||
tagifyConfigs: []
|
||||
};
|
||||
|
|
@ -74,6 +89,11 @@ export default function DHApplicationMixin(Base) {
|
|||
super._attachPartListeners(partId, htmlElement, options);
|
||||
this._dragDrop.forEach(d => d.bind(htmlElement));
|
||||
}
|
||||
/**@inheritdoc */
|
||||
async _onFirstRender(context, options) {
|
||||
await super._onFirstRender(context, options);
|
||||
if (!!this.options.contextMenus.length) this._createContextMenus();
|
||||
}
|
||||
|
||||
/**@inheritdoc */
|
||||
async _onRender(context, options) {
|
||||
|
|
@ -81,6 +101,10 @@ export default function DHApplicationMixin(Base) {
|
|||
this._createTagifyElements(this.options.tagifyConfigs);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Tags */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Creates Tagify elements from configuration objects
|
||||
* @param {TagifyConfig[]} tagConfigs - Array of Tagify configuration objects
|
||||
|
|
@ -140,32 +164,50 @@ export default function DHApplicationMixin(Base) {
|
|||
* @param {DragEvent} event
|
||||
* @protected
|
||||
*/
|
||||
_onDragStart(event) {}
|
||||
_onDragStart(event) { }
|
||||
|
||||
/**
|
||||
* Handle drop event.
|
||||
* @param {DragEvent} event
|
||||
* @protected
|
||||
*/
|
||||
_onDrop(event) {}
|
||||
_onDrop(event) { }
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Context Menu */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
_createContextMenus() {
|
||||
for (const config of this.options.contextMenus) {
|
||||
const { handler, selector, options } = config;
|
||||
this._createContextMenu(handler.bind(this), selector, options);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
|
||||
/**
|
||||
* Get the set of ContextMenu options which should be used for journal entry pages in the sidebar.
|
||||
* @returns {import('@client/applications/ux/context-menu.mjs').ContextMenuEntry[]}
|
||||
* @protected
|
||||
*/
|
||||
_getEntryContextOptions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Prepare Context */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Prepare the template context.
|
||||
* @param {object} options
|
||||
* @param {string} [objectPath='document']
|
||||
* @returns {Promise<object>}
|
||||
* @inheritdoc
|
||||
*/
|
||||
async _prepareContext(options, objectPath = 'document') {
|
||||
/**@inheritdoc*/
|
||||
async _prepareContext(options) {
|
||||
const context = await super._prepareContext(options);
|
||||
context.config = CONFIG.DH;
|
||||
context.source = this[objectPath];
|
||||
context.fields = this[objectPath].schema.fields;
|
||||
context.systemFields = this[objectPath].system ? this[objectPath].system.schema.fields : {};
|
||||
context.source = this.document;
|
||||
context.fields = this.document.schema.fields;
|
||||
context.systemFields = this.document.system.schema.fields;
|
||||
return context;
|
||||
}
|
||||
|
||||
|
|
@ -174,38 +216,44 @@ export default function DHApplicationMixin(Base) {
|
|||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Renders an ActiveEffect's sheet sheet.
|
||||
* Create an embedded document.
|
||||
* @param {PointerEvent} event - The originating click event
|
||||
* @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"]
|
||||
*/
|
||||
static async #addEffect() {
|
||||
const cls = foundry.documents.ActiveEffect;
|
||||
await cls.create(
|
||||
{
|
||||
name: game.i18n.format('DOCUMENT.New', { type: game.i18n.localize(cls.metadata.label) })
|
||||
},
|
||||
{ parent: this.document }
|
||||
);
|
||||
static async #createDoc(event, button) {
|
||||
const { type } = button.dataset;
|
||||
const operation = {
|
||||
parent: this.document,
|
||||
pack: this.document.pack,
|
||||
renderSheet: !event.shiftKey,
|
||||
}
|
||||
|
||||
const cls = getDocumentClass(type);
|
||||
return await cls.createDocuments([{
|
||||
name: cls.defaultName(operation)
|
||||
}], operation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an ActiveEffect's sheet sheet.
|
||||
* Renders an embedded document.
|
||||
* @param {PointerEvent} event - The originating click event
|
||||
* @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"]
|
||||
*/
|
||||
static async #editEffect(_event, button) {
|
||||
const effect = this.document.effects.get(button.dataset.effect);
|
||||
effect.sheet.render({ force: true });
|
||||
static #editDoc(_event, button) {
|
||||
const { type, docId } = button.dataset;
|
||||
this.document.getEmbeddedDocument(type, docId, { strict: true }).sheet.render({ force: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an ActiveEffect from the item.
|
||||
* Delete an embedded document.
|
||||
* @param {PointerEvent} _event - The originating click event
|
||||
* @param {HTMLElement} button - The capturing HTML element which defines the [data-action="removeAction"]
|
||||
*/
|
||||
static async #removeEffect(_event, button) {
|
||||
await this.document.effects.get(button.dataset.effect).delete();
|
||||
static async #deleteDoc(_event, button) {
|
||||
const { type, docId } = button.dataset;
|
||||
await this.document.getEmbeddedDocument(type, docId, { strict: true }).delete();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return DHSheetV2;
|
||||
|
|
|
|||
30
module/applications/sheets/api/base-actor.mjs
Normal file
30
module/applications/sheets/api/base-actor.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import DHApplicationMixin from './application-mixin.mjs';
|
||||
|
||||
const { ActorSheetV2 } = foundry.applications.sheets;
|
||||
|
||||
/**
|
||||
* A base actor sheet extending {@link ActorSheetV2} via {@link DHApplicationMixin}
|
||||
* @extends ActorSheetV2
|
||||
* @mixes DHSheetV2
|
||||
*/
|
||||
export default class DHBaseActorSheet extends DHApplicationMixin(ActorSheetV2) {
|
||||
/** @inheritDoc */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['actor'],
|
||||
position: {
|
||||
width: 480,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: true
|
||||
},
|
||||
actions: {},
|
||||
dragDrop: []
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.isNPC = this.document.isNPC;
|
||||
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,13 +3,15 @@
|
|||
* @typedef {Object} ActorDataModelMetadata
|
||||
* @property {string} label - A localizable label used on application.
|
||||
* @property {string} type - The system type that this data model represents.
|
||||
* @property {Boolean} isNPC - This data model represents a NPC?
|
||||
*/
|
||||
export default class BaseDataActor extends foundry.abstract.TypeDataModel {
|
||||
/** @returns {ActorDataModelMetadata}*/
|
||||
static get metadata() {
|
||||
return {
|
||||
label: 'Base Actor',
|
||||
type: 'base'
|
||||
type: 'base',
|
||||
isNPC: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ export default class DhCharacter extends BaseDataActor {
|
|||
static get metadata() {
|
||||
return foundry.utils.mergeObject(super.metadata, {
|
||||
label: 'TYPES.Actor.character',
|
||||
type: 'character'
|
||||
type: 'character',
|
||||
isNPC: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,16 @@ import { LevelOptionType } from '../data/levelTier.mjs';
|
|||
import DHFeature from '../data/item/feature.mjs';
|
||||
|
||||
export default class DhpActor extends Actor {
|
||||
|
||||
/**
|
||||
* Whether this actor is an NPC.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get isNPC() {
|
||||
return this.system.constructor.metadata.isNPC;
|
||||
}
|
||||
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
if ((await super._preCreate(data, options, user)) === false) return false;
|
||||
|
||||
|
|
@ -351,16 +361,16 @@ export default class DhpActor extends Actor {
|
|||
const modifier = roll.modifier !== null ? Number.parseInt(roll.modifier) : null;
|
||||
return modifier !== null
|
||||
? [
|
||||
{
|
||||
value: modifier,
|
||||
label: roll.label
|
||||
? modifier >= 0
|
||||
? `${roll.label} +${modifier}`
|
||||
: `${roll.label} ${modifier}`
|
||||
: null,
|
||||
title: roll.label
|
||||
}
|
||||
]
|
||||
{
|
||||
value: modifier,
|
||||
label: roll.label
|
||||
? modifier >= 0
|
||||
? `${roll.label} +${modifier}`
|
||||
: `${roll.label} ${modifier}`
|
||||
: null,
|
||||
title: roll.label
|
||||
}
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
|
|
@ -440,10 +450,10 @@ export default class DhpActor extends Actor {
|
|||
damage >= this.system.damageThresholds.severe
|
||||
? 3
|
||||
: damage >= this.system.damageThresholds.major
|
||||
? 2
|
||||
: damage >= this.system.damageThresholds.minor
|
||||
? 1
|
||||
: 0;
|
||||
? 2
|
||||
: damage >= this.system.damageThresholds.minor
|
||||
? 1
|
||||
: 0;
|
||||
|
||||
if (
|
||||
this.type === 'character' &&
|
||||
|
|
|
|||
|
|
@ -4,15 +4,16 @@
|
|||
data-group='{{tabs.effects.group}}'
|
||||
>
|
||||
<fieldset class="one-column">
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Global.Effects"}} <a><i class="fa-solid fa-plus icon-button" data-action="addEffect"></i></a></legend>
|
||||
<legend>{{localize "DAGGERHEART.Sheets.Global.Effects"}}
|
||||
<a data-action="createDoc" data-type="ActiveEffect"><i class="fa-solid fa-plus icon-button"></i></a></legend>
|
||||
<div class="effects-list">
|
||||
{{#each document.effects as |effect|}}
|
||||
<div class="effect-item">
|
||||
<img class="image" src="{{effect.img}}" />
|
||||
<span>{{effect.name}}</span>
|
||||
<div class="controls">
|
||||
<a data-action="editEffect" data-effect="{{effect.id}}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
<a data-action="removeEffect" data-effect="{{effect.id}}"><i class="fa-solid fa-trash"></i></a>
|
||||
<a data-action="editDoc" data-type="ActiveEffect" data-doc-id="{{effect.id}}"><i class="fa-solid fa-pen-to-square"></i></a>
|
||||
<a data-action="deleteDoc" data-type="ActiveEffect" data-doc-id="{{effect.id}}"><i class="fa-solid fa-trash"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue