diff --git a/changelog.md b/changelog.md index c5ac1466..baf5946a 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,7 @@ ## 12.0.16 - Le secret d'Astrobazzarh - Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués) - Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs +- Ajout d'une option pour la localisation des blessures ## 12.0.15 - Le messager d'Astrobazzarh - Correction des faces de dés personalisés dice-so-nice diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 4610fe82..02e549d5 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -415,41 +415,40 @@ export class RdDBaseActorReve extends RdDBaseActor { /* -------------------------------------------- */ async encaisser() { await RdDEncaisser.encaisser(this) } - async encaisserDommages(rollData, attacker = undefined, show = undefined) { + async encaisserDommages(rollData, attacker = undefined, attackerToken = undefined, show = undefined) { if (attacker && !await attacker.accorder(this, 'avant-encaissement')) { return; } const armure = await this.computeArmure(rollData); if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) { - await this.encaisserDommagesValidationGR(rollData, armure, attacker?.id, show); + await this.encaisserDommagesValidationGR(rollData, armure, attackerToken, show); } else { - const jet = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE }); - await this.$onEncaissement(jet, show, attacker); + const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE }); + await this.$onEncaissement(jet, show, attackerToken) } } - async encaisserDommagesValidationGR(rollData, armure, attackerId, show) { + async encaisserDommagesValidationGR(rollData, armure, attackerToken, show) { if (!game.user.isGM) { RdDBaseActor.remoteActorCall({ tokenId: this.token?.id, actorId: this.id, method: 'encaisserDommagesValidationGR', - args: [rollData, armure, attackerId, show] - }); + args: [rollData, armure, attackerToken, show] + }) } else { - const attacker = game.actors.get(attackerId); DialogValidationEncaissement.validerEncaissement(this, rollData, armure, - jet => this.$onEncaissement(jet, show, attacker)); + jet => this.$onEncaissement(jet, show, attackerToken)); } } - async $onEncaissement(jet, show, attacker) { - await this.onAppliquerJetEncaissement(jet, attacker); + async $onEncaissement(jet, show, attackerToken) { + await this.onAppliquerJetEncaissement(jet, attackerToken); await this.$afficherEncaissement(jet, show); } - async onAppliquerJetEncaissement(encaissement, attacker) { } + async onAppliquerJetEncaissement(encaissement, attackerToken) { } async $afficherEncaissement(encaissement, show) { foundry.utils.mergeObject(encaissement, { diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 978c27c2..48e5299a 100644 --- a/module/actor/base-actor-sang.js +++ b/module/actor/base-actor-sang.js @@ -89,9 +89,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve { /* -------------------------------------------- */ - async onAppliquerJetEncaissement(encaissement, attacker) { + async onAppliquerJetEncaissement(encaissement, attackerToken) { const santeOrig = foundry.utils.duplicate(this.system.sante); - const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table + const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table const perteVie = await this.santeIncDec("vie", -encaissement.vie); const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique()); @@ -169,7 +169,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { /* -------------------------------------------- */ - async ajouterBlessure(encaissement, attacker = undefined) { + async ajouterBlessure(encaissement, attackerToken = undefined) { if (encaissement.gravite < 0) return; if (encaissement.gravite > 0) { while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) { @@ -181,7 +181,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { } } const endActuelle = this.getEnduranceActuelle(); - const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attacker); + const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken); if (blessure.isCritique()) { encaissement.endurance = endActuelle; } diff --git a/module/actor/entite.js b/module/actor/entite.js index 70bc0577..ff0ad06a 100644 --- a/module/actor/entite.js +++ b/module/actor/entite.js @@ -74,7 +74,7 @@ export class RdDEntite extends RdDBaseActorReve { return [STATUSES.StatusComma].includes(effectId); } - async onAppliquerJetEncaissement(encaissement, attacker) { + async onAppliquerJetEncaissement(encaissement, attackerToken) { const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance); foundry.utils.mergeObject(encaissement, { resteEndurance: perteEndurance.newValue, diff --git a/module/dialog-validation-encaissement.js b/module/dialog-validation-encaissement.js index d4c41f61..c0a74d85 100644 --- a/module/dialog-validation-encaissement.js +++ b/module/dialog-validation-encaissement.js @@ -8,14 +8,13 @@ import { RdDUtility } from "./rdd-utility.js"; export class DialogValidationEncaissement extends Dialog { static async validerEncaissement(actor, rollData, armure, onEncaisser) { - let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE }); + const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE }); const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', { actor: actor, rollData: rollData, encaissement: encaissement }); - const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser); - dialog.render(true); + new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true); } /* -------------------------------------------- */ @@ -56,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog { this.html = html; this.html.find('input.encaissement-roll-result').keyup(async event => { this.forceDiceResult.total = event.currentTarget.value; - this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult}); + this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult}); this.html.find('label.encaissement-total').text(this.encaissement.total); this.html.find('label.encaissement-blessure').text(this.encaissement.blessures) }); } async onValider() { - this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult}); + this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult}); this.onEncaisser(this.encaissement) } } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index e3e404c0..4de3fb5b 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -496,24 +496,24 @@ export class RdDCombat { /* -------------------------------------------- */ static onMsgEncaisser(msg) { - let defender = canvas.tokens.get(msg.defenderTokenId).actor; if (Misc.isOwnerPlayerOrUniqueConnectedGM()) { let attackerRoll = msg.attackerRoll; let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined; + let defender = canvas.tokens.get(msg.defenderToken.id).actor; - defender.encaisserDommages(attackerRoll, attacker); - const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerTokenId, msg.defenderTokenId); + defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken); + const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id); rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme); } } /* -------------------------------------------- */ static onMsgDefense(msg) { - let defenderToken = canvas.tokens.get(msg.defenderTokenId); + let defenderToken = canvas.tokens.get(msg.defenderToken.id) if (defenderToken && Misc.isFirstConnectedGM()) { - const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerTokenId, msg.defenderTokenId); - rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme); - rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll); + const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) + rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme) + rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll) } } @@ -568,19 +568,21 @@ export class RdDCombat { this.defenderId = this.defender.id this.attackerTokenId = attackerTokenId this.defenderTokenId = defenderTokenId + this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId) + this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, target) } - _extractDefenderTokenData() { - if (this.target) { - return Targets.extractTokenData(this.target) + static $extractAttackerTokenData(attacker, attackerTokenId) { + const token = canvas.tokens.get(attackerTokenId); + return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(attackerTokenId, attacker) + } + + static $extractDefenderTokenData(defender, defenderTokenId, target) { + if (target) { + return Targets.extractTokenData(target) } - const token = canvas.tokens.get(this.defenderTokenId); - return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(this.defenderTokenId, this.defender) - } - - _extractAttackerTokenData(){ - const token = canvas.tokens.get(this.attackerTokenId); - return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(this.attackerTokenId, this.attacker) + const token = canvas.tokens.get(defenderTokenId); + return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender) } @@ -590,7 +592,6 @@ export class RdDCombat { 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; const competence = event.currentTarget.attributes['data-competence']?.value; @@ -600,7 +601,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, defenderRoll, defenderTokenId); + case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll); case '#echec-total-attaque': return this._onEchecTotal(attackerRoll); case '#appel-chance-attaque': return this.attacker.rollAppelChance( @@ -717,7 +718,7 @@ export class RdDCombat { }) } else { - const defenderToken = canvas.tokens.get(this.defenderTokenId); + const defenderToken = canvas.tokens.get(this.defenderTokenId) const dist = this.distance(_token, defenderToken) const isVisible = this.isVisible(_token, defenderToken) const portee = this._ajustementPortee(dist, rollData.arme) @@ -813,16 +814,15 @@ export class RdDCombat { /* -------------------------------------------- */ _prepareAttaque(competence, arme) { - const sourceToken = this._extractAttackerTokenData(); let rollData = { - alias: sourceToken.name, + alias: this.attackerToken.name, passeArme: foundry.utils.randomID(16), mortalite: arme?.system.mortalite, competence: competence, surprise: this.attacker.getSurprise(true), surpriseDefenseur: this.defender.getSurprise(true), - sourceToken: sourceToken, - targetToken: this._extractDefenderTokenData(), + sourceToken: this.attackerToken, + targetToken: this.defenderToken, essais: {} }; @@ -867,10 +867,10 @@ export class RdDCombat { alias: this.attacker.name, whisper: ChatUtility.getOwners(this.attacker), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', { - alias: this.attacker.name, + alias: this.attackerToken.name, attackerId: this.attackerId, - attackerToken: this._extractAttackerTokenData(), - defenderToken: this._extractDefenderTokenData(), + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, isForce: isForce, isFinesse: isFinesse, isRapide: isRapide, @@ -920,7 +920,6 @@ export class RdDCombat { const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive()) esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0); - const paramChatDefense = { passeArme: attackerRoll.passeArme, essais: attackerRoll.essais, @@ -929,8 +928,8 @@ export class RdDCombat { attacker: this.attacker, attackerId: this.attackerId, esquives: esquives, - attackerToken: this._extractAttackerTokenData(), - defenderToken: this._extractDefenderTokenData(), + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps, armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme), diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0, @@ -954,7 +953,7 @@ export class RdDCombat { 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, + alias: this.attackerToken.name, whisper: ChatUtility.getOwners(this.defender), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense), }); @@ -968,9 +967,9 @@ export class RdDCombat { game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense", data: { attackerId: this.attacker?.id, - attackerTokenId: this.attackerTokenId, + attackerToken: this.attackerToken, defenderId: this.defender?.id, - defenderTokenId: this.defenderTokenId, + defenderToken: this.defenderToken, defenderRoll: defenderRoll, paramChatDefense: paramChatDefense, rollMode: true @@ -1003,8 +1002,8 @@ export class RdDCombat { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { attackerId: this.attackerId, attacker: this.attacker, - attackerToken: this._extractAttackerTokenData(), - defenderToken: this._extractDefenderTokenData(), + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, essais: attackerRoll.essais }) }); @@ -1075,13 +1074,12 @@ export class RdDCombat { /* -------------------------------------------- */ _prepareParade(attackerRoll, armeParade, competenceParade) { - const defenderToken = this._extractDefenderTokenData() let defenderRoll = { - alias: defenderToken?.name, + alias: this.defenderToken?.name, passeArme: attackerRoll.passeArme, diffLibre: attackerRoll.diffLibre, - attackerToken: this._extractAttackerTokenData(), - defenderToken: defenderToken, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, attackerRoll: attackerRoll, competence: this.defender.getCompetence(competenceParade), arme: armeParade, @@ -1160,13 +1158,12 @@ export class RdDCombat { /* -------------------------------------------- */ _prepareEsquive(attackerRoll, competence) { - const defenderToken= this._extractDefenderTokenData() let rollData = { - alias: defenderToken?.name, + alias: this.defenderToken?.name, passeArme: attackerRoll.passeArme, diffLibre: attackerRoll.diffLibre, - attackerToken: this._extractAttackerTokenData(), - defenderToken: defenderToken, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, attackerRoll: attackerRoll, competence: competence, surprise: this.defender.getSurprise(true), @@ -1308,9 +1305,8 @@ export class RdDCombat { } /* -------------------------------------------- */ - async encaisser(attackerRoll, defenderRoll, defenderTokenId) { - defenderTokenId = defenderTokenId || this.defenderTokenId; - console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId); + async encaisser(attackerRoll, defenderRoll) { + console.log("RdDCombat.encaisser >>>", attackerRoll, defenderRoll); if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) { this._onEchecTotal(defenderRoll); @@ -1318,19 +1314,19 @@ export class RdDCombat { if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) { attackerRoll.attackerId = this.attackerId; - attackerRoll.defenderTokenId = defenderTokenId; + attackerRoll.defenderTokenId = this.defenderToken.id; await this.computeRecul(defenderRoll); - await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show); + await this.defender.encaisserDommages(attackerRoll, this.attacker, this.attackerToken, defenderRoll?.show); } 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_SOCKET_ID, { msg: "msg_encaisser", data: { attackerId: this.attackerId, - attackerTokenId: this.attackerTokenId, - defenderTokenId: defenderTokenId, - attackerRoll: attackerRoll + attackerRoll: attackerRoll, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken } }); } @@ -1354,12 +1350,12 @@ export class RdDCombat { } await ChatMessage.create({ content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs`, formData), - alias: actor.name + alias: token.name ?? actor.name }) await ChatMessage.create({ content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData), whisper: ChatUtility.getOwners(actor), - alias: actor.name + alias: token.name ?? actor.name }); } } \ No newline at end of file diff --git a/module/rdd-roll-encaisser.js b/module/rdd-roll-encaisser.js index a9fc2d84..14748a6e 100644 --- a/module/rdd-roll-encaisser.js +++ b/module/rdd-roll-encaisser.js @@ -72,6 +72,6 @@ export class RdDEncaisser extends Dialog { encaisserSpecial: this.encaisserSpecial, mortalite: mortalite } - }); + }) } } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 2153bfa7..70950c74 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -563,14 +563,14 @@ export class RdDUtility { } /* -------------------------------------------- */ - static async jetEncaissement(rollData, armure, options = { showDice: HIDE_DICE }) { + static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) { const diff = Math.abs(rollData.diffLibre); let formula = RdDUtility.formuleEncaissement(diff, options) const roll = await RdDDice.roll(formula, options); RdDUtility.remplaceDeMinParDifficulte(roll, diff, options); - return await RdDUtility.prepareEncaissement(rollData, roll, armure); + return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure); } static remplaceDeMinParDifficulte(roll, diff, options) { @@ -602,15 +602,20 @@ export class RdDUtility { } /* -------------------------------------------- */ - static async prepareEncaissement(rollData, roll, armure) { + static async prepareEncaissement(actor, rollData, roll, armure) { // La difficulté d'ataque s'ajoute aux dégâts const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0 const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite); const over20 = Math.max(jetTotal - 20, 0); - encaissement.dmg = rollData.dmg; - encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(this.type); - encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'; + encaissement.dmg = rollData.dmg + if (ReglesOptionnelles.isUsing('localisation-aleatoire')){ + encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type) + encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;' + } + else{ + encaissement.dmg.loc = {label:''} + } encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre encaissement.roll = roll; encaissement.armure = armure; diff --git a/module/settings/regles-optionnelles.js b/module/settings/regles-optionnelles.js index 3eac1e2d..02c2cd60 100644 --- a/module/settings/regles-optionnelles.js +++ b/module/settings/regles-optionnelles.js @@ -11,6 +11,7 @@ const listeReglesOptionnelles = [ { group: 'Récupération', name: 'recuperation-moral', descr: "Le moral revient vers 0 durant Château Dormant"}, + { group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" }, { group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" }, { group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" }, { group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },