Merged with main

This commit is contained in:
WBHarry 2025-06-28 10:21:28 +02:00
commit 45dee57335
15 changed files with 224 additions and 81 deletions

View file

@ -44,10 +44,11 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
makeDeathMove: this.makeDeathMove,
itemQuantityDecrease: (_, button) => this.setItemQuantity(button, -1),
itemQuantityIncrease: (_, button) => this.setItemQuantity(button, 1),
useAbility: this.useAbility,
toChat: this.toChat,
useAdvancementCard: this.useAdvancementCard,
useAdvancementAbility: this.useAdvancementAbility,
toggleEquipItem: this.toggleEquipItem,
toggleVault: this.toggleVault,
levelManagement: this.levelManagement,
editImage: this._onEditImage
},
@ -59,11 +60,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
submitOnChange: true,
closeOnSubmit: false
},
dragDrop: [
{ dragSelector: null, dropSelector: '.weapon-section' },
{ dragSelector: null, dropSelector: '.armor-section' },
{ dragSelector: '.item-list .item', dropSelector: null }
]
dragDrop: []
};
static PARTS = {
@ -215,6 +212,109 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
return { primary: primaryTabs, secondary: secondaryTabs };
}
async _onFirstRender(context, options) {
await super._onFirstRender(context, options);
this._createContextMenues();
}
_createContextMenues() {
const allOptions = {
useItem: {
name: 'DAGGERHEART.Sheets.PC.ContextMenu.UseItem',
icon: '<i class="fa-solid fa-burst"></i>',
callback: this.constructor.useItem.bind(this)
},
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;
},
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 = foundry.utils.fromUuidSync(el.dataset.uuid);
return item.system.equipped;
},
callback: this.constructor.toggleEquipItem.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)
},
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
});
});
}
_attachPartListeners(partId, htmlElement, options) {
super._attachPartListeners(partId, htmlElement, options);
@ -552,20 +652,14 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
(await game.packs.get('daggerheart.communities'))?.render(true);
}
static useItem(event) {
const uuid = event.target.closest('[data-item-id]').dataset.itemId,
item = this.document.items.find(i => i.uuid === uuid);
item.use(event);
static useItem(element, button) {
const id = (button ?? element).closest('a').id,
item = this.document.items.get(id);
item.use({});
}
static async viewObject(_, button) {
const object = await fromUuid(button.dataset.value);
if (!object) return;
const tab = button.dataset.tab;
if (tab && object.sheet._tabs) object.sheet._tabs[0].active = tab;
if (object.sheet.editMode) object.sheet.editMode = false;
static async viewObject(element, button) {
const object = await fromUuid((button ?? element).dataset.uuid);
object.sheet.render(true);
}
@ -628,8 +722,8 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
this.render();
}
static async deleteItem(_, button) {
const item = await fromUuid($(button).closest('[data-item-id]')[0].dataset.itemId);
static async deleteItem(element, button) {
const item = await fromUuid((button ?? element).closest('a').dataset.uuid);
await item.delete();
}
@ -663,35 +757,29 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
}
static async useAbility(_, button) {
const item = await fromUuid(button.dataset.feature);
const type = button.dataset.type;
static async toChat(element, button) {
if (button?.dataset?.type === 'experience') {
const experience = this.document.system.experiences[button.dataset.uuid];
const cls = getDocumentClass('ChatMessage');
const systemData = {
name: game.i18n.localize('DAGGERHEART.General.Experience.Single'),
description: `${experience.description} ${experience.total < 0 ? experience.total : `+${experience.total}`}`
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
const cls = getDocumentClass('ChatMessage');
const systemData = {
title:
type === 'ancestry'
? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.AncestryTitle')
: type === 'community'
? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.CommunityTitle')
: game.i18n.localize('DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle'),
origin: this.document.id,
img: item.img,
name: item.name,
description: item.system.description,
actions: []
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
cls.create(msg.toObject());
} else {
const item = await fromUuid((button ?? element).dataset.uuid);
item.toChat(this.document.id);
}
}
static async useAdvancementCard(_, button) {
@ -746,8 +834,9 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
cls.create(msg.toObject());
}
static async toggleEquipItem(_, button) {
const item = this.document.items.get(button.id);
static async toggleEquipItem(element, button) {
const id = (button ?? element).closest('a').id;
const item = this.document.items.get(id);
if (item.system.equipped) {
await item.update({ 'system.equipped': false });
return;
@ -771,6 +860,12 @@ 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);
await item.update({ 'system.inVault': !item.system.inVault });
}
async _onDragStart(_, event) {
super._onDragStart(event);
}

View file

@ -2,56 +2,55 @@ export const domains = {
arcana: {
id: 'arcana',
label: 'DAGGERHEART.Domains.arcana.label',
src: 'icons/magic/symbols/circled-gem-pink.webp',
src: 'systems/daggerheart/assets/icons/domains/arcana.svg',
description: 'DAGGERHEART.Domains.Arcana'
},
blade: {
id: 'blade',
label: 'DAGGERHEART.Domains.blade.label',
src: 'icons/weapons/swords/sword-broad-crystal-paired.webp',
src: 'systems/daggerheart/assets/icons/domains/blade.svg',
description: 'DAGGERHEART.Domains.Blade'
},
bone: {
id: 'bone',
label: 'DAGGERHEART.Domains.bone.label',
src: 'icons/skills/wounds/bone-broken-marrow-red.webp',
src: 'systems/daggerheart/assets/icons/domains/bone.svg',
description: 'DAGGERHEART.Domains.Bone'
},
codex: {
id: 'codex',
label: 'DAGGERHEART.Domains.codex.label',
src: 'icons/sundries/books/book-embossed-jewel-gold-purple.webp',
src: 'systems/daggerheart/assets/icons/domains/codex.svg',
description: 'DAGGERHEART.Domains.Codex'
},
grace: {
id: 'grace',
label: 'DAGGERHEART.Domains.grace.label',
src: 'icons/skills/movement/feet-winged-boots-glowing-yellow.webp',
src: 'systems/daggerheart/assets/icons/domains/grace.svg',
description: 'DAGGERHEART.Domains.Grace'
},
midnight: {
id: 'midnight',
label: 'DAGGERHEART.Domains.midnight.label',
src: 'icons/environment/settlement/watchtower-castle-night.webp',
background: 'systems/daggerheart/assets/backgrounds/MidnightBackground.webp',
src: 'systems/daggerheart/assets/icons/domains/midnight.svg',
description: 'DAGGERHEART.Domains.Midnight'
},
sage: {
id: 'sage',
label: 'DAGGERHEART.Domains.sage.label',
src: 'icons/sundries/misc/pipe-wooden-straight-brown.webp',
src: 'systems/daggerheart/assets/icons/domains/sage.svg',
description: 'DAGGERHEART.Domains.Sage'
},
splendor: {
id: 'splendor',
label: 'DAGGERHEART.Domains.splendor.label',
src: 'icons/magic/control/control-influence-crown-gold.webp',
src: 'systems/daggerheart/assets/icons/domains/splendor.svg',
description: 'DAGGERHEART.Domains.Splendor'
},
valor: {
id: 'valor',
label: 'DAGGERHEART.Domains.valor.label',
src: 'icons/magic/control/control-influence-rally-purple.webp',
src: 'systems/daggerheart/assets/icons/domains/valor.svg',
description: 'DAGGERHEART.Domains.Valor'
}
};

View file

@ -30,7 +30,10 @@ export default class DhCharacter extends BaseDataActor {
return {
resources: new fields.SchemaField({
hitPoints: resourceField(6),
hitPoints: new fields.SchemaField({
value: new foundry.data.fields.NumberField({ initial: 0, integer: true }),
bonus: new foundry.data.fields.NumberField({ initial: 0, integer: true })
}),
stress: resourceField(6),
hope: resourceField(6)
}),
@ -243,7 +246,7 @@ export default class DhCharacter extends BaseDataActor {
experience.total = experience.value + experience.bonus;
}
this.resources.hitPoints.maxTotal = this.resources.hitPoints.max + this.resources.hitPoints.bonus;
this.resources.hitPoints.maxTotal = (this.class.value?.system?.hitPoints ?? 0) + this.resources.hitPoints.bonus;
this.resources.stress.maxTotal = this.resources.stress.max + this.resources.stress.bonus;
this.evasion.total = (this.class?.evasion ?? 0) + this.evasion.bonus;
this.proficiency.total = this.proficiency.value + this.proficiency.bonus;

View file

@ -20,8 +20,14 @@ export default class DHClass extends BaseDataItem {
...super.defineSchema(),
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
evasion: new fields.NumberField({ initial: 0, integer: true }),
hitPoints: new fields.NumberField({
required: true,
integer: true,
min: 1,
initial: 5,
label: 'DAGGERHEART.Sheets.Class.HitPoints'
}),
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.Sheets.Class.Evasion' }),
hopeFeatures: new foundry.data.fields.ArrayField(new ActionField()),
classFeatures: new foundry.data.fields.ArrayField(new ActionField()),
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),

View file

@ -141,4 +141,32 @@ export default class DhpItem extends Item {
// Display Item Card in chat
return response;
}
async toChat(origin) {
const cls = getDocumentClass('ChatMessage');
const systemData = {
title:
this.type === 'ancestry'
? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.AncestryTitle')
: this.type === 'community'
? game.i18n.localize('DAGGERHEART.Chat.FoundationCard.CommunityTitle')
: game.i18n.localize('DAGGERHEART.Chat.FoundationCard.SubclassFeatureTitle'),
origin: origin,
img: this.img,
name: this.name,
description: this.system.description,
actions: []
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
}
}