mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-11 19:25:21 +01:00
Finalized functionality
This commit is contained in:
parent
f47a869af3
commit
27d49d35fa
11 changed files with 296 additions and 128 deletions
|
|
@ -2,6 +2,7 @@ import { SYSTEM } from './module/config/system.mjs';
|
||||||
import * as applications from './module/applications/_module.mjs';
|
import * as applications from './module/applications/_module.mjs';
|
||||||
import * as data from './module/data/_module.mjs';
|
import * as data from './module/data/_module.mjs';
|
||||||
import * as models from './module/data/_module.mjs';
|
import * as models from './module/data/_module.mjs';
|
||||||
|
import * as canvas from './module/canvas/_module.mjs';
|
||||||
import * as documents from './module/documents/_module.mjs';
|
import * as documents from './module/documents/_module.mjs';
|
||||||
import * as dice from './module/dice/_module.mjs';
|
import * as dice from './module/dice/_module.mjs';
|
||||||
import * as fields from './module/data/fields/_module.mjs';
|
import * as fields from './module/data/fields/_module.mjs';
|
||||||
|
|
@ -19,6 +20,7 @@ import {
|
||||||
import { placeables } from './module/canvas/_module.mjs';
|
import { placeables } from './module/canvas/_module.mjs';
|
||||||
import './node_modules/@yaireo/tagify/dist/tagify.css';
|
import './node_modules/@yaireo/tagify/dist/tagify.css';
|
||||||
import TemplateManager from './module/documents/templateManager.mjs';
|
import TemplateManager from './module/documents/templateManager.mjs';
|
||||||
|
import TokenManager from './module/documents/tokenManager.mjs';
|
||||||
|
|
||||||
CONFIG.DH = SYSTEM;
|
CONFIG.DH = SYSTEM;
|
||||||
CONFIG.TextEditor.enrichers.push(...enricherConfig);
|
CONFIG.TextEditor.enrichers.push(...enricherConfig);
|
||||||
|
|
@ -51,6 +53,8 @@ CONFIG.ChatMessage.template = 'systems/daggerheart/templates/ui/chat/chat-messag
|
||||||
|
|
||||||
CONFIG.Canvas.rulerClass = placeables.DhRuler;
|
CONFIG.Canvas.rulerClass = placeables.DhRuler;
|
||||||
CONFIG.Canvas.layers.templates.layerClass = placeables.DhTemplateLayer;
|
CONFIG.Canvas.layers.templates.layerClass = placeables.DhTemplateLayer;
|
||||||
|
CONFIG.Canvas.layers.tokens.layerClass = canvas.DhTokenLayer;
|
||||||
|
|
||||||
CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate;
|
CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate;
|
||||||
|
|
||||||
CONFIG.Scene.documentClass = documents.DhScene;
|
CONFIG.Scene.documentClass = documents.DhScene;
|
||||||
|
|
@ -73,6 +77,7 @@ CONFIG.ui.countdowns = applications.ui.DhCountdowns;
|
||||||
CONFIG.ux.ContextMenu = applications.ux.DHContextMenu;
|
CONFIG.ux.ContextMenu = applications.ux.DHContextMenu;
|
||||||
CONFIG.ux.TooltipManager = documents.DhTooltipManager;
|
CONFIG.ux.TooltipManager = documents.DhTooltipManager;
|
||||||
CONFIG.ux.TemplateManager = new TemplateManager();
|
CONFIG.ux.TemplateManager = new TemplateManager();
|
||||||
|
CONFIG.ux.TokenManager = new TokenManager();
|
||||||
|
|
||||||
Hooks.once('init', () => {
|
Hooks.once('init', () => {
|
||||||
game.system.api = {
|
game.system.api = {
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,12 @@
|
||||||
"cost": {
|
"cost": {
|
||||||
"stepTooltip": "+{step} per step"
|
"stepTooltip": "+{step} per step"
|
||||||
},
|
},
|
||||||
"summon":{
|
"summon": {
|
||||||
"addSummonEntry": "Add Summon Entry",
|
"addSummonEntry": "Add Summon Entry",
|
||||||
"actorUUID": "Actor to Summon",
|
"actorUUID": "Actor to Summon",
|
||||||
"actor": "Actor",
|
"actor": "Actor",
|
||||||
"count": "Count",
|
"count": "Count",
|
||||||
|
"dropSummonsHere": "Drop Summons Here",
|
||||||
"hint": "Add Actor(s) and the quantity to summon under this action."
|
"hint": "Add Actor(s) and the quantity to summon under this action."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
|
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
tag: 'form',
|
tag: 'form',
|
||||||
classes: ['daggerheart', 'dh-style', 'dialog', 'max-800'],
|
classes: ['daggerheart', 'dh-style', 'dialog', 'action-config', 'max-800'],
|
||||||
window: {
|
window: {
|
||||||
icon: 'fa-solid fa-wrench',
|
icon: 'fa-solid fa-wrench',
|
||||||
resizable: false
|
resizable: false
|
||||||
|
|
@ -37,7 +37,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
submitOnChange: true,
|
submitOnChange: true,
|
||||||
closeOnSubmit: false
|
closeOnSubmit: false
|
||||||
},
|
},
|
||||||
dragDrop: [{ dragSelector: null, dropSelector: '.summon-entry', handlers: ['_onDrop'] }]
|
dragDrop: [{ dragSelector: null, dropSelector: '#summon-drop-zone', handlers: ['_onDrop'] }]
|
||||||
};
|
};
|
||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
|
|
@ -87,7 +87,7 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects','summon'];
|
static CLEAN_ARRAYS = ['damage.parts', 'cost', 'effects', 'summon'];
|
||||||
|
|
||||||
_getTabs(tabs) {
|
_getTabs(tabs) {
|
||||||
for (const v of Object.values(tabs)) {
|
for (const v of Object.values(tabs)) {
|
||||||
|
|
@ -98,23 +98,24 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_attachPartListeners(partId, htmlElement, options) {
|
||||||
|
super._attachPartListeners(partId, htmlElement, options);
|
||||||
|
|
||||||
|
htmlElement.querySelectorAll('.summon-count-wrapper input').forEach(element => {
|
||||||
|
element.addEventListener('change', this.updateSummonCount.bind(this));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async _prepareContext(_options) {
|
async _prepareContext(_options) {
|
||||||
const context = await super._prepareContext(_options, 'action');
|
const context = await super._prepareContext(_options, 'action');
|
||||||
context.source = this.action.toObject(true);
|
context.source = this.action.toObject(true);
|
||||||
// Resolving summon entries so actions can read entry.name / entry.img / entry.uuid
|
// Resolving summon entries so actions can read entry.name / entry.img / entry.uuid
|
||||||
if (Array.isArray(context.source.summon)) {
|
context.summons = [];
|
||||||
context.source.summon = await Promise.all(context.source.summon.map(async entry => {
|
for (const summon of context.source.summon) {
|
||||||
if (!entry) return entry;
|
const actor = await foundry.utils.fromUuid(summon.actorUUID);
|
||||||
const uuid = entry.actorUUID ?? entry.uuid;
|
context.summons.push({ actor, count: summon.count });
|
||||||
entry.uuid = uuid;
|
|
||||||
try {
|
|
||||||
const doc = await foundry.utils.fromUuid(uuid);
|
|
||||||
entry.name = entry.name ?? doc?.name;
|
|
||||||
entry.img = entry.img ?? (doc?.img ?? doc?.prototypeToken?.texture?.src ?? null);
|
|
||||||
} catch (_) {}
|
|
||||||
return entry;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.openSection = this.openSection;
|
context.openSection = this.openSection;
|
||||||
context.tabs = this._getTabs(this.constructor.TABS);
|
context.tabs = this._getTabs(this.constructor.TABS);
|
||||||
context.config = CONFIG.DH;
|
context.config = CONFIG.DH;
|
||||||
|
|
@ -197,8 +198,9 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
}
|
}
|
||||||
|
|
||||||
static async updateForm(event, _, formData) {
|
static async updateForm(event, _, formData) {
|
||||||
const submitData = this._prepareSubmitData(event, formData),
|
const submitData = this._prepareSubmitData(event, formData);
|
||||||
data = foundry.utils.mergeObject(this.action.toObject(), submitData);
|
|
||||||
|
const data = foundry.utils.mergeObject(this.action.toObject(), submitData);
|
||||||
this.action = await this.action.update(data);
|
this.action = await this.action.update(data);
|
||||||
|
|
||||||
this.sheetUpdate?.(this.action);
|
this.sheetUpdate?.(this.action);
|
||||||
|
|
@ -234,13 +236,13 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
static async editDoc(event, button) {
|
static async editDoc(event, button) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const uuid = button?.dataset.itemUuid ?? button?.dataset.uuid; // Obtain uuid from dataset
|
const uuid = button?.dataset.itemUuid ?? button?.dataset.uuid; // Obtain uuid from dataset
|
||||||
if (!uuid) return;
|
if (!uuid) return;
|
||||||
//Try catching errors
|
//Try catching errors
|
||||||
try {
|
try {
|
||||||
const doc = await foundry.utils.fromUuid(uuid);
|
const doc = await foundry.utils.fromUuid(uuid);
|
||||||
if (doc?.sheet) return doc.sheet.render({ force: true });
|
if (doc?.sheet) return doc.sheet.render({ force: true });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn("editDoc action failed for", uuid, err);
|
console.warn('editDoc action failed for', uuid, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,6 +263,14 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateSummonCount(event) {
|
||||||
|
const wrapper = event.target.closest('.summon-count-wrapper');
|
||||||
|
const index = wrapper.dataset.index;
|
||||||
|
const data = this.action.toObject();
|
||||||
|
data.summon[index].count = Number.parseInt(event.target.value);
|
||||||
|
this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(data) });
|
||||||
|
}
|
||||||
|
|
||||||
/** Specific implementation in extending classes **/
|
/** Specific implementation in extending classes **/
|
||||||
static async addEffect(_event) {}
|
static async addEffect(_event) {}
|
||||||
static removeEffect(_event, _button) {}
|
static removeEffect(_event, _button) {}
|
||||||
|
|
@ -271,28 +281,28 @@ export default class DHActionBaseConfig extends DaggerheartSheet(ApplicationV2)
|
||||||
await super.close(options);
|
await super.close(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation for dragdrop for summon actor selection **/
|
|
||||||
async _onDrop(event) {
|
async _onDrop(event) {
|
||||||
const data = foundry.applications.ux.TextEditor.getDragEventData(event);
|
const data = foundry.applications.ux.TextEditor.getDragEventData(event);
|
||||||
const item=await foundry.utils.fromUuid(data.uuid);
|
const item = await foundry.utils.fromUuid(data.uuid);
|
||||||
if (!(item instanceof game.system.api.documents.DhpActor)) {
|
if (!(item instanceof game.system.api.documents.DhpActor)) {
|
||||||
ui.notifications.warn(game.i18n.localize("DAGGERHEART.ACTIONS.TYPES.summon.invalidDrop"));
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.ACTIONS.TYPES.summon.invalidDrop'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//Add to summon array
|
|
||||||
const actionData = this.action.toObject(); // Get current action data
|
const actionData = this.action.toObject();
|
||||||
//checking to see if actor is already in summon list add 1 to count instead of adding new entry
|
|
||||||
let countvalue = 1;
|
let countvalue = 1;
|
||||||
for (const entry of actionData.summon) {
|
for (const entry of actionData.summon) {
|
||||||
if (entry.actorUUID === data.uuid) {
|
if (entry.actorUUID === data.uuid) {
|
||||||
entry.count += 1;
|
entry.count += 1;
|
||||||
countvalue = entry.count;
|
countvalue = entry.count;
|
||||||
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) });
|
await this.constructor.updateForm.bind(this)(null, null, {
|
||||||
|
object: foundry.utils.flattenObject(actionData)
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
actionData.summon.push({ actorUUID: data.uuid, count: countvalue });// Add new summon entry
|
|
||||||
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) }); // Update the form with new data
|
actionData.summon.push({ actorUUID: data.uuid, count: countvalue });
|
||||||
|
await this.constructor.updateForm.bind(this)(null, null, { object: foundry.utils.flattenObject(actionData) });
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
export * as placeables from './placeables/_module.mjs';
|
export * as placeables from './placeables/_module.mjs';
|
||||||
|
export { default as DhTokenLayer } from './tokens.mjs';
|
||||||
|
|
|
||||||
16
module/canvas/tokens.mjs
Normal file
16
module/canvas/tokens.mjs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
export default class DhTokenLayer extends foundry.canvas.layers.TokenLayer {
|
||||||
|
async _createPreview(createData, options) {
|
||||||
|
if (options.actor) {
|
||||||
|
const tokenSizes = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).tokenSizes;
|
||||||
|
if (options.actor?.system.metadata.usesSize) {
|
||||||
|
const tokenSize = tokenSizes[options.actor.system.size];
|
||||||
|
if (tokenSize && options.actor.system.size !== CONFIG.DH.ACTOR.tokenSize.custom.id) {
|
||||||
|
createData.width = tokenSize;
|
||||||
|
createData.height = tokenSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return super._createPreview(createData, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
const fields = foundry.data.fields;
|
const fields = foundry.data.fields;
|
||||||
import DHSummonDialog from '../../../applications/dialogs/summonDialog.mjs';
|
|
||||||
|
|
||||||
export default class DHSummonField extends fields.ArrayField {
|
export default class DHSummonField extends fields.ArrayField {
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,71 +23,47 @@ export default class DHSummonField extends fields.ArrayField {
|
||||||
}
|
}
|
||||||
|
|
||||||
static async execute() {
|
static async execute() {
|
||||||
if(!canvas.scene){
|
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;
|
||||||
}
|
}
|
||||||
const validSummons = this.summon.filter(entry => entry.actorUUID);
|
|
||||||
if (validSummons.length === 0) {
|
if (this.summon.length === 0) {
|
||||||
console.log("No actors configured for this Summon action.");
|
ui.notifications.warn('No actors configured for this Summon action.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const entry of validSummons) {
|
|
||||||
const actor = await fromUuid(entry.actorUUID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// //Open Summon Dialog
|
const summonData = [];
|
||||||
// const summonData = { summons: validSummons };
|
for (const summon of this.summon) {
|
||||||
// console.log(summonData);
|
/* Possibly check for any available instances in the world with prepared images */
|
||||||
// const dialog = new DHSummonDialog(summonData);
|
let actor = await foundry.utils.fromUuid(summon.actorUUID);
|
||||||
// dialog.render(true);
|
|
||||||
|
|
||||||
// Create folder and add tokens to actor folder
|
/* Check for any available instances of the actor present in the world if we're missing artwork in the compendium */
|
||||||
const rootFolderName = game.i18n.localize("DAGGERHEART.APPLICATIONS.Summon.title");
|
const dataType = game.system.api.data.actors[`Dh${actor.type.capitalize()}`];
|
||||||
let rootFolder = game.folders.find(f => f.name === rootFolderName && f.type === 'Actor');
|
if (actor.inCompendium && dataType && actor.img === dataType.DEFAULT_ICON) {
|
||||||
if (!rootFolder) {
|
const worldActorCopy = game.actors.find(x => x.name === actor.name);
|
||||||
rootFolder = await Folder.create({
|
actor = worldActorCopy ?? actor;
|
||||||
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);
|
summonData.push({ actor, count: summon.count });
|
||||||
ui.notifications.info(`Summoned ${actorsToSummon.length} actors successfully in folder ${subFolder.name}.`);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ui.notifications.info(`Summon actors already exist in folder ${subFolder.name}.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSummon = async summonIndex => {
|
||||||
|
const summon = summonData[summonIndex];
|
||||||
|
const result = await CONFIG.ux.TokenManager.createPreviewAsync(summon.actor, {
|
||||||
|
name: `${summon.actor.prototypeToken.name}${summon.count > 1 ? ` (${summon.count}x)` : ''}`
|
||||||
|
});
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
|
summon.count--;
|
||||||
|
if (summon.count === 0) {
|
||||||
|
summonIndex++;
|
||||||
|
if (summonIndex === summonData.length) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSummon(summonIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
handleSummon(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,4 @@ export { default as DhScene } from './scene.mjs';
|
||||||
export { default as DhToken } from './token.mjs';
|
export { default as DhToken } from './token.mjs';
|
||||||
export { default as DhTooltipManager } from './tooltipManager.mjs';
|
export { default as DhTooltipManager } from './tooltipManager.mjs';
|
||||||
export { default as DhTemplateManager } from './templateManager.mjs';
|
export { default as DhTemplateManager } from './templateManager.mjs';
|
||||||
|
export { default as DhTokenManager } from './tokenManager.mjs';
|
||||||
|
|
|
||||||
103
module/documents/tokenManager.mjs
Normal file
103
module/documents/tokenManager.mjs
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
/**
|
||||||
|
* A singleton class that handles preview tokens.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class DhTokenManager {
|
||||||
|
#activePreview;
|
||||||
|
#actor;
|
||||||
|
#resolve;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a template preview, deactivating any existing ones.
|
||||||
|
* @param {object} data
|
||||||
|
*/
|
||||||
|
async createPreview(actor, tokenData) {
|
||||||
|
this.#actor = actor;
|
||||||
|
const token = await canvas.tokens._createPreview(
|
||||||
|
{
|
||||||
|
...actor.prototypeToken,
|
||||||
|
displayName: 50,
|
||||||
|
...tokenData
|
||||||
|
},
|
||||||
|
{ renderSheet: false, actor }
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#activePreview = {
|
||||||
|
document: token.document,
|
||||||
|
object: token,
|
||||||
|
origin: { x: token.document.x, y: token.document.y }
|
||||||
|
};
|
||||||
|
|
||||||
|
this.#activePreview.events = {
|
||||||
|
contextmenu: this.#cancelTemplate.bind(this),
|
||||||
|
mousedown: this.#confirmTemplate.bind(this),
|
||||||
|
mousemove: this.#onDragMouseMove.bind(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
canvas.stage.on('mousemove', this.#activePreview.events.mousemove);
|
||||||
|
canvas.stage.on('mousedown', this.#activePreview.events.mousedown);
|
||||||
|
canvas.app.view.addEventListener('contextmenu', this.#activePreview.events.contextmenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
async createPreviewAsync(actor, tokenData) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.#resolve = resolve;
|
||||||
|
this.createPreview(actor, tokenData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the movement of the token preview on mousedrag.
|
||||||
|
* @param {mousemove Event} event
|
||||||
|
*/
|
||||||
|
#onDragMouseMove(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const { moveTime, object } = this.#activePreview;
|
||||||
|
const update = {};
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - (moveTime || 0) <= 16) return;
|
||||||
|
this.#activePreview.moveTime = now;
|
||||||
|
|
||||||
|
let cursor = event.getLocalPosition(canvas.templates);
|
||||||
|
|
||||||
|
Object.assign(update, canvas.grid.getTopLeftPoint(cursor));
|
||||||
|
|
||||||
|
object.document.updateSource(update);
|
||||||
|
object.renderFlags.set({ refresh: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the preview token on right-click.
|
||||||
|
* @param {contextmenu Event} event
|
||||||
|
*/
|
||||||
|
#cancelTemplate(_event, resolved) {
|
||||||
|
const { mousemove, mousedown, contextmenu } = this.#activePreview.events;
|
||||||
|
this.#activePreview.object.destroy();
|
||||||
|
|
||||||
|
canvas.stage.off('mousemove', mousemove);
|
||||||
|
canvas.stage.off('mousedown', mousedown);
|
||||||
|
canvas.app.view.removeEventListener('contextmenu', contextmenu);
|
||||||
|
if (this.#resolve && !resolved) this.#resolve(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a real Actor and token at the preview location and cancels the preview.
|
||||||
|
* @param {click Event} event
|
||||||
|
*/
|
||||||
|
async #confirmTemplate(event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.#cancelTemplate(event, true);
|
||||||
|
|
||||||
|
const actor = this.#actor.inCompendium
|
||||||
|
? await game.system.api.documents.DhpActor.create(this.#actor.toObject())
|
||||||
|
: this.#actor;
|
||||||
|
const tokenData = await actor.getTokenDocument();
|
||||||
|
const token = await canvas.scene.createEmbeddedDocuments('Token', [
|
||||||
|
{ ...tokenData, x: this.#activePreview.document.x, y: this.#activePreview.document.y }
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.#activePreview = undefined;
|
||||||
|
if (this.#resolve) this.#resolve(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
styles/less/sheets/actions/actions.less
Normal file
50
styles/less/sheets/actions/actions.less
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
.application.daggerheart.dh-style.action-config {
|
||||||
|
.actor-summon-items {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
.actor-summon-line {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
|
||||||
|
.actor-summon-name {
|
||||||
|
flex: 2;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-summon-controls {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.summon-dragger {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 40px;
|
||||||
|
margin-top: 10px;
|
||||||
|
border: 1px dashed light-dark(@dark-blue-50, @beige-50);
|
||||||
|
border-radius: 3px;
|
||||||
|
color: light-dark(@dark-blue-50, @beige-50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -37,3 +37,5 @@
|
||||||
@import './items/feature.less';
|
@import './items/feature.less';
|
||||||
@import './items/heritage.less';
|
@import './items/heritage.less';
|
||||||
@import './items/item-sheet-shared.less';
|
@import './items/item-sheet-shared.less';
|
||||||
|
|
||||||
|
@import './actions/actions.less';
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,50 @@
|
||||||
<fieldset class="one-column" data-key="summon">
|
<fieldset class="one-column" id="summon-drop-zone" data-key="summon">
|
||||||
<legend>
|
<legend>
|
||||||
{{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
|
{{localize "DAGGERHEART.ACTIONS.TYPES.summon.name"}}
|
||||||
</legend>
|
</legend>
|
||||||
<p class="hint">{{localize "DAGGERHEART.ACTIONS.Settings.summon.hint"}}</p>
|
|
||||||
|
|
||||||
<div class="drag-area summon-actor-drop">
|
<ul class="actor-summon-items">
|
||||||
<div class="actors-list summon-entry">
|
{{#each @root.summons as |summon index|}}
|
||||||
|
<li class="actor-summon-line">
|
||||||
{{#each source as |entry index|}}
|
<div class="actor-summon-name">
|
||||||
<ul class="actor-summon-item">
|
<img class="image" src="{{summon.actor.img}}" />
|
||||||
<div class="actor-summon-line">
|
<h4 class="h4">
|
||||||
<img class="image" src="{{entry.img}}" />
|
{{summon.actor.name}}
|
||||||
<h4 class="h4">
|
</h4>
|
||||||
{{entry.name}}
|
</div>
|
||||||
</h4>
|
|
||||||
{{formField ../fields.count label="DAGGERHEART.ACTIONS.Settings.summon.count" value=entry.count name=(concat "summon." index ".count") localize=true}}
|
<div class="actor-summon-controls">
|
||||||
<div class="controls">
|
<div class="form-group summon-count-wrapper" data-index="{{index}}">
|
||||||
<a
|
<div class="form-fields">
|
||||||
class='effect-control'
|
<input type="text" data-dtype="Number" value="{{summon.count}}" />
|
||||||
data-action='editDoc'
|
|
||||||
data-item-uuid="{{entry.uuid}}"
|
|
||||||
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
|
||||||
>
|
|
||||||
<i class="fa-solid fa-globe"></i>
|
|
||||||
</a>
|
|
||||||
<a
|
|
||||||
class='effect-control'
|
|
||||||
data-action='removeElement'
|
|
||||||
data-target="summon"
|
|
||||||
data-uuid="{{entry.uuid}}"
|
|
||||||
data-index="{{index}}"
|
|
||||||
data-tooltip='{{localize "CONTROLS.CommonDelete"}}'
|
|
||||||
>
|
|
||||||
<i class='fas fa-trash'></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
|
||||||
{{/each}}
|
<div class="controls">
|
||||||
{{#unless source.length}}
|
<a
|
||||||
<span>{{localize "DAGGERHEART.GENERAL.dropActorsHere"}}</span>
|
class='effect-control'
|
||||||
{{/unless}}
|
data-action='editDoc'
|
||||||
</div>
|
data-item-uuid="{{summon.actor.uuid}}"
|
||||||
</div>
|
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
|
||||||
|
>
|
||||||
|
<i class="fa-solid fa-globe"></i>
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
class='effect-control'
|
||||||
|
data-action='removeElement'
|
||||||
|
data-target="summon"
|
||||||
|
data-uuid="{{summon.actor.uuid}}"
|
||||||
|
data-index="{{index}}"
|
||||||
|
data-tooltip='{{localize "CONTROLS.CommonDelete"}}'
|
||||||
|
>
|
||||||
|
<i class='fas fa-trash'></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
<div class="summon-dragger">
|
||||||
|
<span>{{localize "DAGGERHEART.ACTIONS.Settings.summon.dropSummonsHere"}}</span>
|
||||||
|
</div>
|
||||||
|
</ul>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue