From c96e8d69d79210088458b79662cdec80436cd095 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Wed, 5 Aug 2026 21:24:33 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20retours=20review=20-=20validation=20de?= =?UTF-8?q?=20phase,=20drop=20de=20v=C3=A9hicule=20et=20d=C3=A9s=20de=20R?= =?UTF-8?q?=C3=A9serve?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - resetPhaseLimits ne touche plus au compteur de phase (seul le dialogue d'attribution du MJ l'avance) : évite le double-incrément quand joueur et MJ valident la même phase. - _onDropActor : import d'une copie monde pour un véhicule déposé depuis un compendium, confirmation avant de transférer un véhicule déjà rattaché à un autre Groupe, try/catch avec retour utilisateur. - #onClickRadioHexa : garde isEditable (pas d'erreur de permission pour un utilisateur non éditeur). --- lang/en.json | 5 +++ lang/fr.json | 5 +++ .../applications/sheets/base-actor-sheet.mjs | 5 +++ .../applications/sheets/character-sheet.mjs | 2 +- module/applications/sheets/group-sheet.mjs | 39 ++++++++++++++++--- module/system/experience.mjs | 14 +++---- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/lang/en.json b/lang/en.json index d0a14d9..667bd39 100644 --- a/lang/en.json +++ b/lang/en.json @@ -378,6 +378,11 @@ "open_learning": "Learning", "validate_phase": "Validate phase", "validate_phase_done": "Experience phase validated: learning limits reset.", + "error_not_editable": "You do not have permission to modify this element.", + "vehicle_assign": "Attach vehicle", + "vehicle_assign_confirm": "This vehicle already belongs to \"{group}\". Attach it to this group?", + "vehicle_assign_failed": "Could not attach this vehicle to the group.", + "vehicle_import_failed": "Could not import this vehicle from the compendium.", "learning_limits": "Learning limits (per phase)", "learned_skill": "Skill", "learned_specialty": "Specialty", diff --git a/lang/fr.json b/lang/fr.json index 2cfbbcb..daebb90 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -361,6 +361,11 @@ "open_learning": "Apprentissage", "validate_phase": "Valider la phase", "validate_phase_done": "Phase d'Expérience validée : limites d'apprentissage réinitialisées.", + "error_not_editable": "Vous n'avez pas la permission de modifier cet élément.", + "vehicle_assign": "Attacher le véhicule", + "vehicle_assign_confirm": "Ce véhicule appartient déjà à « {group} ». L'attacher à ce Groupe ?", + "vehicle_assign_failed": "Impossible d'attacher ce véhicule au Groupe.", + "vehicle_import_failed": "Impossible d'importer ce véhicule depuis le compendium.", "learning_limits": "Limites d'apprentissage (par phase)", "learned_skill": "Compétence", "learned_specialty": "Spécialité", diff --git a/module/applications/sheets/base-actor-sheet.mjs b/module/applications/sheets/base-actor-sheet.mjs index d15b1b6..60199d7 100644 --- a/module/applications/sheets/base-actor-sheet.mjs +++ b/module/applications/sheets/base-actor-sheet.mjs @@ -311,6 +311,11 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo static #onClickRadioHexa(event, target) { event.preventDefault() event.stopPropagation() + // Évite une erreur de permission pour un utilisateur non éditeur. + if (!this.isEditable) { + ui.notifications.warn(game.i18n.localize("VERMINE.error_not_editable")) + return + } const input = target const update = {} let current = this.document diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index a5e87f0..2a7fda3 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -130,7 +130,7 @@ export default class VermineCharacterSheetV2 extends VermineBaseActorSheet { /** Valide la phase d'Expérience courante et réinitialise les limites. */ static async #onValidatePhase() { const { VermineExperience } = await import("../../system/experience.mjs") - await VermineExperience.completePhase(this.document) + await VermineExperience.resetPhaseLimits(this.document) ui.notifications.info(game.i18n.localize("VERMINE.validate_phase_done")) } } diff --git a/module/applications/sheets/group-sheet.mjs b/module/applications/sheets/group-sheet.mjs index a89eaab..cb3587e 100644 --- a/module/applications/sheets/group-sheet.mjs +++ b/module/applications/sheets/group-sheet.mjs @@ -113,16 +113,45 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { /** * Dépôt d'un acteur Véhicule sur la fiche : lie le véhicule au Groupe * (system.ownerId) au lieu de le dupliquer, puis affiche la liste. + * Gère les dépôts depuis un compendium (copie importée dans le monde) + * et demande confirmation si le véhicule appartient déjà à un autre Groupe. * @override */ async _onDropActor(event, data) { - const actor = data instanceof foundry.abstract.Document ? data : await fromUuid(data.uuid) - if (actor?.type === "vehicle") { + let actor = data instanceof foundry.abstract.Document ? data : await fromUuid(data.uuid) + if (actor?.type !== "vehicle") { + return super._onDropActor?.(event, data) + } + // Véhicule issu d'un compendium : importer une copie dans le monde. + if (actor.compendium) { + try { + const copy = await game.actors.importFromCompendium(actor.compendium, actor._id, { renderSheet: false }) + if (!copy) return + actor = copy + } catch { + ui.notifications.warn(game.i18n.localize("VERMINE.vehicle_import_failed")) + return + } + } + // Véhicule déjà rattaché à un autre Groupe : confirmation avant transfert. + const currentOwner = actor.system?.ownerId + if (currentOwner && currentOwner !== this.document.id) { + const other = game.actors.get(currentOwner) + const content = game.i18n.localize("VERMINE.vehicle_assign_confirm").replace("{group}", other?.name ?? currentOwner) + const confirmed = await Dialog.confirm({ + title: game.i18n.localize("VERMINE.vehicle_assign"), + content, + defaultYes: false + }) + if (!confirmed) return + } + try { await actor.update({ "system.ownerId": this.document.id }) - this.render() + } catch { + ui.notifications.warn(game.i18n.localize("VERMINE.vehicle_assign_failed")) return } - return super._onDropActor?.(event, data) + this.render() } // Actions : délégation aux applications AppV1 existantes pour TotemPicker/ActorPicker @@ -192,7 +221,7 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet { /** Valide la phase d'Expérience courante du Groupe et réinitialise les limites. */ static async #onValidatePhase() { const { VermineExperience } = await import("../../system/experience.mjs") - await VermineExperience.completePhase(this.document) + await VermineExperience.resetPhaseLimits(this.document) ui.notifications.info(game.i18n.localize("VERMINE.validate_phase_done")) } } diff --git a/module/system/experience.mjs b/module/system/experience.mjs index 193d612..59cb579 100644 --- a/module/system/experience.mjs +++ b/module/system/experience.mjs @@ -215,24 +215,22 @@ export class VermineExperience { } /** - * Valide la phase d'Expérience courante : passe à la phase suivante et - * réinitialise toutes les limites d'apprentissage (learned.*), pour un - * personnage ou un Groupe. + * Réinitialise les limites d'apprentissage (learned.*) de la phase + * courante, pour un personnage ou un Groupe, sans toucher au compteur + * de phase (avancé uniquement par le dialogue d'attribution du MJ). * @param {foundry.abstract.Document} actor personnage ou Groupe * @returns {Promise} */ - static async completePhase(actor) { + static async resetPhaseLimits(actor) { const ex = actor.system?.experience if (!ex) return - const phase = (ex.phase || 0) + 1 - const update = { "system.experience.phase": phase } + const update = {} if (ex.learned && typeof ex.learned === "object") { - update["system.experience.learned.phase"] = phase for (const key of Object.keys(ex.learned)) { if (key === "phase") continue update[`system.experience.learned.${key}`] = false } } - await actor.update(update) + if (Object.keys(update).length) await actor.update(update) } }