daggerheart/module/applications/sheets/items/class.mjs
WBHarry 187ee3e1bd
Refactor/84 data models structure (#131)
* - Move all DataModel item files to a new 'items' subfolder for better organization
- Add _module.mjs file to simplify imports
- Update all import paths
- Rename class for use the new acronym DH

* FIX: remove unnecessary import

* FEAT: BaseDataItem class
add TODO comments for future improvements
FIX: Remove effect field on template
FIX: remove unused DhpEffects file

* FEAT: new FormulaField class
FEAT: add getRollData on BaseDataItem Class
FEAT: weapon
FIX: remove inventoryWeapon field on Weapon Data Model

* FEAT: add class prepareBaseData for domains

* FEAT: new ForeignDocumentUUIDField
FIX: Remove unnecessary fields
FEAT: use ForeignDocumentUUIDField in the Item Class DataModel

* FIX: remove wrong option in String Field

* FIX: remove unused import

* FIX: ADD htmlFields description in manifest

* FIX: minor fixes

* REFACTOR: rename folder `data/items` -> `data/item`
REFACTOR: rename folder `data/messages` -> `data/chat-message`.

* FIX: imports
FIX: items sheet new paths
FIX: ItemDataModelMetadata type jsdoc

* FEAT: formatting code
FIX: fix fields used
FEAT: add jsdoc

* 110 - Class Data Model (#111)

* Added PreCreate/Create/Delete logic for Class/Subclass and set it as foreignUUID fields in PC

* Moved methods into TypedModelData

* Simplified Subclass

* Fixed up data model and a basic placeholder template (#117)

* 118 - adversary data model (#119)

* Fixed datamodel and set up basic template in new style

* Added in a temp attack button, because why not

* Restored HitPoints counting up

* 113 - Character Data Model (#114)

* Improved Character datamodel

* Removed additional unneccessary getters

* Preliminary cleanup in the class sheet

* Cleanup of 'pc' references

* Corrected Duality rolling from Character

* Fix to damage roll

* Added a basic BaseDataActor data model

* Gathered exports

* getRollData recursion fix

* Feature/112 items use action datamodel (#127)

* Create new actions classes

* actions types - attack roll

* fixes before merge

* First PR

* Add daggerheart.css to gitignore

* Update ToDo

* Remove console log

* Fixed chat /dr roll

* Remove jQuery

* Fixed so the different chat themes work again

* Fixed duality roll buttons

* Fix to advantage/disadvantage shortcut

* Extand action to other item types

* Roll fixes

* Fixes to adversary rolls

* resources

* Fixed adversary dice

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>

* Feature/116-implementation-of-pseudo-documents (#125)

* FEAT: add baseDataModel logic

* FEAT: new PseudoDocumentsField
FIX: BasePseudoDocument 's getEmbeddedDocument

* FEAT: PseudoDocument class

* FEAT: add TypedPseudoDocument
REFACTOR: PreudoDocument
FIX: Typos Bug

* FIX: CONFIG types

* FEAT: basic PseudoDocumentSheet

* FIX: remove schema
ADD: input of example

---------

Co-authored-by: Joaquin Pereyra <joaquinpereyra98@users.noreply.github.com>
Co-authored-by: WBHarry <williambjrklund@gmail.com>

* Levelup Followup (#126)

* Levelup applies bonuses to character

* Added visualisation of domain card levels

* Fixed domaincard level max for selections in a tier

* A trait can now only be level up once within the same tier

---------

Co-authored-by: Joaquin Pereyra <joaquinpereyra98@users.noreply.github.com>
Co-authored-by: joaquinpereyra98 <24190917+joaquinpereyra98@users.noreply.github.com>
Co-authored-by: Dapoulp <74197441+Dapoulp@users.noreply.github.com>
2025-06-13 14:17:13 +02:00

205 lines
8.1 KiB
JavaScript

import { tagifyElement } from '../../../helpers/utils.mjs';
import DaggerheartSheet from '../daggerheart-sheet.mjs';
const { ItemSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux;
export default class ClassSheet extends DaggerheartSheet(ItemSheetV2) {
static DEFAULT_OPTIONS = {
tag: 'form',
classes: ['daggerheart', 'sheet', 'item', 'dh-style', 'class'],
position: { width: 700 },
actions: {
removeSubclass: this.removeSubclass,
viewSubclass: this.viewSubclass,
deleteFeature: this.deleteFeature,
editFeature: this.editFeature,
removeItem: this.removeItem,
viewItem: this.viewItem,
removePrimaryWeapon: this.removePrimaryWeapon,
removeSecondaryWeapon: this.removeSecondaryWeapon,
removeArmor: this.removeArmor
},
form: {
handler: this.updateForm,
submitOnChange: true,
closeOnSubmit: false
},
dragDrop: [
{ dragSelector: '.suggested-item', dropSelector: null },
{ dragSelector: null, dropSelector: '.take-section' },
{ dragSelector: null, dropSelector: '.choice-a-section' },
{ dragSelector: null, dropSelector: '.choice-b-section' },
{ dragSelector: null, dropSelector: '.primary-weapon-section' },
{ dragSelector: null, dropSelector: '.secondary-weapon-section' },
{ dragSelector: null, dropSelector: '.armor-section' },
{ dragSelector: null, dropSelector: null }
]
};
static PARTS = {
header: { template: 'systems/daggerheart/templates/sheets/items/class/header.hbs' },
tabs: { template: 'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs' },
features: {
template: 'systems/daggerheart/templates/sheets/items/class/features.hbs',
scrollable: ['.features']
},
settings: {
template: 'systems/daggerheart/templates/sheets/items/class/settings.hbs',
scrollable: ['.settings']
}
};
static TABS = {
features: {
active: true,
cssClass: '',
group: 'primary',
id: 'features',
icon: null,
label: 'DAGGERHEART.Sheets.Class.Tabs.Features'
},
settings: {
active: false,
cssClass: '',
group: 'primary',
id: 'settings',
icon: null,
label: 'DAGGERHEART.Sheets.Class.Tabs.settings'
}
};
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
const domainInput = htmlElement.querySelector('.domain-input');
tagifyElement(domainInput, SYSTEM.DOMAIN.domains, this.onDomainSelect.bind(this));
}
async _prepareContext(_options) {
const context = await super._prepareContext(_options);
context.document = this.document;
context.tabs = super._getTabs(this.constructor.TABS);
context.domains = this.document.system.domains;
return context;
}
static async updateForm(event, _, formData) {
await this.document.update(formData.object);
this.render();
}
onAddTag(e) {
if (e.detail.index === 2) {
ui.notifications.info(game.i18n.localize('DAGGERHEART.Notification.Info.ClassCanOnlyHaveTwoDomains'));
}
}
async onDomainSelect(domains) {
await this.document.update({ 'system.domains': domains.map(x => x.value) });
this.render(true);
}
static async removeSubclass(_, button) {
await this.document.update({
'system.subclasses': this.document.system.subclasses.filter(x => x.uuid !== button.dataset.subclass)
});
}
static async viewSubclass(_, button) {
const subclass = await fromUuid(button.dataset.subclass);
subclass.sheet.render(true);
}
static async deleteFeature(_, button) {
await this.document.update({
'system.features': this.document.system.features.map(x => x.uuid).filter(x => x !== button.dataset.feature)
});
}
static async editFeature(_, button) {
const feature = await fromUuid(button.dataset.feature);
feature.sheet.render(true);
}
static async removeItem(event, button) {
event.stopPropagation();
const type = button.dataset.type;
const path = `system.inventory.${type}`;
await this.document.update({
[path]: this.document.system.inventory[type].filter(x => x.uuid !== button.dataset.item)
});
}
static async viewItem(_, button) {
const item = await fromUuid(button.dataset.item);
item.sheet.render(true);
}
static async removePrimaryWeapon(event) {
event.stopPropagation();
await this.document.update({ 'system.characterGuide.suggestedPrimaryWeapon': null }, { diff: false });
}
static async removeSecondaryWeapon(event) {
event.stopPropagation();
await this.document.update({ 'system.characterGuide.suggestedSecondaryWeapon': null }, { diff: false });
}
static async removeArmor(event) {
event.stopPropagation();
await this.document.update({ 'system.characterGuide.suggestedArmor': null }, { diff: false });
}
async _onDrop(event) {
const data = TextEditor.getDragEventData(event);
const item = await fromUuid(data.uuid);
if (item.type === 'subclass') {
await this.document.update({
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
});
} else if (item.type === 'feature') {
await this.document.update({
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
});
} else if (item.type === 'weapon') {
if (event.currentTarget.classList.contains('primary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedPrimaryWeapon': item.uuid
});
} else if (event.currentTarget.classList.contains('secondary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary)
await this.document.update({
'system.characterGuide.suggestedSecondaryWeapon': item.uuid
});
}
} else if (item.type === 'armor') {
if (event.currentTarget.classList.contains('armor-section')) {
if (!this.document.system.characterGuide.suggestedArmor)
await this.document.update({
'system.characterGuide.suggestedArmor': item.uuid
});
}
} else if (event.currentTarget.classList.contains('choice-a-section')) {
if (item.type === 'miscellaneous' || item.type === 'consumable') {
if (this.document.system.inventory.choiceA.length < 2)
await this.document.update({
'system.inventory.choiceA': [...this.document.system.inventory.choiceA, item.uuid]
});
}
} else if (item.type === 'miscellaneous') {
if (event.currentTarget.classList.contains('take-section')) {
if (this.document.system.inventory.take.length < 3)
await this.document.update({
'system.inventory.take': [...this.document.system.inventory.take, item.uuid]
});
} else if (event.currentTarget.classList.contains('choice-b-section')) {
if (this.document.system.inventory.choiceB.length < 2)
await this.document.update({
'system.inventory.choiceB': [...this.document.system.inventory.choiceB, item.uuid]
});
}
}
}
}