ActiveEffects: Add complete ActiveEffects management system

- New: modules/mournblade-cyd2-effects.js with utility methods for creating, applying, and managing effects
- New: templates/partial-active-effects.hbs for displaying actor effects
- New: templates/partial-item-effects.hbs for displaying item effects
- Update: modules/mournblade-cyd2-config.js with effect configuration (types, attribute keys, categories)
- Update: templates/actor-sheet.hbs and creature-sheet.hbs with Effects tab
- Update: templates/partial-item-nav.hbs with conditional Effects tab
- Update: templates/item-talent-sheet.hbs with Effects tab content
- Update: base-actor-sheet.mjs with effect action handlers (create, edit, delete, toggle)
- Update: base-item-sheet.mjs with effect action handlers and context
- Update: modules/mournblade-cyd2-main.js to import and expose MournbladeCYD2Effects
- Update: lang/fr.json with effect-related translations

Features:
- Support for creating permanent and temporary effects
- Support for attribute modifications (ADR, PUI, CLA, PRE, TRE, etc.)
- Support for health, soul, combat, and adversity modifications
- Support for status effects
- Support for runes (pronounced and traced) effects
- Toggle to enable/disable effects
- Duration tracking (rounds, turns, seconds, combat, scene)
- Display of all active modifications summary

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-06-06 22:51:31 +02:00
parent 5ab03920d6
commit 156672d853
12 changed files with 1291 additions and 2 deletions
@@ -39,6 +39,12 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
deletePredilection: MournbladeCYD2ItemSheetV2.#onDeletePredilection,
addAutomation: MournbladeCYD2ItemSheetV2.#onAddAutomation,
deleteAutomation: MournbladeCYD2ItemSheetV2.#onDeleteAutomation,
// Actions pour les ActiveEffects
createEffect: MournbladeCYD2ItemSheetV2.#onCreateEffect,
editEffect: MournbladeCYD2ItemSheetV2.#onEditEffect,
deleteEffect: MournbladeCYD2ItemSheetV2.#onDeleteEffect,
toggleEffect: MournbladeCYD2ItemSheetV2.#onToggleEffect,
applyEffect: MournbladeCYD2ItemSheetV2.#onApplyEffect,
},
};
@@ -52,6 +58,7 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
item: this.document,
system: this.document.system,
source: this.document.toObject(),
config: game.system.mournbladecyd2.config,
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(
this.document.system.description || "", { async: true }
),
@@ -171,4 +178,118 @@ export default class MournbladeCYD2ItemSheetV2 extends HandlebarsApplicationMixi
await this.document.update({ "system.isautomated": false });
}
}
// #region ActiveEffects Management
/**
* Crée un nouvel effet actif sur l'item
* @param {Event} event - Événement
* @param {HTMLElement} target - Éléments cible
* @private
*/
static async #onCreateEffect(event, target) {
event.preventDefault();
// Créer les données par défaut pour un nouvel effet
const defaultEffectData = {
name: game.i18n.localize("MOURNBLADECYD2.EFFECT.new") || "Nouvel Effet",
icon: "systems/fvtt-mournblade-cyd-2-0/assets/icons/effect.webp",
description: "",
changes: [],
disabled: false,
duration: {},
origin: this.document.uuid,
tint: "",
transfer: false,
flags: {}
};
// Utiliser la dialog native FoundryVTT pour créer l'effet
const effect = await foundry.applications.api.ActiveEffectDialog.create({
document: this.document,
effect: defaultEffectData
});
if (effect) {
await this.document.createEmbeddedDocuments("ActiveEffect", [effect.toObject()]);
}
}
/**
* Édite un effet actif existant sur l'item
* @param {Event} event - Événement
* @param {HTMLElement} target - Éléments cible
* @private
*/
static async #onEditEffect(event, target) {
event.preventDefault();
const effectId = target?.dataset?.effectId;
if (!effectId) return;
const effect = this.document.effects.get(effectId);
if (effect) {
// Ouvrir la sheet de l'effet pour édition
effect.sheet.render(true);
}
}
/**
* Supprime un effet actif de l'item
* @param {Event} event - Événement
* @param {HTMLElement} target - Éléments cible
* @private
*/
static async #onDeleteEffect(event, target) {
event.preventDefault();
const effectId = target?.dataset?.effectId;
if (!effectId) return;
const effect = this.document.effects.get(effectId);
if (effect) {
const confirmed = await foundry.applications.api.DialogV2.confirm({
title: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirm") || "Supprimer l'effet",
content: game.i18n.localize("MOURNBLADECYD2.EFFECT.deleteConfirmText") || `Êtes-vous sûr de vouloir supprimer l'effet "${effect.name}" ?`
});
if (confirmed) {
await this.document.deleteEmbeddedDocuments("ActiveEffect", [effectId]);
}
}
}
/**
* Toggle l'état actif/désactivé d'un effet sur l'item
* @param {Event} event - Événement
* @param {HTMLElement} target - Éléments cible
* @private
*/
static async #onToggleEffect(event, target) {
event.preventDefault();
const effectId = target?.dataset?.effectId;
if (!effectId) return;
const effect = this.document.effects.get(effectId);
if (effect) {
await effect.update({ disabled: !effect.disabled });
}
}
/**
* Applique un effet à partir de l'item
* @param {Event} event - Événement
* @param {HTMLElement} target - Éléments cible
* @private
*/
static async #onApplyEffect(event, target) {
event.preventDefault();
const effectId = target?.dataset?.effectId;
if (!effectId) return;
const effect = this.document.effects.get(effectId);
if (effect) {
await effect.apply();
}
}
// #endregion
}