diff --git a/fvtt-hamalron.mjs b/fvtt-hamalron.mjs index 67701d9..f8ec0cf 100644 --- a/fvtt-hamalron.mjs +++ b/fvtt-hamalron.mjs @@ -29,6 +29,7 @@ Hooks.once("init", function () { models, documents, openTarotDeckManager: () => applications.HamalronTarotDeckManager.openManager(), + openActionComplexe: () => applications.HamalronActionComplexe.open(), } // Global reference needed by initiative override @@ -124,6 +125,15 @@ Hooks.once("init", function () { default: { deck: [], discard: [] }, }) + game.settings.register("fvtt-hamalron", "actionComplexeState", { + name: "Action Complexe State", + hint: "Stores ongoing complex actions", + scope: "world", + config: false, + type: Object, + default: { actions: [] }, + }) + // Activate socket handler game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent) @@ -156,10 +166,9 @@ Hooks.once("ready", function () { }) -// Add button to scene controls for Tarot Deck Manager +// Add button to scene controls for Tarot Deck Manager and Actions Complexes Hooks.on("getSceneControlButtons", (controls) => { if (game.user.isGM) { - // Handle both old and new Foundry API const controlsArray = Array.isArray(controls) ? controls : controls.controls || []; const tokenControls = controlsArray.find(c => c.name === "token") if (tokenControls) { @@ -170,6 +179,13 @@ Hooks.on("getSceneControlButtons", (controls) => { button: true, onClick: () => applications.HamalronTarotDeckManager.openManager(), }) + tokenControls.tools.push({ + name: "action-complexe", + title: "HAMALRON.ActionComplexe.Title", + icon: "fas fa-tasks", + button: true, + onClick: () => applications.HamalronActionComplexe.open(), + }) } } }) diff --git a/lang/fr.json b/lang/fr.json index 1e80f7f..4d21dfc 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -810,6 +810,24 @@ "label": "Seuil" } } + }, + "ActionComplexe": { + "Title": "Actions complexes", + "CreateAction": "Nouvelle action", + "CreateTitle": "Créer une action complexe", + "Create": "Créer", + "Name": "Nom", + "Symbole": "Symbole", + "Resistance": "Résistance", + "Notes": "Notes", + "Success": "Réussite", + "Failure": "Échec", + "Successes": "succès", + "NoActions": "Aucune action complexe en cours", + "Completed": "{name} — Action accomplie !", + "Progress": "{name} — {current}/{total} succès", + "DeleteTitle": "Supprimer l'action", + "DeleteWarning": "Voulez-vous vraiment supprimer cette action complexe ? Les données seront perdues." } } } \ No newline at end of file diff --git a/module/applications/_module.mjs b/module/applications/_module.mjs index a6d9409..506afaa 100644 --- a/module/applications/_module.mjs +++ b/module/applications/_module.mjs @@ -14,3 +14,4 @@ export { default as HamalronItemSheet } from "./sheets/base-item-sheet.mjs" export { default as HamalronActorSheet } from "./sheets/base-actor-sheet.mjs" export { default as HamalronTarotDeckManager } from "./tarot-deck-manager.mjs" export { default as HamalronSortilegeCasting } from "./sortilege-casting.mjs" +export { default as HamalronActionComplexe } from "./action-complexe.mjs" diff --git a/module/applications/action-complexe.mjs b/module/applications/action-complexe.mjs new file mode 100644 index 0000000..35120b4 --- /dev/null +++ b/module/applications/action-complexe.mjs @@ -0,0 +1,200 @@ +const { HandlebarsApplicationMixin } = foundry.applications.api + +export default class HamalronActionComplexe extends HandlebarsApplicationMixin(foundry.applications.api.ApplicationV2) { + constructor(options = {}) { + super(options) + HamalronActionComplexe.#instance = this + this.actions = [] + this.#loadState() + } + + static #instance + + static get instance() { + if (!HamalronActionComplexe.#instance) { + HamalronActionComplexe.#instance = new HamalronActionComplexe() + } + return HamalronActionComplexe.#instance + } + + static DEFAULT_OPTIONS = { + id: "action-complexe", + classes: ["fvtt-hamalron", "action-complexe"], + tag: "div", + window: { + title: "HAMALRON.ActionComplexe.Title", + icon: "fas fa-tasks", + resizable: true, + }, + position: { + width: 500, + height: "auto", + }, + actions: { + createAction: HamalronActionComplexe.#onCreateAction, + recordSuccess: HamalronActionComplexe.#onRecordSuccess, + recordFailure: HamalronActionComplexe.#onRecordFailure, + deleteAction: HamalronActionComplexe.#onDeleteAction, + resetAction: HamalronActionComplexe.#onResetAction, + }, + } + + static PARTS = { + main: { + template: "systems/fvtt-hamalron/templates/dialog-action-complexe.hbs", + }, + } + + async _prepareContext(options) { + const context = await super._prepareContext(options) + context.actions = this.actions.map(a => ({ + ...a, + pct: a.resistance > 0 ? Math.round((a.currentSuccesses / a.resistance) * 100) : 0, + isComplete: a.currentSuccesses >= a.resistance, + symboleIcon: HamalronActionComplexe.#symboleIcon(a.symbole), + })) + context.hasActions = context.actions.length > 0 + return context + } + + static #symboleIcon(symbole) { + const icons = { coupe: "fa-heart", epee: "fa-crossed-swords", denier: "fa-coins", baton: "fa-staff" } + return icons[symbole] || "fa-circle" + } + + #loadState() { + const state = game.settings.get("fvtt-hamalron", "actionComplexeState") + if (state?.actions?.length) { + this.actions = state.actions + } + } + + async #saveState() { + await game.settings.set("fvtt-hamalron", "actionComplexeState", { actions: this.actions }) + } + + static #onCreateAction(event, target) { + const self = this + const content = ` +
${action.currentSuccesses}/${action.resistance} ${game.i18n.localize("HAMALRON.ActionComplexe.Successes")}
${game.i18n.localize("HAMALRON.ActionComplexe.DeleteWarning")}
`, + rejectClose: false, + modal: true, + }) + if (!confirmed) return + this.actions = this.actions.filter(a => a.id !== id) + await this.#saveState() + this.render() + } + + static #onResetAction(event, target) { + const id = target.dataset.actionId + const action = this.actions.find(a => a.id === id) + if (!action) return + action.currentSuccesses = 0 + action.failures = 0 + this.#saveState() + this.render() + } + + static open() { + if (!game.user.isGM) { + ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.GMOnly")) + return + } + HamalronActionComplexe.instance.render(true, { focus: true }) + return HamalronActionComplexe.instance + } +} diff --git a/templates/dialog-action-complexe.hbs b/templates/dialog-action-complexe.hbs new file mode 100644 index 0000000..930c183 --- /dev/null +++ b/templates/dialog-action-complexe.hbs @@ -0,0 +1,58 @@ +{{localize "HAMALRON.ActionComplexe.NoActions"}}
+