Add status effect selector
This commit is contained in:
@@ -33,7 +33,8 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
removeAction: ConfigurableReactionsConfigApp.#onRemoveAction,
|
||||
saveReactionBasics: ConfigurableReactionsConfigApp.#onSaveReactionBasics,
|
||||
clearTriggerSpell: ConfigurableReactionsConfigApp.#onClearTriggerSpell,
|
||||
clearActionSpell: ConfigurableReactionsConfigApp.#onClearActionSpell
|
||||
clearActionSpell: ConfigurableReactionsConfigApp.#onClearActionSpell,
|
||||
removeActionStatus: ConfigurableReactionsConfigApp.#onRemoveActionStatus
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,16 +67,23 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
const activeTrigger = triggerPalette.find(t => t.type === selectedReaction?.trigger?.type) ?? null;
|
||||
const triggerSpellName = selectedReaction?.trigger?.spell?.itemName || selectedReaction?.trigger?.spell?.itemUuid || "";
|
||||
const activeTriggerAcceptsSpell = isSpellTrigger(selectedReaction?.trigger?.type);
|
||||
const statusEffects = getStatusEffectOptions();
|
||||
const visualActions = (selectedReaction?.actions ?? []).map((action, index) => {
|
||||
const paletteEntry = actionPalette.find(p => p.type === action.type);
|
||||
const selectedStatusIds = Array.from(new Set(action.statuses ?? []));
|
||||
const selectedStatuses = selectedStatusIds.map(statusId => resolveStatusEffect(statusId, statusEffects));
|
||||
|
||||
return {
|
||||
...action,
|
||||
index,
|
||||
label: paletteEntry?.label ?? action.type,
|
||||
icon: paletteEntry?.icon ?? "fa-solid fa-puzzle-piece",
|
||||
summary: summarizeAction(action),
|
||||
summary: summarizeAction(action, statusEffects),
|
||||
isSpellAction: action.type === ACTION_TYPES.CAST_SPELL_FROM_TOKEN,
|
||||
spellName: action.spellSelection?.itemName || action.spellSelection?.itemUuid || ""
|
||||
spellName: action.spellSelection?.itemName || action.spellSelection?.itemUuid || "",
|
||||
isStatusAction: action.type === ACTION_TYPES.APPLY_STATUS,
|
||||
selectedStatuses,
|
||||
availableStatuses: statusEffects.filter(status => !selectedStatusIds.includes(status.id))
|
||||
};
|
||||
});
|
||||
|
||||
@@ -95,7 +103,7 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
activeTriggerAcceptsSpell,
|
||||
triggerSpellName,
|
||||
visualActions,
|
||||
statusEffects: CONFIG.statusEffects.map(s => ({ id: s.id, name: game.i18n.localize(s.name ?? s.id) }))
|
||||
statusEffects
|
||||
};
|
||||
}
|
||||
|
||||
@@ -107,9 +115,22 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
this.render({ force: true });
|
||||
});
|
||||
|
||||
this.#activateStatusSelectors();
|
||||
this.#activateDragAndDrop();
|
||||
}
|
||||
|
||||
#activateStatusSelectors() {
|
||||
for (const select of this.element.querySelectorAll("[data-cr-status-select]")) {
|
||||
select.addEventListener("change", async event => {
|
||||
const actionIndex = Number(event.currentTarget.dataset.actionIndex);
|
||||
const statusId = event.currentTarget.value;
|
||||
if (!Number.isInteger(actionIndex) || !statusId) return;
|
||||
|
||||
await this.#addActionStatus(actionIndex, statusId);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#activateDragAndDrop() {
|
||||
for (const draggable of this.element.querySelectorAll("[data-cr-drag]")) {
|
||||
draggable.setAttribute("draggable", "true");
|
||||
@@ -275,6 +296,18 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
});
|
||||
}
|
||||
|
||||
static async #onRemoveActionStatus(event, target) {
|
||||
const actionIndex = Number(target.dataset.actionIndex);
|
||||
const statusId = target.dataset.statusId;
|
||||
if (!Number.isInteger(actionIndex) || !statusId) return;
|
||||
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
const action = reaction.actions?.[actionIndex];
|
||||
if (!action || action.type !== ACTION_TYPES.APPLY_STATUS) return;
|
||||
action.statuses = (action.statuses ?? []).filter(id => id !== statusId);
|
||||
});
|
||||
}
|
||||
|
||||
static async #onSaveReactionBasics(event, target) {
|
||||
const name = this.element.querySelector("[name='reactionName']")?.value?.trim();
|
||||
const enabled = this.element.querySelector("[name='reactionEnabled']")?.checked === true;
|
||||
@@ -318,6 +351,16 @@ export class ConfigurableReactionsConfigApp extends HandlebarsApplicationMixin(A
|
||||
});
|
||||
}
|
||||
|
||||
async #addActionStatus(actionIndex, statusId) {
|
||||
await this.#mutateSelectedReaction(reaction => {
|
||||
const action = reaction.actions?.[actionIndex];
|
||||
if (!action || action.type !== ACTION_TYPES.APPLY_STATUS) return;
|
||||
|
||||
action.statuses ??= [];
|
||||
if (!action.statuses.includes(statusId)) action.statuses.push(statusId);
|
||||
});
|
||||
}
|
||||
|
||||
async #mutateSelectedReaction(mutator) {
|
||||
const reactions = foundry.utils.deepClone(game.settings.get(MODULE_ID, SETTINGS.REACTIONS) ?? []);
|
||||
const reaction = reactions.find(r => r.id === this._selectedReactionId);
|
||||
@@ -436,7 +479,23 @@ function createDefaultAction(type, item = null) {
|
||||
}
|
||||
}
|
||||
|
||||
function summarizeAction(action) {
|
||||
function getStatusEffectOptions() {
|
||||
return (CONFIG.statusEffects ?? []).map(status => ({
|
||||
id: status.id,
|
||||
label: game.i18n.localize(status.name ?? status.label ?? status.id),
|
||||
icon: status.img ?? status.icon ?? "icons/svg/aura.svg"
|
||||
})).sort((a, b) => a.label.localeCompare(b.label, game.i18n.lang));
|
||||
}
|
||||
|
||||
function resolveStatusEffect(statusId, statusEffects = getStatusEffectOptions()) {
|
||||
return statusEffects.find(status => status.id === statusId) ?? {
|
||||
id: statusId,
|
||||
label: statusId,
|
||||
icon: "icons/svg/aura.svg"
|
||||
};
|
||||
}
|
||||
|
||||
function summarizeAction(action, statusEffects = getStatusEffectOptions()) {
|
||||
switch (action.type) {
|
||||
case ACTION_TYPES.TELEPORT:
|
||||
return game.i18n.format("CONFIGURABLE_REACTIONS.Actions.Teleport.Summary", {
|
||||
@@ -445,7 +504,9 @@ function summarizeAction(action) {
|
||||
});
|
||||
|
||||
case ACTION_TYPES.APPLY_STATUS: {
|
||||
const statuses = action.statuses?.length ? action.statuses.join(", ") : game.i18n.localize("CONFIGURABLE_REACTIONS.Actions.ApplyStatus.NoStatuses");
|
||||
const statuses = action.statuses?.length
|
||||
? action.statuses.map(statusId => resolveStatusEffect(statusId, statusEffects).label).join(", ")
|
||||
: game.i18n.localize("CONFIGURABLE_REACTIONS.Actions.ApplyStatus.NoStatuses");
|
||||
const duration = action.duration?.type === "unlimited" ? game.i18n.localize("CONFIGURABLE_REACTIONS.Duration.Unlimited") : `${action.duration?.value ?? 1} ${action.duration?.type ?? "rounds"}`;
|
||||
return `${statuses} · ${duration}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user