From c0442f607c71a78c809e8ee6f84e8729b9fb3e13 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 29 Jan 2022 23:33:31 +0100 Subject: [PATCH] Gestion des choix de combat par flags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Utiliser des flags sur les ChatMessage de choix de combat permet: - de conserver les informations même après un refresh - de simplifier un peu (pas besoin de gérer un stockage custom) --- module/chat-utility.js | 20 +++++- module/rdd-combat.js | 141 +++++++---------------------------------- 2 files changed, 43 insertions(+), 118 deletions(-) diff --git a/module/chat-utility.js b/module/chat-utility.js index ba8fdf4c..976e1b0c 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -1,5 +1,7 @@ import { Misc } from "./misc.js"; -import { SYSTEM_SOCKET_ID } from "./constants.js"; +import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; + +export const MESSAGE_DATA = 'message-data'; /** * Class providing helper methods to get the list of users, and @@ -160,4 +162,20 @@ export class ChatUtility { } } + static async setMessageData(chatMessage, key, data) { + if (data) { + await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(data)); + } + } + + static getMessageData(chatMessage, key) { + const json = chatMessage.getFlag(SYSTEM_RDD, key); + return json ? JSON.parse(json) : undefined; + } + + static getChatMessage(event) { + const chatMessageId = $(event.currentTarget).closest('.chat-message').attr('data-message-id'); + return game.messages.get(chatMessageId); + } + } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index d7a38e3f..e341ed42 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -371,19 +371,10 @@ export class RdDCombatManager extends Combat { export class RdDCombat { static init() { - this.initStorePasseArmes(); Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) }); Hooks.on("preDeleteCombat", (combat, options, userId) => { RdDCombat.onPreDeleteCombat(combat, options, userId); }); } - /* -------------------------------------------- */ - static initStorePasseArmes() { - game.system.rdd.combatStore = { - attaques: {}, - defenses: {} - }; - } - /* -------------------------------------------- */ static onSocketMessage(sockmsg) { switch (sockmsg.msg) { @@ -391,8 +382,6 @@ export class RdDCombat { return RdDCombat.onMsgEncaisser(sockmsg.data); case "msg_defense": return RdDCombat.onMsgDefense(sockmsg.data); - case "msg_combat_passearme": - return RdDCombat.onMsgPasseArme(sockmsg.data); } } @@ -405,22 +394,11 @@ export class RdDCombat { /* -------------------------------------------- */ static onPreDeleteCombat(combat, options, userId) { - if (game.user.isGM) { + if (Misc.isUniqueConnectedGM()) { combat.cleanItemUse(); ChatUtility.removeChatMessageContaining(`
`) - /* - * TODO: support de plusieurs combats parallèles - * il faudrait avoir un id de combat en plus de celui de passe d'armes - */ - for (const key in game.system.rdd.combatStore.attaques) { - const attackerRoll = game.system.rdd.combatStore.attaques[key]; - ChatUtility.removeChatMessageContaining(`
`); - } - for (const key in game.system.rdd.combatStore.defenses) { - const defenderRoll = game.system.rdd.combatStore.defenses[key]; - ChatUtility.removeChatMessageContaining(`
`); - } - RdDCombat.initStorePasseArmes(); + game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined) + .forEach(it => it.delete()); } } @@ -471,61 +449,6 @@ export class RdDCombat { return undefined; } - /* -------------------------------------------- */ - static messagePasseArme(data) { - // TODO: store required info for combat in the chat message presenting choices? - game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_combat_passearme", data: data }); - RdDCombat.onMsgPasseArme(data); - } - - /* -------------------------------------------- */ - static onMsgPasseArme(data) { - switch (data.actionPasseArme) { - case "store-attaque": - game.system.rdd.combatStore.attaques[data.id] = data.rollData; - break; - case "store-defense": - game.system.rdd.combatStore.defenses[data.id] = data.rollData; - break; - case "delete-attaque": - delete game.system.rdd.combatStore.attaques[data.id]; - break; - case "delete-defense": - delete game.system.rdd.combatStore.defenses[data.id]; - break; - } - } - - /* -------------------------------------------- */ - static _storeAttaque(attackerId, attackerRoll) { - RdDCombat.messagePasseArme({ actionPasseArme: "store-attaque", id: attackerId, rollData: attackerRoll }); - } - - /* -------------------------------------------- */ - static _getAttaque(attackerId) { - return game.system.rdd.combatStore.attaques[attackerId]; - } - - /* -------------------------------------------- */ - static _deleteAttaque(attackerId) { - RdDCombat.messagePasseArme({ actionPasseArme: "delete-attaque", id: attackerId }); - } - - /* -------------------------------------------- */ - static _storeDefense(passeArme, defenderRoll) { - RdDCombat.messagePasseArme({ actionPasseArme: "store-defense", id: passeArme, rollData: defenderRoll }); - } - - /* -------------------------------------------- */ - static _getDefense(passeArme) { - return game.system.rdd.combatStore.defenses[passeArme]; - } - - /* -------------------------------------------- */ - static _deleteDefense(passeArme) { - RdDCombat.messagePasseArme({ actionPasseArme: "delete-defense", id: passeArme }); - } - /* -------------------------------------------- */ static create(attacker, defender, defenderTokenId, target = undefined) { return new RdDCombat(attacker, defender, defenderTokenId, target) @@ -547,7 +470,7 @@ export class RdDCombat { static onMsgEncaisser(data) { let defender = canvas.tokens.get(data.defenderTokenId).actor; if (Misc.isOwnerPlayerOrUniqueConnectedGM()) { - let attackerRoll = RdDCombat._getAttaque(data.attackerId); // Retrieve the rolldata from the store + let attackerRoll = data.attackerRoll; let attacker = data.attackerId ? game.actors.get(data.attackerId) : null; defender.encaisserDommages(attackerRoll, attacker); @@ -563,10 +486,8 @@ export class RdDCombat { const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); if (rddCombat) { const defenderRoll = msg.defenderRoll; - RdDCombat._storeAttaque(msg.attackerId, defenderRoll.attackerRoll); - RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll); rddCombat.removeChatMessageActionsPasseArme(defenderRoll.passeArme); - rddCombat._chatMessageDefense(msg.paramChatDefense); + rddCombat._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll); } } } @@ -621,12 +542,10 @@ export class RdDCombat { /* -------------------------------------------- */ async onEvent(button, event) { - const attackerRoll = RdDCombat._getAttaque(this.attackerId); - if (!attackerRoll) { - ui.notifications.warn("Action automatisée impossible, le jet de l'attaquant a été perdu (suite à un raffraichissement?)") - return; - } - const defenderRoll = game.system.rdd.combatStore.defenses[attackerRoll.passeArme]; + const chatMessage = ChatUtility.getChatMessage(event); + const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll'); + const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll') ; + console.log('RdDCombat', attackerRoll, defenderRoll); const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value; const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; @@ -637,7 +556,7 @@ export class RdDCombat { case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); case '#parer-button': return this.parade(attackerRoll, armeParadeId); case '#esquiver-button': return this.esquive(attackerRoll, compId, competence); - case '#encaisser-button': return this.encaisser(attackerRoll, defenderTokenId); + case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll, defenderTokenId); case '#echec-total-attaque': return this._onEchecTotal(attackerRoll); case '#appel-chance-attaque': return this.attacker.rollAppelChance( @@ -650,7 +569,7 @@ export class RdDCombat { () => this.attaqueSignificative(attackerRoll), () => { }); case '#appel-destinee-defense': return this.defender.appelDestinee( - () => this.defenseDestinee(attackerRoll), + () => this.defenseDestinee(defenderRoll), () => { }); } } @@ -680,8 +599,7 @@ export class RdDCombat { } /* -------------------------------------------- */ - defenseDestinee(attackerRoll) { - let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme); + defenseDestinee(defenderRoll) { if (defenderRoll) { ui.notifications.info('Défense significative grâce à la destinée') RdDResolutionTable.significativeRequise(defenderRoll.rolled); @@ -819,8 +737,7 @@ export class RdDCombat { /* -------------------------------------------- */ async _onAttaqueParticuliere(rollData) { - RdDCombat._storeAttaque(this.attackerId, rollData); - + const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0; // force toujours, sauf empoignade // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum @@ -838,8 +755,8 @@ export class RdDCombat { else if (!isForce && !isFinesse && isRapide) { return await this.choixParticuliere(rollData, "rapidite"); } - - ChatMessage.create({ + + const choixParticuliere = await ChatMessage.create({ alias: this.attacker.name, whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', { @@ -852,6 +769,7 @@ export class RdDCombat { passeArme: rollData.passeArme }) }); + ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData); } /* -------------------------------------------- */ @@ -860,10 +778,6 @@ export class RdDCombat { attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar()); let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} } - // Save rollData for defender - RdDCombat._storeAttaque(this.attackerId, attackerRoll); - RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll); - attackerRoll.show = { cible: this.target ? this.defender.data.name : 'la cible', isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge') @@ -918,7 +832,7 @@ export class RdDCombat { }; if (Misc.isUniqueConnectedGM()) { - await this._chatMessageDefense(paramChatDefense); + await this._chatMessageDefense(paramChatDefense, defenderRoll); } else { this._socketSendMessageDefense(paramChatDefense, defenderRoll); @@ -926,14 +840,16 @@ export class RdDCombat { } /* -------------------------------------------- */ - async _chatMessageDefense(paramDemandeDefense) { - ChatMessage.create({ + async _chatMessageDefense(paramDemandeDefense, defenderRoll) { + const choixDefense = await ChatMessage.create({ // message privé: du défenseur à lui même (et aux GMs) speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)), alias: this.attacker.name, whisper: ChatUtility.getWhisperRecipientsAndGMs(this.defender.name), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense), }); + // flag pour garder les jets d'attaque/defense + ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll); } /* -------------------------------------------- */ @@ -974,10 +890,7 @@ export class RdDCombat { /* -------------------------------------------- */ async _onAttaqueEchecTotal(attackerRoll) { - - RdDCombat._storeAttaque(this.attackerId, attackerRoll); - - ChatMessage.create({ + const choixEchecTotal = await ChatMessage.create({ whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { attackerId: this.attackerId, @@ -986,6 +899,7 @@ export class RdDCombat { essais: attackerRoll.essais }) }); + ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll); } /* -------------------------------------------- */ @@ -1105,7 +1019,6 @@ export class RdDCombat { this.removeChatMessageActionsPasseArme(defenderRoll.passeArme); this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true }); - RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll); } /* -------------------------------------------- */ @@ -1177,7 +1090,6 @@ export class RdDCombat { this.removeChatMessageActionsPasseArme(defenderRoll.passeArme); this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true }) - RdDCombat._storeDefense(defenderRoll.passeArme, defenderRoll); } /* -------------------------------------------- */ @@ -1282,15 +1194,10 @@ export class RdDCombat { } /* -------------------------------------------- */ - async encaisser(attackerRoll, defenderTokenId) { + async encaisser(attackerRoll, defenderRoll, defenderTokenId) { defenderTokenId = defenderTokenId || this.defenderTokenId; console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId); - let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme); - if (!defenderRoll) { - ui.notifications.warn("Cette passe d'arme est déjà terminée!") - return; - } if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) { this._onEchecTotal(defenderRoll); }