162 lines
5.3 KiB
JavaScript
162 lines
5.3 KiB
JavaScript
import { MODULE_ID, SETTINGS } from "../constants.js";
|
|
|
|
export async function assignReactionToSelectedTokens(reactionId) {
|
|
if (!game.user.isGM) {
|
|
ui.notifications.warn(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.GmOnly"));
|
|
return;
|
|
}
|
|
|
|
if (!reactionId) {
|
|
ui.notifications.warn(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.NoReactionSelected"));
|
|
return;
|
|
}
|
|
|
|
const selectedTokens = canvas?.tokens?.controlled ?? [];
|
|
if (!selectedTokens.length) {
|
|
ui.notifications.warn(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.NoTokensSelected"));
|
|
return;
|
|
}
|
|
|
|
const reactions = game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? [];
|
|
const reaction = reactions.find(r => r.id === reactionId);
|
|
if (!reaction) {
|
|
ui.notifications.error(game.i18n.localize("CONFIGURABLE_REACTIONS.Errors.ReactionNotFound"));
|
|
return;
|
|
}
|
|
|
|
const assignments = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.ASSIGNMENTS) ?? []);
|
|
let assignedCount = 0;
|
|
let skippedCount = 0;
|
|
|
|
for (const token of selectedTokens) {
|
|
const tokenDocument = token.document;
|
|
const actor = token.actor;
|
|
|
|
if (!actor) {
|
|
skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
const assignment = buildAssignmentForToken(tokenDocument, actor, reactionId);
|
|
const alreadyAssigned = assignments.some(existing =>
|
|
existing.reactionId === assignment.reactionId &&
|
|
existing.mode === assignment.mode &&
|
|
existing.actorUuid === assignment.actorUuid &&
|
|
existing.tokenUuid === assignment.tokenUuid
|
|
);
|
|
|
|
if (alreadyAssigned) {
|
|
skippedCount++;
|
|
continue;
|
|
}
|
|
|
|
assignments.push(assignment);
|
|
|
|
if (assignment.mode === "actor") {
|
|
await addReactionFlag(actor, reactionId);
|
|
await ensureManagedReactionEffectOnActor(actor, reaction);
|
|
} else {
|
|
await addReactionFlag(tokenDocument, reactionId);
|
|
}
|
|
|
|
assignedCount++;
|
|
}
|
|
|
|
await game.settings.set(MODULE_ID, SETTINGS.ASSIGNMENTS, assignments);
|
|
ui.notifications.info(game.i18n.format("CONFIGURABLE_REACTIONS.Assignments.AssignedResult", { assigned: assignedCount, skipped: skippedCount }));
|
|
}
|
|
|
|
export async function removeAssignment(assignmentId) {
|
|
if (!game.user.isGM) return;
|
|
|
|
const assignments = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.ASSIGNMENTS) ?? []);
|
|
const assignment = assignments.find(a => a.id === assignmentId);
|
|
if (!assignment) return;
|
|
|
|
await game.settings.set(MODULE_ID, SETTINGS.ASSIGNMENTS, assignments.filter(a => a.id !== assignmentId));
|
|
|
|
if (assignment.mode === "actor" && assignment.actorUuid) {
|
|
const actor = await fromUuid(assignment.actorUuid);
|
|
if (actor) await removeReactionFromDocument(actor, assignment.reactionId, true);
|
|
}
|
|
|
|
if (assignment.mode === "token" && assignment.tokenUuid) {
|
|
const tokenDocument = await fromUuid(assignment.tokenUuid);
|
|
if (tokenDocument) await removeReactionFromDocument(tokenDocument, assignment.reactionId, false);
|
|
}
|
|
}
|
|
|
|
function buildAssignmentForToken(tokenDocument, actor, reactionId) {
|
|
if (tokenDocument.actorLink === true) {
|
|
return {
|
|
id: foundry.utils.randomID(),
|
|
reactionId,
|
|
mode: "actor",
|
|
actorUuid: actor.uuid,
|
|
tokenUuid: null,
|
|
sceneUuid: null,
|
|
name: actor.name
|
|
};
|
|
}
|
|
|
|
return {
|
|
id: foundry.utils.randomID(),
|
|
reactionId,
|
|
mode: "token",
|
|
actorUuid: null,
|
|
tokenUuid: tokenDocument.uuid,
|
|
sceneUuid: tokenDocument.parent?.uuid ?? canvas.scene?.uuid ?? null,
|
|
name: tokenDocument.name
|
|
};
|
|
}
|
|
|
|
async function addReactionFlag(document, reactionId) {
|
|
const assigned = foundry.utils.deepClone(document.getFlag(MODULE_ID, "assignedReactions") ?? []);
|
|
if (!assigned.some(entry => entry.reactionId === reactionId)) {
|
|
assigned.push({ reactionId, assignedAt: Date.now(), assignedBy: game.user.id });
|
|
}
|
|
await document.setFlag(MODULE_ID, "assignedReactions", assigned);
|
|
}
|
|
|
|
async function ensureManagedReactionEffectOnActor(actor, reaction) {
|
|
if (!game.settings.get(MODULE_ID, SETTINGS.CREATE_MANAGED_EFFECTS_ON_ASSIGNMENT)) return;
|
|
|
|
const existing = actor.effects.find(effect =>
|
|
effect.getFlag(MODULE_ID, "reactionId") === reaction.id &&
|
|
effect.getFlag(MODULE_ID, "managed") === true
|
|
);
|
|
|
|
if (existing) return;
|
|
|
|
await actor.createEmbeddedDocuments("ActiveEffect", [{
|
|
name: game.i18n.format("CONFIGURABLE_REACTIONS.Effects.ManagedReaction", { name: reaction.name }),
|
|
icon: reaction.icon ?? "icons/svg/aura.svg",
|
|
origin: `Module.${MODULE_ID}`,
|
|
disabled: false,
|
|
transfer: false,
|
|
changes: [],
|
|
flags: {
|
|
[MODULE_ID]: {
|
|
reactionId: reaction.id,
|
|
managed: true
|
|
}
|
|
}
|
|
}]);
|
|
}
|
|
|
|
async function removeReactionFromDocument(document, reactionId, removeManagedEffects) {
|
|
const assigned = foundry.utils.deepClone(document.getFlag(MODULE_ID, "assignedReactions") ?? [])
|
|
.filter(entry => entry.reactionId !== reactionId);
|
|
|
|
if (assigned.length) await document.setFlag(MODULE_ID, "assignedReactions", assigned);
|
|
else await document.unsetFlag(MODULE_ID, "assignedReactions");
|
|
|
|
if (!removeManagedEffects || !document.effects) return;
|
|
|
|
const effectIds = document.effects
|
|
.filter(effect => effect.getFlag(MODULE_ID, "reactionId") === reactionId && effect.getFlag(MODULE_ID, "managed") === true)
|
|
.map(effect => effect.id);
|
|
|
|
if (effectIds.length) await document.deleteEmbeddedDocuments("ActiveEffect", effectIds);
|
|
}
|