Compare commits

..

No commits in common. "f47a869af35461022a9bb7b27f3cb05f888b4bbc" and "e83202681ecddec76a6dbd33bf098fb9169f176e" have entirely different histories.

6 changed files with 138 additions and 126 deletions

View file

@ -610,10 +610,6 @@
"title": "{name} Resource", "title": "{name} Resource",
"rerollDice": "Reroll Dice" "rerollDice": "Reroll Dice"
}, },
"Summon": {
"title": "Summon Tokens",
"hint": "Drag tokens from the list below into the scene to summon them."
},
"TagTeamSelect": { "TagTeamSelect": {
"title": "Tag Team Roll", "title": "Tag Team Roll",
"leaderTitle": "Initiating Character", "leaderTitle": "Initiating Character",

View file

@ -5,46 +5,44 @@ export default class DHSummonDialog extends HandlebarsApplicationMixin(Applicati
super(summonData); super(summonData);
// Initialize summons and index // Initialize summons and index
this.summons = summonData.summons || []; this.summons = summonData.summons || [];
this.index = 0;
} }
static PARTS = { get_title() {
main: { template: 'systems/daggerheart/templates/dialogs/summon/summonDialog.hbs' } return game.i18n.localize("DAGGERHEART.DIALOGS.SUMMON.title");
}; }
static DEFAULT_OPTIONS= { static DEFAULT_OPTIONS= {
tag: 'form', ...super.DEFAULT_OPTIONS,
window: { template: 'systems/daggerheart/module/applications/dialogs/summon/summonDialog.hbs',
title: "DAGGERHEART.APPLICATIONS.Summon.title",
resizable: false
},
position: {
width: 400, width: 400,
height: 'auto' height: 'auto',
},
classes: ['daggerheart', 'dialog', 'summon-dialog'], classes: ['daggerheart', 'dialog', 'summon-dialog'],
dragDrop: [{dragSelector: '.summon-token'}], dragDrop: [{ dragSelector: '.summon-token', dropSelector: null, handler:'onDrop'}]
}; };
async _prepareContext() { async _prepareContext() {
const context = await super._prepareContext(); const context = await super._prepareContext();
context.summons=await Promise.all(this.summons.map(async(entry)=>{ context.summons=this.summons;
const actor = await fromUuid(entry.actorUUID); context.index=this.index;
return {
...entry,
name: actor?.name || game.i18n.localize("DAGGERHEART.GENERAL.Unknown"),
img: actor?.img || 'icons/svg/mystery-man.svg',
};
}));
return context; return context;
} }
_onDragStart(event) { getData(options={}) {
const uuid = event.currentTarget.dataset.uuid; const data = super.getData(options);
if(!uuid) return; data.summons=this.summons;
const dragData = { type: 'Actor', uuid: uuid }; data.index=this.index;
event.dataTransfer.effectAllowed = 'all'; return data;
event.dataTransfer.setData('text/plain', JSON.stringify(dragData)); }
async prepareContext() {
const context = await super.prepareContext();
return context;
} }
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 });
}
} }

View file

@ -1,5 +1,54 @@
import DHBaseAction from './baseAction.mjs'; import DHBaseAction from './baseAction.mjs';
export default class DHSummonAction extends DHBaseAction { export default class DHSummonAction extends DHBaseAction {
static extraSchemas = [...super.extraSchemas, 'summon']; 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();
}
} }

View file

@ -1,94 +1,61 @@
const fields = foundry.data.fields;
import DHSummonDialog from '../../../applications/dialogs/summonDialog.mjs'; import DHSummonDialog from '../../../applications/dialogs/summonDialog.mjs';
export default class DHSummonField extends fields.ArrayField { const fields = foundry.data.fields;
export default class DHSummonField extends fields.SchemaField {
/** /**
* Action Workflow order * Action Workflow order
*/ */
static order = 120; static order = 120;
constructor(options = {}, context = {}) { constructor(options = {}, context = {}) {
const summonFields = new fields.SchemaField({ const summonFields = {
summon: new fields.ArrayField(new fields.SchemaField({
actorUUID: new fields.DocumentUUIDField({ actorUUID: new fields.DocumentUUIDField({
type: 'Actor', type: 'Actor',
required: true required: true }),
}),
count: new fields.NumberField({ count: new fields.NumberField({
required: true, required: true,
default: 1, default: 1,
min: 1, min: 1,
integer: true integer: true })
}) }), { required: false, initial: [] })
}); };
super(summonFields, options, context); super(summonFields, options, context);
} }
static async execute() { /**
if(!canvas.scene){ * 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){
ui.notifications.warn(game.i18n.localize("DAGGERHEART.ACTIONS.TYPES.summon.error")); ui.notifications.warn(game.i18n.localize("DAGGERHEART.ACTIONS.TYPES.summon.error"));
return; return false;
} }
const validSummons = this.summon.filter(entry => entry.actorUUID); return true;
if (validSummons.length === 0) {
console.log("No actors configured for this Summon action.");
return;
} }
/**
* Logic to perform the summon action - incomplete implementation
*/
for (const entry of validSummons) { get defaultValues() {
const actor = await fromUuid(entry.actorUUID); return {
} summon: { actorUUID: "", count: 1 }
};
// //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}.`);
} }
get canSummon() {
return game.user.can('TOKEN_CREATE');
} }
} }

View file

@ -3,6 +3,12 @@
{{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}} {{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
</legend> </legend>
<p class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.summon.hint"}}</p> <p class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.summon.hint"}}</p>
{{!-- {{#each source as |entry index|}}
<div class="nest-inputs summon-entry">
{{formField ../fields.actorUUID label="DAGGERHEART.ACTIONS.Settings.summon.actor" value=entry.actorUUID name=(concat "summon." index ".actorUUID") localize=true classes="summon-actor-drop"}}
{{formField ../fields.count label="DAGGERHEART.ACTIONS.Settings.summon.count" value=entry.count name=(concat "summon." index ".count") localize=true}}
</div>
{{/each}} --}}
<div class="drag-area summon-actor-drop"> <div class="drag-area summon-actor-drop">
<div class="actors-list summon-entry"> <div class="actors-list summon-entry">

View file

@ -1,28 +1,24 @@
<fieldset class="one-column" data-key="summon"> <fieldset class="one-column" data-key="summon">
<legend> <legend>
{{localize "DAGGERHEART.APPLICATIONS.Summon.title"}} {{localize "DAGGERHEART.DIALOGS.Summon.title"}}
</legend> </legend>
<p class="hint">{{localize "DAGGERHEART.APPLICATIONS.Summon.hint"}}</p> <p class="hint">{{localize "DAGGERHEART.DIALOGS.Summon.hint"}}</p>
<div class="summons-list"> <div class="summons-list">
<ul class="actor-summon-item">
{{#each summons as |entry index|}} {{#each summons as |entry index|}}
<li class="summon-token" draggable="true" data-uuid="{{entry.actorUUID}}"> <ul class="actor-summon-item">
<div class="actor-summon-line"> <div class="actor-summon-line">
<img class="image" src="{{entry.img}}" /> <img class="image" src="{{entry.img}}" />
{{#if (gte entry.count 1)}} {{#if (gte entry.count 1)}}
<h4 class="h4"> <h4 class="h4">
{{entry.name}} {{entry.name}} (x{{entry.count}})
</h4> </h4>
<span>Count: {{entry.count}}</span>
{{else}} {{else}}
<h4 class="h4 disabled"> <h4 class="h4 disabled">
{{entry.name}} {{entry.name}}
</h4> </h4>
{{/if}} {{/if}}
</div> </div>
</li>
{{/each}}
</ul> </ul>
{{/each}}
</div> </div>