|
let circularMaskTexture = null;
|
|
|
|
function countEffects(token) {
|
|
if (!token) {
|
|
return 0;
|
|
}
|
|
let numEffects = token.document.effects?.length || 0;
|
|
token.actor?.temporaryEffects?.forEach((actorEffect) => {
|
|
if (!actorEffect.getFlag("core", "overlay")) {
|
|
numEffects++;
|
|
}
|
|
});
|
|
return numEffects;
|
|
}
|
|
|
|
function sortIcons(e1, e2) {
|
|
if (e1.position.x === e2.position.x) {
|
|
return e1.position.y - e2.position.y;
|
|
}
|
|
return e1.position.x - e2.position.x;
|
|
}
|
|
|
|
function updateIconSize(effectIcon, size) {
|
|
effectIcon.width = size;
|
|
effectIcon.height = size;
|
|
}
|
|
|
|
function polar_to_cartesian(r, theta) {
|
|
return {
|
|
x: r * Math.cos(theta),
|
|
y: r * Math.sin(theta),
|
|
};
|
|
}
|
|
|
|
function updateIconPosition(effectIcon, i, effectIcons, token) {
|
|
const actorSize = token?.actor?.size;
|
|
let max = 20;
|
|
if (actorSize == "tiny") max = 10;
|
|
if (actorSize == "sm") max = 14;
|
|
if (actorSize == "med") max = 16;
|
|
const ratio = i / max;
|
|
// const angularOffset = i < max ? 0 : ratio / 2;
|
|
const gridSize = token?.scene?.grid?.size ?? 100;
|
|
const tokenTileFactor = token?.document?.width ?? 1;
|
|
const sizeOffset = sizeToOffset(actorSize);
|
|
const offset = sizeOffset * tokenTileFactor * gridSize;
|
|
const initialRotation = (0.5 + (1 / max) * Math.PI) * Math.PI;
|
|
const { x, y } = polar_to_cartesian(offset, (ratio + 0) * 2 * Math.PI + initialRotation);
|
|
// debugger;
|
|
effectIcon.position.x = x / 2 + (gridSize * tokenTileFactor) / 2;
|
|
effectIcon.position.y = (-1 * y) / 2 + (gridSize * tokenTileFactor) / 2;
|
|
}
|
|
|
|
// Nudge icons to be on the token ring or slightly outside
|
|
function sizeToOffset(size) {
|
|
if (size == "tiny") {
|
|
return 1.4;
|
|
} else if (size == "sm") {
|
|
return 1.0;
|
|
} else if (size == "med") {
|
|
return 1.2;
|
|
} else if (size == "lg") {
|
|
return 0.925;
|
|
} else if (size == "huge") {
|
|
return 0.925;
|
|
} else if (size == "grg") {
|
|
return 0.925;
|
|
}
|
|
return 1.0;
|
|
}
|
|
|
|
function sizeToIconScale(size) {
|
|
if (size == "tiny") {
|
|
return 1.4;
|
|
} else if (size == "sm") {
|
|
return 1.4;
|
|
} else if (size == "med") {
|
|
return 1.4;
|
|
} else if (size == "lg") {
|
|
return 1.25;
|
|
} else if (size == "huge") {
|
|
return 1.55;
|
|
} else if (size == "grg") {
|
|
return 2.2;
|
|
}
|
|
return 1.0;
|
|
}
|
|
|
|
function drawBG(effectIcon, background, gridScale) {
|
|
const r = effectIcon.width / 2;
|
|
const isDorakoUiActive = game.modules.get("pf2e-dorako-ui")?.active;
|
|
const appTheme = isDorakoUiActive ? game.settings.get("pf2e-dorako-ui", "theme.app-theme") : false;
|
|
if (appTheme && appTheme.includes("foundry2")) {
|
|
background.lineStyle((1 * gridScale) / 2, 0x302831, 1, 0);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.beginFill(0x0b0a13);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.endFill();
|
|
return;
|
|
} else if (appTheme && appTheme.includes("crb")) {
|
|
background.lineStyle((1 * gridScale) / 2, 0x956d58, 1, 1);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.lineStyle((1 * gridScale) / 2, 0xe9d7a1, 1, 0);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.beginFill(0x956d58);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.endFill();
|
|
return;
|
|
} else if (appTheme && appTheme.includes("bg3")) {
|
|
background.lineStyle((1 * gridScale) / 2, 0x9a8860, 1, 1);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.lineStyle((1 * gridScale) / 2, 0xd3b87c, 1, 0);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.beginFill(0x000000);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.endFill();
|
|
return;
|
|
}
|
|
// background.lineStyle((1 * gridScale) / 2, 0x222222, 1, 1);
|
|
// background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.lineStyle((1 * gridScale) / 2, 0x444444, 1, 0);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.beginFill(0x222222);
|
|
background.drawCircle(effectIcon.position.x, effectIcon.position.y, r + 1 * gridScale);
|
|
background.endFill();
|
|
}
|
|
|
|
function updateEffectScales(token) {
|
|
// if (token?.actor?.size == "sm") return;
|
|
const numEffects = countEffects(token);
|
|
if (numEffects > 0 && token.effects.children.length > 0) {
|
|
const background = token.effects.children[0];
|
|
if (!(background instanceof PIXI.Graphics)) return;
|
|
|
|
background.clear();
|
|
|
|
// Exclude the background and overlay
|
|
const effectIcons = token.effects.children.slice(1, 1 + numEffects);
|
|
const tokenSize = token?.actor?.size;
|
|
|
|
const gridSize = token?.scene?.grid?.size ?? 100;
|
|
// Reposition and scale them
|
|
effectIcons.forEach((effectIcon, i, effectIcons) => {
|
|
if (!(effectIcon instanceof PIXI.Sprite)) return;
|
|
|
|
effectIcon.anchor.set(0.5);
|
|
|
|
const iconScale = sizeToIconScale(tokenSize);
|
|
const gridScale = gridSize / 100;
|
|
const scaledSize = 12 * iconScale * gridScale;
|
|
updateIconSize(effectIcon, scaledSize);
|
|
updateIconPosition(effectIcon, i, effectIcons, token);
|
|
drawBG(effectIcon, background, gridScale);
|
|
});
|
|
}
|
|
}
|
|
|
|
Hooks.once("ready", () => {
|
|
const enabled = game.settings.get("pf2e-dorako-ux", "moving.adjust-token-effects-hud");
|
|
if (!enabled) return;
|
|
|
|
const origRefreshEffects = Token.prototype._refreshEffects;
|
|
Token.prototype._refreshEffects = function (...args) {
|
|
// const enabled = game.settings.get("pf2e-dorako-ux", "ux.adjust-token-effects-hud");
|
|
// if (!enabled) {
|
|
// origRefreshEffects.apply(this, args);
|
|
// return;
|
|
// }
|
|
if (this) {
|
|
origRefreshEffects.apply(this, args);
|
|
updateEffectScales(this);
|
|
}
|
|
};
|
|
|
|
const origDrawEffect = Token.prototype._drawEffect;
|
|
Token.prototype._drawEffect = async function (...args) {
|
|
// const enabled = game.settings.get("pf2e-dorako-ux", "ux.adjust-token-effects-hud");
|
|
// if (!enabled) {
|
|
// origDrawEffect.apply(this, args);
|
|
// return;
|
|
// }
|
|
if (this) {
|
|
const src = args[0];
|
|
const tint = args[1];
|
|
// debugger;
|
|
if (!src) return;
|
|
let tex = await loadTexture(src, { fallback: "icons/svg/hazard.svg" });
|
|
let icon = new PIXI.Sprite(tex);
|
|
if (src != game.settings.get("pf2e", "deathIcon")) {
|
|
// If the circular mask hasn't been created yet
|
|
// if (!circularMaskTexture) {
|
|
// // Define a new render texture that is 110x110
|
|
// circularMaskTexture = PIXI.RenderTexture.create(110, 110);
|
|
// // Define the mask sprite
|
|
// const renderedMaskSprite = new PIXI.Graphics().beginFill(0xffffff).drawCircle(55, 55, 55).endFill();
|
|
// // Blur the mask sprite
|
|
// const blurFilter = new PIXI.filters.BlurFilter(2);
|
|
// renderedMaskSprite.filters = [blurFilter];
|
|
// // Render the result of the mask sprite to the texture
|
|
// canvas.app.renderer.render(renderedMaskSprite, circularMaskTexture);
|
|
// }
|
|
|
|
const minDimension = Math.min(icon.width, icon.height);
|
|
// Use the blurred pre-made texture and create a new mask sprite for the specific icon
|
|
const myMask = new PIXI.Graphics().beginFill(0xffffff).drawCircle(55, 55, 55).endFill();
|
|
//const myMask = new PIXI.Sprite(circularMaskTexture);
|
|
//myMask.anchor.set(0.5,0.5);
|
|
myMask.width = minDimension;
|
|
myMask.height = minDimension;
|
|
myMask.x = -icon.width / 2;
|
|
myMask.y = -icon.height / 2;
|
|
|
|
icon.mask = myMask;
|
|
icon.addChild(myMask);
|
|
}
|
|
// debugger;
|
|
return this.effects.addChild(icon);
|
|
}
|
|
};
|
|
});
|