diff --git a/module/actor.js b/module/actor.js index 583198e3..78aa7024 100644 --- a/module/actor.js +++ b/module/actor.js @@ -409,7 +409,7 @@ export class RdDActor extends Actor { async dormir(heures = 1) { let message = { whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: "Vous dormez " + heures + " heure" + (heures > 1 ? "s" : "") + content: this.name +": Vous dormez " + heures + " heure" + (heures > 1 ? "s" : "") }; await this.recupereEndurance(message); for (let i = 0; i < heures; i++) { @@ -2105,7 +2105,7 @@ export class RdDActor extends Actor { } // Notification au MJ - ChatMessage.create({ content: game.user.name + " est monté dans les TMR en mode : " + mode, whisper: ChatMessage.getWhisperRecipients("GM") }); + ChatMessage.create({ content: this.name + " est monté dans les TMR en mode : " + mode, whisper: ChatMessage.getWhisperRecipients("GM") }); let data = { fatigue: { diff --git a/module/chat-utility.js b/module/chat-utility.js index b6cb99ea..2d71979c 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -59,7 +59,7 @@ export class ChatUtility { /* -------------------------------------------- */ static getWhisperRecipientsAndGMs(name) { return ChatMessage.getWhisperRecipients(name) - .concat(this.getUsers(user => user.isGM)); + .concat(ChatMessage.getWhisperRecipients('GM')); } /* -------------------------------------------- */ diff --git a/module/item-sheet.js b/module/item-sheet.js index ee0cee01..5c2dc75c 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -64,7 +64,7 @@ export class RdDItemSheet extends ItemSheet { data.actorId = this.actor._id; } data.bonusCaseList = RdDItemSort.getBonusCaseList(data, true); - data.isGM = game.user.isGM; // Pour vérouiller certaines éditions + data.isGM = game.user.isGM; // Pour verrouiller certaines éditions return data; } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index c3c16c16..c4183b1b 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -28,9 +28,9 @@ export class RdDCombat { static onSocketMessage(sockmsg) { switch (sockmsg.msg) { case "msg_encaisser": - return RdDCombat.terminerPasseArmes(data); + return RdDCombat.onMsgEncaisser(sockmsg.data); case "msg_defense": - return RdDCombat.handleMsgDefense(sockmsg.data); + return RdDCombat.onMsgDefense(sockmsg.data); } } @@ -99,6 +99,36 @@ export class RdDCombat { return undefined; } + /* -------------------------------------------- */ + static _storeAttaque(attackerId, attackerRoll) { + game.system.rdd.combatStore.attaques[attackerId] = duplicate(attackerRoll); + } + + /* -------------------------------------------- */ + static _getAttaque(attackerId) { + return game.system.rdd.combatStore.attaques[attackerId]; + } + + /* -------------------------------------------- */ + static _deleteAttaque(attackerId) { + delete game.system.rdd.combatStore.attaques[attackerId]; + } + + /* -------------------------------------------- */ + static _storeDefense(defenderRoll) { + game.system.rdd.combatStore.defenses[defenderRoll.passeArme] = duplicate(defenderRoll); + } + + /* -------------------------------------------- */ + static _getDefense(passeArme) { + return game.system.rdd.combatStore.defenses[passeArme]; + } + + /* -------------------------------------------- */ + static _deleteDefense(passeArme) { + delete game.system.rdd.combatStore.defenses; + } + /* -------------------------------------------- */ static create(attacker, defender, defenderTokenId, target = undefined) { return new RdDCombat(attacker, defender, defenderTokenId, target) @@ -121,59 +151,36 @@ export class RdDCombat { } /* -------------------------------------------- */ - static handleMsgDefense(data) { - let defenderToken = canvas.tokens.get(data.defenderTokenId); + static onMsgEncaisser(data) { + let attackerRoll = RdDCombat._getAttaque(data.attackerId); // Retrieve the rolldata from the store + + if (game.user.id === data.gmId) { // Seul le GM effectue l'encaissement sur la fiche + let attacker = data.attackerId ? game.actors.get(data.attackerId) : null; + let defender = canvas.tokens.get(data.defenderTokenId).actor; + + defender.encaisserDommages(attackerRoll, attacker); + } + + RdDCombat._deleteDefense(attackerRoll.passeArme); + RdDCombat._deleteAttaque(data.attackerId); + } + + /* -------------------------------------------- */ + static onMsgDefense(msgData) { + let defenderToken = canvas.tokens.get(msgData.defenderTokenId); if (defenderToken) { - if (!game.user.isGM && game.user.character == undefined) { // vérification / sanity check + if (!game.user.isGM && !game.user.character) { // vérification / sanity check ui.notifications.error("Le joueur " + game.user.name + " n'est connecté à aucun personnage. Impossible de continuer."); return; } if ((game.user.isGM && !defenderToken.actor.hasPlayerOwner) || (defenderToken.actor.hasPlayerOwner && (game.user.character.id == defenderToken.actor.data._id))) { - //console.log("User is pushing message...", game.user.name); - game.system.rdd.combatStore.attaques[data.attackerId] = duplicate(data.rollData); - data.whisper = [game.user]; - data.blind = true; - data.rollMode = "blindroll"; - ChatMessage.create(data); + const defenderRoll = msgData.defenderRoll; + RdDCombat._storeAttaque(msgData.attackerId, defenderRoll.attackerRoll); + RdDCombat._storeDefense(defenderRoll); } } } - static terminerPasseArmes(data) { - if (game.user.isGM) { // Seul le GM nettoie le stockage des données de combat - let attackerRoll = game.system.rdd.combatStore.attaques[data.attackerId]; // Retrieve the rolldata from the store - game.system.rdd.combatStore.attaques[data.attackerId] = undefined; - game.system.rdd.combatStore.defenses[attackerRoll.passeArme] = undefined; - } - } - - /* -------------------------------------------- */ - static _sendRollMessage(sender, recipient, defenderTokenId, topic, message, rollData) { - let chatMessage = { - content: message, - whisper: ChatUtility.getWhisperRecipients("blindroll", recipient.name), - }; - - // envoyer le message au destinataire - if (!game.user.isGM || recipient.hasPlayerOwner) { - let data = { - attackerId: sender?.data._id, - defenderId: recipient?.data._id, - defenderTokenId: defenderTokenId, - rollData: duplicate(rollData), - rollMode: true - }; - mergeObject(data, chatMessage); - game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: topic, data: data }); - } else { - chatMessage.whisper = [game.user]; - } - - if (game.user.isGM) { // Always push the message to the MJ - ChatMessage.create(chatMessage); - } - } - /* -------------------------------------------- */ static _callJetDeVie(event) { let actorId = event.currentTarget.attributes['data-actorId'].value; @@ -218,11 +225,12 @@ export class RdDCombat { /* -------------------------------------------- */ async onEvent(button, event) { - let attackerRoll = game.system.rdd.combatStore.attaques[this.attackerId]; + 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 defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value; const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; @@ -238,8 +246,8 @@ export class RdDCombat { () => this.attaqueChanceuse(attackerRoll), () => this._onEchecTotal(attackerRoll)); case '#appel-chance-defense': return this.defender.rollAppelChance( - () => this.defenseChanceuse(attackerRoll), - () => this.afficherOptionsDefense(attackerRoll, { defenseChance: true })); + () => this.defenseChanceuse(attackerRoll, defenderRoll), + () => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true })); case '#appel-destinee-attaque': return this.attacker.appelDestinee( () => this.attaqueSignificative(attackerRoll), () => { }); @@ -249,23 +257,6 @@ export class RdDCombat { } } - /* -------------------------------------------- */ - _consumeDefense(passeArme) { - let defenderRoll = this._getDefense(passeArme); - game.system.rdd.combatStore.defenses[passeArme] = undefined; - return defenderRoll; - } - - /* -------------------------------------------- */ - _getDefense(passeArme) { - return game.system.rdd.combatStore.defenses[passeArme]; - } - - /* -------------------------------------------- */ - _storeDefense(defenderRoll) { - game.system.rdd.combatStore.defenses[defenderRoll.passeArme] = defenderRoll; - } - /* -------------------------------------------- */ attaqueChanceuse(attackerRoll) { ui.notifications.info("L'attaque est rejouée grâce à la chance") @@ -282,17 +273,17 @@ export class RdDCombat { } /* -------------------------------------------- */ - defenseChanceuse(attackerRoll) { + defenseChanceuse(attackerRoll, defenderRoll) { ui.notifications.info("La défense est rejouée grâce à la chance") attackerRoll.essais.defenseChance = true; attackerRoll.essais.defense = false; this.removeChatMessageActionsPasseArme(attackerRoll.passeArme); - this._sendMessageDefense(attackerRoll); + this._sendMessageDefense(attackerRoll, defenderRoll, attackerRoll.essais); } /* -------------------------------------------- */ defenseDestinee(attackerRoll) { - let defenderRoll = this._getDefense(attackerRoll.passeArme); + let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme); if (defenderRoll) { ui.notifications.info('Défense significative grâce à la destinée') RdDResolutionTable.forceSignificative(defenderRoll.rolled); @@ -310,9 +301,9 @@ export class RdDCombat { } /* -------------------------------------------- */ - afficherOptionsDefense(attackerRoll, essais) { + afficherOptionsDefense(attackerRoll, defenderRoll, essais) { ui.notifications.info("La chance n'est pas avec vous"); - this._sendMessageDefense(attackerRoll, essais); + this._sendMessageDefense(attackerRoll, defenderRoll, essais); } /* -------------------------------------------- */ @@ -410,13 +401,15 @@ export class RdDCombat { /* -------------------------------------------- */ async _onAttaqueParticuliere(rollData) { - game.system.rdd.combatStore.attaques[this.attackerId] = duplicate(rollData); + RdDCombat._storeAttaque(this.attackerId, rollData); // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum const isMeleeDiffNegative = rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0; ChatMessage.create({ - whisper: ChatMessage.getWhisperRecipients(this.attacker.name), + alias: this.attacker.name, + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', { + alias: this.attacker.name, attackerId: this.attackerId, defenderTokenId: this.defenderTokenId, isFinesse: isMeleeDiffNegative, @@ -432,7 +425,7 @@ export class RdDCombat { attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar()); // Save rollData for defender - game.system.rdd.combatStore.attaques[this.attackerId] = duplicate(attackerRoll); + RdDCombat._storeAttaque(this.attackerId, attackerRoll); attackerRoll.show = { cible: this.target ? this.defender.data.name : 'la cible', @@ -450,29 +443,52 @@ export class RdDCombat { } /* -------------------------------------------- */ - async _sendMessageDefense(attackerRoll, essais = {}) { - console.log("RdDCombat._sendMessageDefense", attackerRoll, essais, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.data.categorie); + async _sendMessageDefense(attackerRoll, defenderRoll = undefined, essaisPrecedents = undefined) { + console.log("RdDCombat._sendMessageDefense", attackerRoll, defenderRoll, essaisPrecedents, " / ", this.attacker, this.target, this.attackerId, attackerRoll.competence.data.categorie); this.removeChatMessageActionsPasseArme(attackerRoll.passeArme); - mergeObject(attackerRoll.essais, essais, { overwrite: true }); + if (essaisPrecedents) { + mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true }); + } const paramDemandeDefense = { passeArme: attackerRoll.passeArme, essais: attackerRoll.essais, - // surprise: this.defender.getSurprise(true), - // surprise: attackerRoll.ajustements.attaqueDefenseurSurpris.used, defender: this.defender, attackerId: this.attackerId, defenderTokenId: this.defenderTokenId, mainsNues: attackerRoll.dmg.mortalite != 'mortel' && this.defender.getCompetence("Corps à corps"), armes: this._filterArmesParade(this.defender.data.items, attackerRoll.competence, attackerRoll.arme), diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0, + attaqueParticuliere: attackerRoll.particuliere, dmg: attackerRoll.dmg }; - let message = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense); - RdDCombat._sendRollMessage(this.attacker, this.defender, this.defenderTokenId, "msg_defense", message, attackerRoll); + RdDCombat._sendRollMessage(this.attacker, this.defender, this.defenderTokenId, + defenderRoll ?? { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }, + essaisPrecedents != undefined); + + let chatMessage = { + alias: this.attacker.name, + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.defender.name), + content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense), + }; + ChatMessage.create(chatMessage); } + /* -------------------------------------------- */ + static _sendRollMessage(sender, recipient, defenderTokenId, defenderRoll, selfMessage) { + // envoyer le message au destinataire + if (!selfMessage || !game.user.isGM || recipient.hasPlayerOwner) { + let data = { + attackerId: sender?.data._id, + defenderId: recipient?.data._id, + defenderTokenId: defenderTokenId, + defenderRoll: duplicate(defenderRoll), + rollMode: true + }; + game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_defense", data: data }); + } + } /* -------------------------------------------- */ _filterArmesParade(items, competence) { items = items.filter(item => (item.type == 'arme' && item.data.equipe) || (item.type == 'competencecreature' && item.data.isparade)); @@ -492,7 +508,7 @@ export class RdDCombat { /* -------------------------------------------- */ async _onAttaqueEchecTotal(attackerRoll) { - game.system.rdd.combatStore.attaques[this.attackerId] = duplicate(attackerRoll); + RdDCombat._storeAttaque(this.attackerId, attackerRoll); // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum ChatMessage.create({ @@ -536,7 +552,7 @@ export class RdDCombat { /* -------------------------------------------- */ async parade(attackerRoll, armeParadeId) { let arme = this.defender.getArmeParade(armeParadeId); - + console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme); let rollData = this._prepareParade(attackerRoll, arme); @@ -616,11 +632,11 @@ export class RdDCombat { async _onParadeNormale(defenderRoll) { console.log("RdDCombat._onParadeNormale >>>", defenderRoll); - this._consumeDefense(defenderRoll.passeArme); await this.computeRecul(defenderRoll); await this.computeDeteriorationArme(defenderRoll); - await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-parade.html'); + + RdDCombat._deleteDefense(defenderRoll.passeArme); } /* -------------------------------------------- */ @@ -630,7 +646,7 @@ export class RdDCombat { await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-parade.html'); this.removeChatMessageActionsPasseArme(defenderRoll.passeArme); - this._sendMessageDefense(defenderRoll.attackerRoll, { defense: true }); + this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true }); this._storeDefense(defenderRoll); } @@ -691,8 +707,8 @@ export class RdDCombat { /* -------------------------------------------- */ async _onEsquiveNormale(defenderRoll) { console.log("RdDCombat._onEsquiveNormal >>>", defenderRoll); - this._consumeDefense(defenderRoll.passeArme); await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-esquive.html'); + RdDCombat._deleteDefense(defenderRoll.passeArme); } /* -------------------------------------------- */ @@ -702,7 +718,7 @@ export class RdDCombat { await RdDResolutionTable.displayRollData(defenderRoll, this.defender, 'chat-resultat-esquive.html'); this.removeChatMessageActionsPasseArme(defenderRoll.passeArme); - this._sendMessageDefense(defenderRoll.attackerRoll, { defense: true }) + this._sendMessageDefense(defenderRoll.attackerRoll, defenderRoll, { defense: true }) this._storeDefense(defenderRoll); } @@ -792,15 +808,8 @@ export class RdDCombat { defenderTokenId = defenderTokenId || this.defenderTokenId; console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId); - let defenderRoll = this._consumeDefense(attackerRoll.passeArme); - if (!defenderRoll) { - defenderRoll = { - attackerRoll: attackerRoll, - show: {} - }; - } - else if (RdDCombat.isEchecTotal(defenderRoll)) { - // TODO: echec total!!! + let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme); + if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) { this._onEchecTotal(defenderRoll); } @@ -810,12 +819,18 @@ export class RdDCombat { await this.computeRecul(defenderRoll); this.defender.encaisserDommages(attackerRoll, this.attacker); - } else { // Emit message for GM + } else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_encaisser", - data: { attackerId: this.attackerId, defenderTokenId: defenderTokenId } + data: { + attackerId: this.attackerId, + defenderTokenId: defenderTokenId, + attackerRoll: attackerRoll, + gmId: game.users.entities.find(u => u.isGM)?.id, + } }); } + RdDCombat._deleteDefense(attackerRoll.passeArme); } /* -------------------------------------------- */ diff --git a/module/rdd-utility.js b/module/rdd-utility.js index be776021..491f3740 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -635,8 +635,6 @@ export class RdDUtility { static onSocketMesssage(sockmsg) { console.log(">>>>> MSG RECV", sockmsg); switch (sockmsg.msg) { - case "msg_encaisser": - return RdDUtility._handleMsgEncaisser(sockmsg.data); case "msg_gm_chat_message": return ChatUtility.handleGMChatMessage(sockmsg.data); case "msg_sync_time": @@ -749,15 +747,6 @@ export class RdDUtility { }); } - /* -------------------------------------------- */ - static _handleMsgEncaisser(data) { - if (game.user.isGM) { // Seul le GM effectue l'encaissement sur la fiche - let defender = canvas.tokens.get(data.defenderTokenId).actor; - let attacker = data.attackerId ? game.actors.get(data.attackerId) : null; - defender.encaisserDommages(attackerRoll, attacker); - } - } - /* -------------------------------------------- */ static async chatListeners(html) { RdDCombat.registerChatCallbacks(html); diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index e333371e..5c6c1e6d 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -114,7 +114,7 @@