foundry-sw5e/module/pixi/ability-template.js
supervj b56a074697 DND5e Core 1.3.5
DND5e Core 1.3.5 modded to SW5e System

Combining with DND5e Core 1.3.2 to see one big commit since last core update

DND5e Core 1.3.2 modded to SW5e System
2021-06-22 22:01:19 -04:00

133 lines
4.4 KiB
JavaScript

import { SW5E } from "../config.js";
/**
* A helper class for building MeasuredTemplates for 5e powers and abilities
* @extends {MeasuredTemplate}
*/
export default class AbilityTemplate extends MeasuredTemplate {
/**
* A factory method to create an AbilityTemplate instance using provided data from an Item5e instance
* @param {Item5e} item The Item object for which to construct the template
* @return {AbilityTemplate|null} The template object, or null if the item does not produce a template
*/
static fromItem(item) {
const target = getProperty(item.data, "data.target") || {};
const templateShape = SW5E.areaTargetTypes[target.type];
if ( !templateShape ) return null;
// Prepare template data
const templateData = {
t: templateShape,
user: game.user._id,
distance: target.value,
direction: 0,
x: 0,
y: 0,
fillColor: game.user.color
};
// Additional type-specific data
switch ( templateShape ) {
case "cone":
templateData.angle = CONFIG.MeasuredTemplate.defaults.angle;
break;
case "rect": // 5e rectangular AoEs are always cubes
templateData.distance = Math.hypot(target.value, target.value);
templateData.width = target.value;
templateData.direction = 45;
break;
case "ray": // 5e rays are most commonly 1 square (5 ft) in width
templateData.width = target.width ?? canvas.dimensions.distance;
break;
default:
break;
}
// Return the template constructed from the item data
const cls = CONFIG.MeasuredTemplate.documentClass;
const template = new cls(templateData, {parent: canvas.scene});
const object = new this(template);
object.item = item;
object.actorSheet = item.actor?.sheet || null;
return object;
}
/* -------------------------------------------- */
/**
* Creates a preview of the power template
*/
drawPreview() {
const initialLayer = canvas.activeLayer;
// Draw the template and switch to the template layer
this.draw();
this.layer.activate();
this.layer.preview.addChild(this);
// Hide the sheet that originated the preview
if ( this.actorSheet ) this.actorSheet.minimize();
// Activate interactivity
this.activatePreviewListeners(initialLayer);
}
/* -------------------------------------------- */
/**
* Activate listeners for the template preview
* @param {CanvasLayer} initialLayer The initially active CanvasLayer to re-activate after the workflow is complete
*/
activatePreviewListeners(initialLayer) {
const handlers = {};
let moveTime = 0;
// Update placement (mouse-move)
handlers.mm = event => {
event.stopPropagation();
let now = Date.now(); // Apply a 20ms throttle
if ( now - moveTime <= 20 ) return;
const center = event.data.getLocalPosition(this.layer);
const snapped = canvas.grid.getSnappedPosition(center.x, center.y, 2);
this.data.update({x: snapped.x, y: snapped.y});
this.refresh();
moveTime = now;
};
// Cancel the workflow (right-click)
handlers.rc = event => {
this.layer.preview.removeChildren();
canvas.stage.off("mousemove", handlers.mm);
canvas.stage.off("mousedown", handlers.lc);
canvas.app.view.oncontextmenu = null;
canvas.app.view.onwheel = null;
initialLayer.activate();
this.actorSheet.maximize();
};
// Confirm the workflow (left-click)
handlers.lc = event => {
handlers.rc(event);
const destination = canvas.grid.getSnappedPosition(this.data.x, this.data.y, 2);
this.data.update(destination);
canvas.scene.createEmbeddedDocuments("MeasuredTemplate", [this.data]);
};
// Rotate the template by 3 degree increments (mouse-wheel)
handlers.mw = event => {
if ( event.ctrlKey ) event.preventDefault(); // Avoid zooming the browser window
event.stopPropagation();
let delta = canvas.grid.type > CONST.GRID_TYPES.SQUARE ? 30 : 15;
let snap = event.shiftKey ? delta : 5;
this.data.update({direction: this.data.direction + (snap * Math.sign(event.deltaY))});
this.refresh();
};
// Activate listeners
canvas.stage.on("mousemove", handlers.mm);
canvas.stage.on("mousedown", handlers.lc);
canvas.app.view.oncontextmenu = handlers.rc;
canvas.app.view.onwheel = handlers.mw;
}
}