diff --git a/lang/en.json b/lang/en.json index 12b452df..8be8b1f6 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2368,6 +2368,8 @@ "wrongDomain": "The card isn't from one of your class domains.", "cardTooHighLevel": "The card is too high level!", "duplicateCard": "You cannot select the same card more than once.", + "duplicateCharacter": "This actor is already registered in the party members list.", + "onlyCharactersInPartySheet": "You can drag only characters to a party sheet.", "notPrimary": "The weapon is not a primary weapon!", "notSecondary": "The weapon is not a secondary weapon!", "itemTooHighTier": "The item must be from Tier1", diff --git a/module/applications/sheets/actors/party.mjs b/module/applications/sheets/actors/party.mjs index 98dd90d7..a387695b 100644 --- a/module/applications/sheets/actors/party.mjs +++ b/module/applications/sheets/actors/party.mjs @@ -1,4 +1,5 @@ import DHBaseActorSheet from '../api/base-actor.mjs'; +import { getDocFromElement } from '../../../helpers/utils.mjs'; export default class Party extends DHBaseActorSheet { /**@inheritdoc */ @@ -10,7 +11,9 @@ export default class Party extends DHBaseActorSheet { window: { resizable: true }, - actions: {}, + actions: { + deletePartyMember: this.#deletePartyMember + }, dragDrop: [{ dragSelector: '.actors-section .inventory-item', dropSelector: null }] }; @@ -103,20 +106,39 @@ export default class Party extends DHBaseActorSheet { async _onDrop(event) { const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); - if (data.fromInternal) return; + const actor = await foundry.utils.fromUuid(data.uuid); + const currentMembers = this.document.system.partyMembers.map(x => x.uuid); - const item = await fromUuid(data.uuid); - if (item.type === 'adversary' && event.target.closest('.category-container')) { - const target = event.target.closest('.category-container'); - const path = `system.potentialAdversaries.${target.dataset.potentialAdversary}.adversaries`; - const current = foundry.utils.getProperty(this.actor, path).map(x => x.uuid); - await this.actor.update({ - [path]: [...current, item.uuid] - }); - this.render(); - } else if (item.type === 'feature' && event.target.closest('.tab.features')) { - await this.actor.createEmbeddedDocuments('Item', [item]); - this.render(); + if (foundry.utils.parseUuid(data.uuid).collection instanceof CompendiumCollection) return; + + if (actor.type !== 'character') { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.onlyCharactersInPartySheet')); } + + if (currentMembers.includes(data.uuid)) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.duplicateCharacter')); + } + + await this.document.update({ 'system.partyMembers': [...currentMembers, actor.uuid] }); + } + + static async #deletePartyMember(_event, target) { + const doc = await getDocFromElement(target.closest('.inventory-item')); + + const confirmed = await foundry.applications.api.DialogV2.confirm({ + window: { + title: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.title', { + type: game.i18n.localize('TYPES.Actor.adversary'), + name: doc.name + }) + }, + content: game.i18n.format('DAGGERHEART.APPLICATIONS.DeleteConfirmation.text', { name: doc.name }) + }); + + if (!confirmed) return; + + const currentMembers = this.document.system.partyMembers.map(x => x.uuid); + const newMemberdList = currentMembers.filter(uuid => uuid !== doc.uuid); + await this.document.update({ 'system.partyMembers': newMemberdList }); } } diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index 80bcb43e..b1639af7 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -170,4 +170,13 @@ export default class DhpAdversary extends BaseDataActor { } } } + + _getTags() { + const tags = [ + game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${this.tier}`), + `${game.i18n.localize(`DAGGERHEART.CONFIG.AdversaryType.${this.type}.label`)}`, + `${game.i18n.localize('DAGGERHEART.GENERAL.difficulty')}: ${this.difficulty}` + ]; + return tags; + } } diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index bb6a8c65..bfed5208 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -675,4 +675,9 @@ export default class DhCharacter extends BaseDataActor { this.companion.updateLevel(1); } } + + _getTags() { + const tags = [this.class.value.name, this.class.subclass.name, this.community.name, this.ancestry.name]; + return tags; + } } diff --git a/module/data/actor/party.mjs b/module/data/actor/party.mjs index 2b65122b..61edd627 100644 --- a/module/data/actor/party.mjs +++ b/module/data/actor/party.mjs @@ -7,12 +7,7 @@ export default class DhParty extends BaseDataActor { const fields = foundry.data.fields; return { ...super.defineSchema(), - partyMembers: new fields.TypedObjectField( - new fields.SchemaField({ - label: new fields.StringField(), - adversaries: new ForeignDocumentUUIDArrayField({ type: 'Actor' }) - }) - ), + partyMembers: new ForeignDocumentUUIDArrayField({ type: 'Actor' }), notes: new fields.HTMLField() }; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index c4cc2207..1c00dfec 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -772,4 +772,14 @@ export default class DhpActor extends Actor { this.#scrollTextInterval = setInterval(intervalFunc.bind(this), 600); } } + + /** + * Generate an array of localized tag. + * @returns {string[]} An array of localized tag strings. + */ + _getTags() { + const tags = []; + if (this.system._getTags) tags.push(...this.system._getTags()); + return tags; + } } diff --git a/styles/less/sheets/actors/party/party-members.less b/styles/less/sheets/actors/party/party-members.less new file mode 100644 index 00000000..8bfdf2d6 --- /dev/null +++ b/styles/less/sheets/actors/party/party-members.less @@ -0,0 +1,43 @@ +@import '../../../utils/colors.less'; +@import '../../../utils/fonts.less'; + +.application.sheet.daggerheart.actor.dh-style.party { + .tab.partyMembers { + max-height: 400px; + overflow: auto; + + .actions-section { + display: flex; + align-items: center; + justify-content: center; + padding: 10px; + gap: 20px; + background-color: light-dark(@dark-blue-10, @golden-10); + + button { + span { + font-size: 12px; + } + } + } + + .actors-list { + display: flex; + flex-direction: column; + gap: 10px; + align-items: center; + width: 100%; + } + .actors-dragger { + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + width: 100%; + height: 40px; + border: 1px dashed light-dark(@dark-blue-50, @beige-50); + border-radius: 3px; + color: light-dark(@dark-blue-50, @beige-50); + } + } +} diff --git a/styles/less/sheets/index.less b/styles/less/sheets/index.less index 9c4307f8..95359511 100644 --- a/styles/less/sheets/index.less +++ b/styles/less/sheets/index.less @@ -23,6 +23,7 @@ @import './actors/environment/sheet.less'; @import './actors/party/header.less'; +@import './actors/party/party-members.less'; @import './actors/party/sheet.less'; @import './items/beastform.less'; diff --git a/templates/sheets/actors/party/party-members.hbs b/templates/sheets/actors/party/party-members.hbs index 1594302f..74f46019 100644 --- a/templates/sheets/actors/party/party-members.hbs +++ b/templates/sheets/actors/party/party-members.hbs @@ -3,17 +3,37 @@ data-tab='{{tabs.partyMembers.id}}' data-group='{{tabs.partyMembers.group}}' > -