diff --git a/lang/en.json b/lang/en.json index 7f359f09..80091d1e 100755 --- a/lang/en.json +++ b/lang/en.json @@ -610,6 +610,10 @@ "title": "{name} Resource", "rerollDice": "Reroll Dice" }, + "Summon": { + "title": "Summon Tokens", + "hint": "Drag tokens from the list below into the scene to summon them." + }, "TagTeamSelect": { "title": "Tag Team Roll", "leaderTitle": "Initiating Character", diff --git a/module/applications/dialogs/summonDialog.mjs b/module/applications/dialogs/summonDialog.mjs index c5ab7a3d..9dc189fd 100644 --- a/module/applications/dialogs/summonDialog.mjs +++ b/module/applications/dialogs/summonDialog.mjs @@ -5,44 +5,46 @@ export default class DHSummonDialog extends HandlebarsApplicationMixin(Applicati super(summonData); // Initialize summons and index this.summons = summonData.summons || []; - this.index = 0; } - get_title() { - return game.i18n.localize("DAGGERHEART.DIALOGS.SUMMON.title"); - } + static PARTS = { + main: { template: 'systems/daggerheart/templates/dialogs/summon/summonDialog.hbs' } + }; + static DEFAULT_OPTIONS= { - ...super.DEFAULT_OPTIONS, - template: 'systems/daggerheart/module/applications/dialogs/summon/summonDialog.hbs', - width: 400, - height: 'auto', + tag: 'form', + window: { + title: "DAGGERHEART.APPLICATIONS.Summon.title", + resizable: false + }, + position: { + width: 400, + height: 'auto' + }, classes: ['daggerheart', 'dialog', 'summon-dialog'], - dragDrop: [{ dragSelector: '.summon-token', dropSelector: null, handler:'onDrop'}] + dragDrop: [{dragSelector: '.summon-token'}], }; async _prepareContext() { const context = await super._prepareContext(); - context.summons=this.summons; - context.index=this.index; + context.summons=await Promise.all(this.summons.map(async(entry)=>{ + const actor = await fromUuid(entry.actorUUID); + return { + ...entry, + name: actor?.name || game.i18n.localize("DAGGERHEART.GENERAL.Unknown"), + img: actor?.img || 'icons/svg/mystery-man.svg', + }; + })); return context; } - getData(options={}) { - const data = super.getData(options); - data.summons=this.summons; - data.index=this.index; - return data; - } - async prepareContext() { - const context = await super.prepareContext(); - return context; + _onDragStart(event) { + const uuid = event.currentTarget.dataset.uuid; + if(!uuid) return; + const dragData = { type: 'Actor', uuid: uuid }; + event.dataTransfer.effectAllowed = 'all'; + event.dataTransfer.setData('text/plain', JSON.stringify(dragData)); } - async onDrop(event) {//add to canvas - event.preventDefault(); - const tokenData = JSON.parse(event.dataTransfer.getData('text/plain')); - const position = { x: event.clientX, y: event.clientY }; - await canvas.scene.createEmbeddedDocuments("Token", [tokenData], { temporary: false, x: position.x, y: position.y }); - } } \ No newline at end of file diff --git a/module/data/action/summonAction.mjs b/module/data/action/summonAction.mjs index 56e0446c..1505ce2d 100644 --- a/module/data/action/summonAction.mjs +++ b/module/data/action/summonAction.mjs @@ -1,54 +1,5 @@ import DHBaseAction from './baseAction.mjs'; export default class DHSummonAction extends DHBaseAction { - static defineSchema() { - const fields = foundry.data.fields; - return { - ...super.defineSchema(), - summon: new fields.ArrayField(new fields.SchemaField({ - actorUUID: new fields.DocumentUUIDField({ type: 'Actor', required: true }), - count: new fields.NumberField({ required: true, default: 1, min: 1, integer: true }) - }), { required: false, initial: [] }) - }; - } - - get defaultValues() { - return { - summon: { actorUUID: "", count: 1 } - }; - } - - async trigger(event, ...args) { - if (!this.canSummon || !canvas.scene){ - ui.notifications.warn(game.i18n.localize("DAGGERHEART.ACTIONS.TYPES.summon.error")); - return; - } - await this._performAction(); - } - - get canSummon() { - return game.user.can('TOKEN_CREATE'); - } - - //Accessor for summon manager for performing the summon action - get summonManager() { - return game.dh.summon; //incomplete implementation - } - - //Logic to perform the summon action - incomplete implementation - async _performAction(event, ...args) { - const validSummons = this.summon.filter(entry => entry.actorUUID); - if (validSummons.length === 0) { - ui.notifications.warn("No actors configured for this Summon action."); - return; - } - // FOR NOW: Just log the data to prove the schema working or not - console.group("Summon Action Triggered"); - - for (const entry of validSummons) { - const actor = await fromUuid(entry.actorUUID); - console.log(`- Ready to summon ${entry.count}x [${actor?.name || "Unknown Actor"}]`); - } - console.groupEnd(); - } + static extraSchemas = [...super.extraSchemas, 'summon']; } diff --git a/module/data/fields/action/summonField.mjs b/module/data/fields/action/summonField.mjs index 7bcd1145..6ba1f8a2 100644 --- a/module/data/fields/action/summonField.mjs +++ b/module/data/fields/action/summonField.mjs @@ -1,61 +1,94 @@ +const fields = foundry.data.fields; import DHSummonDialog from '../../../applications/dialogs/summonDialog.mjs'; -const fields = foundry.data.fields; - -export default class DHSummonField extends fields.SchemaField { +export default class DHSummonField extends fields.ArrayField { /** * Action Workflow order */ static order = 120; constructor(options = {}, context = {}) { - const summonFields = { - summon: new fields.ArrayField(new fields.SchemaField({ - actorUUID: new fields.DocumentUUIDField({ - type: 'Actor', - required: true }), - count: new fields.NumberField({ - required: true, - default: 1, - min: 1, - integer: true }) - }), { required: false, initial: [] }) - }; + const summonFields = new fields.SchemaField({ + actorUUID: new fields.DocumentUUIDField({ + type: 'Actor', + required: true + }), + count: new fields.NumberField({ + required: true, + default: 1, + min: 1, + integer: true + }) + }); super(summonFields, options, context); } - /** - * Summon Action Workflow part. - * Must be called within Action context or similar. - * @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods. - */ - static async execute(config) { - const selected = await DHSummonDialog.configure(config, this.item); - if (!selected) return false; - return await DHSummonField.summon.call(this, selected); - } - /** - * Update Action Workflow config object. - * Must be called within Action context. - * @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods. - */ - prepareConfig(config) { - if (!canvas.scene){ + static async execute() { + if(!canvas.scene){ ui.notifications.warn(game.i18n.localize("DAGGERHEART.ACTIONS.TYPES.summon.error")); - return false; + return; + } + const validSummons = this.summon.filter(entry => entry.actorUUID); + if (validSummons.length === 0) { + console.log("No actors configured for this Summon action."); + return; + } + + for (const entry of validSummons) { + const actor = await fromUuid(entry.actorUUID); + } + + // //Open Summon Dialog + // const summonData = { summons: validSummons }; + // console.log(summonData); + // const dialog = new DHSummonDialog(summonData); + // dialog.render(true); + + // Create folder and add tokens to actor folder + const rootFolderName = game.i18n.localize("DAGGERHEART.APPLICATIONS.Summon.title"); + let rootFolder = game.folders.find(f => f.name === rootFolderName && f.type === 'Actor'); + if (!rootFolder) { + rootFolder = await Folder.create({ + name: rootFolderName, + type: 'Actor', + }); + } + const parentName = this.item.name ?? "Unkown Feature"; + const actionName = this.name ?? "Unkown Action"; + const subFolderName = `${parentName} - ${actionName}`; + + let subFolder = game.folders.find(f => f.name === subFolderName && f.type === 'Actor' && f.folder?.id === rootFolder.id); + if (!subFolder) { + subFolder = await Folder.create({ + name: subFolderName, + type: 'Actor', + folder: rootFolder.id + }); + const actorsToSummon = []; + for (const entry of validSummons) { + const sourceActor = await fromUuid(entry.actorUUID); + if (!sourceActor) { + console.warn('DHSummonField: Could not find actor for UUID', entry.actorUUID); + continue; + } + const actorData = sourceActor.toObject(); + delete actorData._id; // Remove _id to create a new Actor + actorData.folder = subFolder.id; + + for (let i = 0; i < entry.count; i++) { + const newActor = foundry.utils.deepClone(actorData); + if (entry.count > 1) { + newActor.name = `${actorData.name} ${i + 1}`; + } + actorsToSummon.push(newActor); + } + } + if (actorsToSummon.length > 0) { + await Actor.createDocuments(actorsToSummon); + ui.notifications.info(`Summoned ${actorsToSummon.length} actors successfully in folder ${subFolder.name}.`); + } + } else { + ui.notifications.info(`Summon actors already exist in folder ${subFolder.name}.`); } - return true; } - /** - * Logic to perform the summon action - incomplete implementation - */ - - get defaultValues() { - return { - summon: { actorUUID: "", count: 1 } - }; - } - get canSummon() { - return game.user.can('TOKEN_CREATE'); - } -} \ No newline at end of file +} diff --git a/templates/actionTypes/summon.hbs b/templates/actionTypes/summon.hbs index d313fb4c..276045a8 100644 --- a/templates/actionTypes/summon.hbs +++ b/templates/actionTypes/summon.hbs @@ -3,12 +3,6 @@ {{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
{{localize "DAGGERHEART.ACTIONS.Settings.summon.hint"}}
- {{!-- {{#each source as |entry index|}} -