Feature/112 items use action datamodel (#194)

* Fix action for items

* Cost & Range #1

* remove log

* actions

* Split methods

* Roll classes

* Begin damage

* g

* Actions

* before main merge

* Fix d20RollDialog costs check

* Fix submit on close

* Add uses in action dialog

* Adversary Attack

* 166 - Damage Reduction (#180)

* Temp

* Fixed Stress Reductions

* Changed from index based to object

* Fixed stress resources management for DamageReduction

* Fix Adversary attack multiplier

* Auto add Attack action to newly created weapon

* Few fixes

* 164 - Add Hope/Fear formula

* 163 - Actor Sub Datas (#182)

* Added rules/bonuses for all classes and subclasses

* More

* Add Save

* Fix delete action button

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>
Co-authored-by: WBHarry <89362246+WBHarry@users.noreply.github.com>
This commit is contained in:
Dapoulp 2025-06-28 19:01:08 +02:00 committed by GitHub
parent 1135669d0b
commit 3593f44612
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 3707 additions and 1828 deletions

View file

@ -28,7 +28,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
toggleLoadoutView: this.toggleLoadoutView,
attackRoll: this.attackRoll,
useDomainCard: this.useDomainCard,
removeCard: this.removeDomainCard,
selectClass: this.selectClass,
selectSubclass: this.selectSubclass,
selectAncestry: this.selectAncestry,
@ -50,7 +49,8 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
toggleEquipItem: this.toggleEquipItem,
toggleVault: this.toggleVault,
levelManagement: this.levelManagement,
editImage: this._onEditImage
editImage: this._onEditImage,
triggerContextMenu: this.triggerContextMenu
},
window: {
resizable: true
@ -223,14 +223,18 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
useItem: {
name: 'DAGGERHEART.Sheets.PC.ContextMenu.UseItem',
icon: '<i class="fa-solid fa-burst"></i>',
callback: (element, event) => this.constructor.useItem.bind(this)(event, element)
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 = foundry.utils.fromUuidSync(el.dataset.uuid);
return !item.system.equipped;
const item = this.getItem(el);
return ['weapon', 'armor'].includes(item.type) && !item.system.equipped;
},
callback: this.constructor.toggleEquipItem.bind(this)
},
@ -238,11 +242,34 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Unequip',
icon: '<i class="fa-solid fa-hands"></i>',
condition: el => {
const item = foundry.utils.fromUuidSync(el.dataset.uuid);
return item.system.equipped;
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>',
@ -252,66 +279,12 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
name: 'DAGGERHEART.Sheets.PC.ContextMenu.Delete',
icon: '<i class="fa-solid fa-trash"></i>',
callback: this.constructor.deleteItem.bind(this)
},
sendToLoadout: {
name: 'DAGGERHEART.Sheets.PC.ContextMenu.ToLoadout',
icon: '<i class="fa-solid fa-arrow-up"></i>',
condition: el => {
const item = foundry.utils.fromUuidSync(el.dataset.uuid);
return 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 = foundry.utils.fromUuidSync(el.dataset.uuid);
return !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)
}
};
const getMenuOptions = type => () => {
let menuItems = ['class', 'subclass'].includes(type) ? [] : [allOptions.useItem];
switch (type) {
case 'weapon':
case 'armor':
menuItems.push(...[allOptions.equip, allOptions.unequip]);
break;
case 'domainCard':
menuItems.push(...[allOptions.sendToLoadout, allOptions.sendToVault]);
break;
}
menuItems.push(...[allOptions.sendToChat, allOptions.edit, allOptions.delete]);
return menuItems;
};
const menuConfigs = [
'armor',
'weapon',
'miscellaneous',
'consumable',
'domainCard',
'miscellaneous',
'ancestry',
'community',
'class',
'subclass'
];
menuConfigs.forEach(type => {
this._createContextMenu(getMenuOptions(type), `.${type}-context-menu`, {
eventName: 'click',
parentClassHooks: false,
fixed: true
});
this._createContextMenu(() => Object.values(allOptions), `[data-item-id]`, {
parentClassHooks: false,
fixed: true
});
}
@ -319,10 +292,16 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
super._attachPartListeners(partId, htmlElement, options);
htmlElement.querySelector('.level-value')?.addEventListener('change', this.onLevelChange.bind(this));
// To Remove when ContextMenu Handler is made
htmlElement
.querySelectorAll('[data-item-id]')
.forEach(element => element.addEventListener('contextmenu', this.editItem.bind(this)));
}
getItem(element) {
const itemId = (element.target ?? element).closest('[data-item-id]').dataset.itemId,
item = this.document.items.get(itemId);
return item;
}
static triggerContextMenu(event, button) {
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
}
static _onEditImage() {
@ -469,51 +448,12 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
const abilityLabel = game.i18n.localize(abilities[button.dataset.attribute].label);
const config = {
event: event,
title: game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', {
ability: abilityLabel
}),
title: game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', { ability: abilityLabel }),
roll: {
label: abilityLabel,
modifier: button.dataset.value
},
chatMessage: {
template: 'systems/daggerheart/templates/chat/duality-roll.hbs'
trait: button.dataset.attribute
}
};
this.document.diceRoll(config);
// Delete when new roll logic test done
/* const { roll, hope, fear, advantage, disadvantage, modifiers } = await this.document.dualityRoll(
{ title: game.i18n.localize(abilities[button.dataset.attribute].label), value: button.dataset.value },
event.shiftKey
);
const cls = getDocumentClass('ChatMessage');
const systemContent = new DHDualityRoll({
title: game.i18n.format('DAGGERHEART.Chat.DualityRoll.AbilityCheckTitle', {
ability: game.i18n.localize(abilities[button.dataset.attribute].label)
}),
origin: this.document.id,
roll: roll._formula,
modifiers: modifiers,
hope: hope,
fear: fear,
advantage: advantage,
disadvantage: disadvantage
});
await cls.create({
type: 'dualityRoll',
sound: CONFIG.sounds.dice,
system: systemContent,
user: game.user.id,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/duality-roll.hbs',
systemContent
),
rolls: [roll]
}); */
}
static async toggleMarks(_, button) {
@ -592,8 +532,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
new DhlevelUp(this.document).render(true);
}
static async useDomainCard(_, button) {
const card = this.document.items.find(x => x.uuid === button.dataset.key);
static async useDomainCard(event, button) {
const card = this.getItem(event);
if (!card) return;
const cls = getDocumentClass('ChatMessage');
const systemData = {
@ -617,13 +558,6 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
}
static async removeDomainCard(_, button) {
if (button.dataset.type === 'domainCard') {
const card = this.document.items.find(x => x.uuid === button.dataset.key);
await card.delete();
}
}
static async selectClass() {
(await game.packs.get('daggerheart.classes'))?.render(true);
}
@ -659,23 +593,22 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
static async useItem(event, button) {
const id = button.closest('a').id,
item = this.document.items.get(id);
const item = this.getItem(button);
if (!item) return;
const wasUsed = await item.use(event);
if (wasUsed && item.type === 'weapon') {
Hooks.callAll(SYSTEM.HOOKS.characterAttack, {});
}
}
static async viewObject(element, button) {
const object = await fromUuid((button ?? element).dataset.uuid);
object.sheet.render(true);
static async viewObject(event, button) {
const item = this.getItem(event);
if (!item) return;
item.sheet.render(true);
}
editItem(event) {
const uuid = event.target.closest('[data-item-id]').dataset.itemId,
item = this.document.items.find(i => i.uuid === uuid);
const item = this.getItem(event);
if (!item) return;
if (item.sheet.editMode) item.sheet.editMode = false;
@ -719,29 +652,26 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
}
async itemUpdate(event) {
const name = event.currentTarget.dataset.item;
const item = await fromUuid($(event.currentTarget).closest('[data-item-id]')[0].dataset.itemId);
await item.update({ [name]: event.currentTarget.value });
}
async onLevelChange(event) {
await this.document.updateLevel(Number(event.currentTarget.value));
this.render();
}
static async deleteItem(element, button) {
const item = await fromUuid((button ?? element).closest('a').dataset.uuid);
static async deleteItem(event, button) {
const item = this.getItem(event);
if (!item) return;
await item.delete();
}
static async setItemQuantity(button, value) {
const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
const item = this.getItem(button);
if (!item) return;
await item.update({ 'system.quantity': Math.max(item.system.quantity + value, 1) });
}
static async useFeature(_, button) {
const item = await fromUuid(button.dataset.id);
static async useFeature(event, button) {
const item = this.getItem(event);
if (!item) return;
const cls = getDocumentClass('ChatMessage');
const systemData = {
@ -765,7 +695,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
}
static async toChat(element, button) {
static async toChat(event, button) {
if (button?.dataset?.type === 'experience') {
const experience = this.document.system.experiences[button.dataset.uuid];
const cls = getDocumentClass('ChatMessage');
@ -787,7 +717,8 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
} else {
const item = await fromUuid((button ?? element).dataset.uuid);
const item = this.getItem(event);
if (!item) return;
item.toChat(this.document.id);
}
}
@ -846,9 +777,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
}
static async toggleEquipItem(element, button) {
const id = (button ?? element).closest('a').id;
const item = this.document.items.get(id);
static async toggleEquipItem(event, button) {
const item = this.getItem(event);
if (!item) return;
if (item.system.equipped) {
await item.update({ 'system.equipped': false });
return;
@ -872,9 +803,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
this.render();
}
static async toggleVault(element, button) {
const id = (button ?? element).closest('a').id;
const item = this.document.items.get(id);
static async toggleVault(event, button) {
const item = this.getItem(event);
if (!item) return;
await item.update({ 'system.inVault': !item.system.inVault });
}