export function getBestTokenDocumentForActor(actor) { if (!actor) return null; const syntheticToken = getSyntheticTokenDocument(actor); if (syntheticToken) return syntheticToken; const controlled = canvas?.tokens?.controlled?.find(token => token.actor?.uuid === actor.uuid || token.actor?.id === actor.id); if (controlled) return controlled.document; const combatant = game.combat?.combatants?.find(c => c.actor?.uuid === actor.uuid || c.actor?.id === actor.id); if (combatant?.token) return combatant.token; const activeTokens = actor.getActiveTokens?.(true, true) ?? []; if (activeTokens.length === 1) return activeTokens[0].document; return activeTokens[0]?.document ?? null; } function getSyntheticTokenDocument(actor) { const tokenDocument = actor.token ?? actor.prototypeToken ?? null; if (tokenDocument?.documentName === "Token") return tokenDocument; return null; } export function getPrimaryOwner(actor) { if (!actor) return null; return game.users.find(user => user.active && !user.isGM && actor.testUserPermission(user, "OWNER")) ?? null; } export function isTokenSpaceOccupied(token, targetPosition) { const targetRect = new PIXI.Rectangle(targetPosition.x, targetPosition.y, token.w, token.h); return canvas.tokens.placeables.some(other => { if (other.id === token.id) return false; if (other.document.hidden) return false; const otherRect = new PIXI.Rectangle(other.document.x, other.document.y, other.w, other.h); return rectanglesOverlap(targetRect, otherRect); }); } function rectanglesOverlap(a, b) { return a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y; }