diff --git a/changelog.md b/changelog.md index ad50c309..b696159d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,25 @@ # 12.0 +## 12.0.18 - A la barbe d'Astrobazzarh +- Améliorations sur la feuille de PNJ simplifiée + - Ajout du portrait + - Ajout du corps à corps + - Affichage du niveau d'esquive + - Un clic sur l'initiative permet de lancer l'initiative + - les boutons +/- pour la vie, l'endurance et la fatigue changent si on est à la valeur normale + - un clic sur l'endurance effectue un jet d'endurance +- Fix + - les achats des commerces sont de nouveau possibles + - la commande /astro fonctionne de nouveau + - le nombre d'utilisations d'items est réinitialisé à chaque round et fin de combat + - la difficulté de parade pour les armes à distances n'est plus indiquée + - les propositions d'armes de parade sont corrigées +- Ajout d'un indicateur pour les armes de parade nécessitant une significative + +## 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 - Les messages de maladies ne sont plus publics diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 5e2ff8b6..1b2f7abf 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -220,18 +220,18 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { // Points de reve actuel this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true)) this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) - this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)))) + + this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence')) // Initiative pour l'arme - this.html.find('.arme-initiative a').click(async event => { - let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id); + this.html.find('.roll-init-arme').click(async event => { + let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id) if (combatant) { - let action = this._getEventArmeCombat(event); - RdDCombatManager.rollInitiativeAction(combatant._id, action); + RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event)); } else { ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat."); } - }); + }) // Display TMR this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal")) diff --git a/module/actor.js b/module/actor.js index 73c21990..75eec4e8 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1548,7 +1548,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { - if (!Misc.firstConnectedGM()){ + if (!Misc.isFirstConnectedGM()){ return } hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) @@ -2615,7 +2615,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async resetItemUse() { - await this.setFlag(SYSTEM_RDD, 'itemUse', {}); + await this.unsetFlag(SYSTEM_RDD, 'itemUse'); } /* -------------------------------------------- */ @@ -3011,7 +3011,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async onCreateOwnedDraconique(item, options, id) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { let draconique = Draconique.all().find(it => it.match(item)); if (draconique) { await draconique.onActorCreateOwned(this, item) @@ -3023,7 +3023,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async onDeleteOwnedDraconique(item, options, id) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { let draconique = Draconique.all().find(it => it.match(item)); if (draconique) { await draconique.onActorDeleteOwned(this, item) @@ -3033,7 +3033,7 @@ export class RdDActor extends RdDBaseActorSang { /* -------------------------------------------- */ async onDeleteOwnedCaseTmr(item, options, id) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { let draconique = Draconique.all().find(it => it.isCase(item)); if (draconique) { await draconique.onActorDeleteCaseTmr(this, item) diff --git a/module/actor/base-actor-reve.js b/module/actor/base-actor-reve.js index 06b560f5..53b5604b 100644 --- a/module/actor/base-actor-reve.js +++ b/module/actor/base-actor-reve.js @@ -78,8 +78,10 @@ export class RdDBaseActorReve extends RdDBaseActor { } async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } } isDead() { return false } + isSonne() { return false } blessuresASoigner() { return [] } getEtatGeneral(options = { ethylisme: false }) { return 0 } + isActorCombat() { return true } async computeArmure(attackerRoll) { return this.getProtectionNaturelle() } async remiseANeuf() { } @@ -327,14 +329,15 @@ export class RdDBaseActorReve extends RdDBaseActor { const competence = this.getCompetence(idOrName); let rollData = { carac: this.system.carac, competence: competence, arme: options.arme } if (competence.type == ITEM_TYPES.competencecreature) { + const token = RdDUtility.getSelectedToken(this) const arme = RdDItemCompetenceCreature.armeCreature(competence) if (arme && options.tryTarget && Targets.hasTargets()) { - Targets.selectOneToken(target => { + Targets.selectOneTargetToken(target => { if (arme.action == "possession") { RdDPossession.onAttaquePossession(target, this, competence) } else { - RdDCombat.rddCombatTarget(target, this).attaque(competence, arme) + RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme) } }); return; @@ -364,7 +367,8 @@ export class RdDBaseActorReve extends RdDBaseActor { * @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession * @returns */ - rollArme(arme, categorieArme = "competence") { + rollArme(arme, categorieArme, token) { + token = token ?? RdDUtility.getSelectedToken(this) const compToUse = this.$getCompetenceArme(arme, categorieArme) if (!RdDItemArme.isArmeUtilisable(arme)) { ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`) @@ -385,7 +389,7 @@ export class RdDBaseActorReve extends RdDBaseActor { return } - Targets.selectOneToken(target => { + Targets.selectOneTargetToken(target => { if (Targets.isTargetEntite(target)) { ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`); return @@ -395,7 +399,7 @@ export class RdDBaseActorReve extends RdDBaseActor { if (competence.isCompetencePossession()) { return RdDPossession.onAttaquePossession(target, this, competence); } - RdDCombat.rddCombatTarget(target, this).attaque(competence, arme); + RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme); }) } @@ -403,58 +407,52 @@ export class RdDBaseActorReve extends RdDBaseActor { return RdDItemArme.getCompetenceArme(arme, competenceName) } - verifierForceMin(item) { - } - /* -------------------------------------------- */ - async resetItemUse() { } - async incDecItemUse(itemId, inc = 1) { } - getItemUse(itemId) { return 0; } + verifierForceMin(item) { } /* -------------------------------------------- */ async encaisser() { await RdDEncaisser.encaisser(this) } - async encaisserDommages(rollData, attacker = undefined, show = undefined) { + async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = 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, show, attackerToken, defenderToken); } 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, defenderToken) } } - async encaisserDommagesValidationGR(rollData, armure, attackerId, show) { + async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) { if (!game.user.isGM) { RdDBaseActor.remoteActorCall({ tokenId: this.token?.id, actorId: this.id, method: 'encaisserDommagesValidationGR', - args: [rollData, armure, attackerId, show] - }); + args: [rollData, armure, show, attackerToken, defenderToken] + }) } else { - const attacker = game.actors.get(attackerId); DialogValidationEncaissement.validerEncaissement(this, rollData, armure, - jet => this.$onEncaissement(jet, show, attacker)); + jet => this.$onEncaissement(jet, show, attackerToken, defenderToken)); } } - async $onEncaissement(jet, show, attacker) { - await this.onAppliquerJetEncaissement(jet, attacker); - await this.$afficherEncaissement(jet, show); + async $onEncaissement(jet, show, attackerToken, defenderToken) { + await this.onAppliquerJetEncaissement(jet, attackerToken); + await this.$afficherEncaissement(jet, show, defenderToken); } - async onAppliquerJetEncaissement(encaissement, attacker) { } + async onAppliquerJetEncaissement(encaissement, attackerToken) { } - async $afficherEncaissement(encaissement, show) { + async $afficherEncaissement(encaissement, show, defenderToken) { foundry.utils.mergeObject(encaissement, { - alias: this.name, + alias: defenderToken?.name ?? this.name, hasPlayerOwner: this.hasPlayerOwner, show: show ?? {} - }); + }, {overwrite: false}); await ChatUtility.createChatWithRollMode( { diff --git a/module/actor/base-actor-sang.js b/module/actor/base-actor-sang.js index 978c27c2..26a58350 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; } @@ -276,11 +276,11 @@ export class RdDBaseActorSang extends RdDBaseActorReve { ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`); return; } - await this.setEffect(STATUSES.StatusStunned, sonne); + await this.setEffect(STATUSES.StatusStunned, sonne) } - getSonne() { - return this.getEffect(STATUSES.StatusStunned); + isSonne() { + return this.getEffect(STATUSES.StatusStunned) } isEffectAllowed(effectId) { return true } diff --git a/module/actor/base-actor.js b/module/actor/base-actor.js index 57fbcb07..7d8b64ab 100644 --- a/module/actor/base-actor.js +++ b/module/actor/base-actor.js @@ -205,11 +205,8 @@ export class RdDBaseActor extends Actor { /* -------------------------------------------- */ async onPreUpdateItem(item, change, options, id) { } - async onCreateItem(item, options, id) { } - async onDeleteItem(item, options, id) { } - async onUpdateActor(update, options, actorId) { } async onTimeChanging(oldTimestamp, newTimestamp) { @@ -218,7 +215,7 @@ export class RdDBaseActor extends Actor { } async creerObjetParMJ(object) { - if (!Misc.isUniqueConnectedGM()) { + if (!Misc.isFirstConnectedGM()) { RdDBaseActor.remoteActorCall({ tokenId: this.token?.id, actorId: this.id, @@ -317,7 +314,7 @@ export class RdDBaseActor extends Actor { RdDAudio.PlayContextAudio("argent"); // Petit son ChatMessage.create({ - whisper: ChatUtility.getOwners(this.name), + whisper: ChatUtility.getOwners(this), content: `Vous avez reçu ${sols} Sols ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` }); } @@ -335,7 +332,7 @@ export class RdDBaseActor extends Actor { ui.notifications.info("Inutile de se vendre à soi-même"); return; } - if (!Misc.isUniqueConnectedGM()) { + if (!Misc.isFirstConnectedGM()) { RdDBaseActor.remoteActorCall({ actorId: achat.vendeurId ?? achat.acheteurId, method: 'achatVente', @@ -708,5 +705,9 @@ export class RdDBaseActor extends Actor { } return undefined } - + async resetItemUse() { } + async incDecItemUse(itemId, inc = 1) { } + getItemUse(itemId) { return 0; } + async finDeRound(options = { terminer: false }) { } + isActorCombat() { return false } } \ No newline at end of file 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/actor/export-scriptarium/mapping.js b/module/actor/export-scriptarium/mapping.js index ffb2b788..8a4cd515 100644 --- a/module/actor/export-scriptarium/mapping.js +++ b/module/actor/export-scriptarium/mapping.js @@ -84,7 +84,7 @@ const MAPPING_BASE = [ { column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) }, { column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value }, { column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value }, - { column: "endurance_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.endurance.value }, + { column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value }, { column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) }, { column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) }, { column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) }, @@ -140,16 +140,15 @@ export class Mapping { static prepareArmes(actor) { const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme) - return armes.map(arme => - [ - arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined, - arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined, - !(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined, - arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined, - arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined - ] - .filter(it => it != undefined) - ).reduce((a, b) => a.concat(b), []) + RdDItemArme.ajoutCorpsACorps(armes, actor) + return armes.map(arme => [ + arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined, + arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined, + !(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined, + arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined, + arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined] + .filter(it => it != undefined)) + .reduce((a, b) => a.concat(b), []) } static prepareArme(actor, arme, maniement) { @@ -158,27 +157,35 @@ export class Mapping { if (RdDItemCompetence.isNiveauBase(competence)) { return undefined } - const dmgArme = RdDItemArme.dommagesReels(arme, maniement) - const dommages = dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme) const categorie = Mapping.complementCategorie(arme, maniement) + const dommages = Mapping.dommagesArme(actor, arme, maniement) return { name: arme.name + categorie, niveau: Misc.toSignedString(competence.system.niveau), init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau, - dommages: Misc.toSignedString(dommages), + dommages: dommages, competence: competence, arme: arme } } + static dommagesArme(actor, arme, maniement){ + const dmgArme = RdDItemArme.dommagesReels(arme, maniement) + const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme)) + switch(arme.system.mortalite) { + case 'non-mortel': return `(${dommages})` + case 'empoignade': return '-' + } + return dommages + } static complementCategorie(arme, maniement) { switch (maniement) { - case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer||arme.system.tir) ? ' mêlée': '' - case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer||arme.system.tir) ? ' mêlée': '' + case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : '' + case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : '' case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : '' case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : '' } - return '' + return '' } static calculBaseInit(actor, categorie) { @@ -327,7 +334,8 @@ export class Mapping { const txtByCategories = Object.values(byCategories) .map(it => it.competencesParNiveau) .map(byNiveau => { - const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending()) + const niveaux = Object.keys(byNiveau) + .map(it => Number(it)).sort(Misc.ascending()) if (niveaux.length == 0) { return '' } diff --git a/module/chat-utility.js b/module/chat-utility.js index 76792c86..5f515ce8 100644 --- a/module/chat-utility.js +++ b/module/chat-utility.js @@ -49,7 +49,7 @@ export class ChatUtility { /* -------------------------------------------- */ static onRemoveMessages(socketData) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { if (socketData.part) { const toDelete = game.messages.filter(it => it.content.includes(socketData.part)); toDelete.forEach(it => it.delete()); @@ -63,7 +63,7 @@ export class ChatUtility { /* -------------------------------------------- */ static removeMessages(socketData) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { ChatUtility.onRemoveMessages(socketData); } else { @@ -161,7 +161,7 @@ export class ChatUtility { /* -------------------------------------------- */ static handleGMChatMessage(socketData) { console.log("blindMessageToGM", socketData); - if (Misc.firstConnectedGM()) { + if (Misc.isFirstConnectedGM()) { ChatMessage.create({ user: game.user.id, whisper: ChatUtility.getGMs(), 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/item-arme.js b/module/item-arme.js index 25cb4dd4..86255aa6 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -81,37 +81,59 @@ export class RdDItemArme extends Item { /* -------------------------------------------- */ static getCategorieParade(armeData) { if (armeData.system.categorie_parade) { - return armeData.system.categorie_parade; + return armeData.system.categorie_parade } // pour compatibilité avec des personnages existants if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') { - return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : ''); + return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '') } if (!armeData.type.match(/arme|competencecreature/)) { - return ''; + return '' } if (armeData.system.competence == undefined) { return ITEM_TYPES.competencecreature; } let compname = armeData.system.competence.toLowerCase(); - if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return ''; + if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) { + return '' + } - if (compname.match('hache')) return 'haches'; - if (compname.match('hast')) return 'hast'; - if (compname.match('lance')) return 'lances'; - if (compname.match('bouclier')) return 'boucliers'; - if (compname.match('masse')) return 'masses'; + if (compname.match('hache')) return 'haches' + if (compname.match('hast')) return 'hast' + if (compname.match('lance')) return 'lances' + if (compname.match('bouclier')) return 'boucliers' + if (compname.match('masse')) return 'masses' if (compname.match('epée') || compname.match('épée')) { if (armeData.name.toLowerCase().match(/(gnome)/)) - return 'epees-courtes'; + return 'epees-courtes' if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/)) - return 'epees-longues'; - return 'epees-lourdes'; + return 'epees-longues' + return 'epees-lourdes' } if (compname.match('dague')) { - return 'dagues'; + return 'dagues' + } + return 'sans-armes' + } + + static defenseArmeParade(armeAttaque, armeParade) { + const defCategory = RdDItemArme.getCategorieParade(armeParade) + if (defCategory == 'bouclier') { + return 'norm' + } + if (armeAttaque.system.competence.toLowerCase().match(/(fléau)/)) { + return '' + } + if (armeParade.system.tir) { + return '' + } + const attCategory = RdDItemArme.getCategorieParade(armeAttaque) + switch (attCategory) { + case 'armes-naturelles': case 'sans-armes': + return defCategory == 'sans-armes' ? 'norm' : '' + default: + return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm' } - return 'sans-armes'; } /* -------------------------------------------- */ @@ -120,8 +142,8 @@ export class RdDItemArme extends Item { return false; } // categories d'armes à la parade (cf. page 115 ) - let attCategory = RdDItemArme.getCategorieParade(armeAttaque); - let defCategory = RdDItemArme.getCategorieParade(armeParade); + const attCategory = RdDItemArme.getCategorieParade(armeAttaque) + const defCategory = RdDItemArme.getCategorieParade(armeParade) // bouclier et mêmes catégorie: peuvent se parer sans difficulté if (defCategory == 'boucliers') { return false; diff --git a/module/item-competence.js b/module/item-competence.js index 25c6659d..f09ca6a8 100644 --- a/module/item-competence.js +++ b/module/item-competence.js @@ -190,7 +190,7 @@ export class RdDItemCompetence extends Item { /* -------------------------------------------- */ static isNiveauBase(item) { - return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type); + return item.system.niveau == undefined || Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type); } /* -------------------------------------------- */ diff --git a/module/item-sheet.js b/module/item-sheet.js index 93e3a6c5..dd58ab6f 100644 --- a/module/item-sheet.js +++ b/module/item-sheet.js @@ -267,10 +267,17 @@ export class RdDItemSheet extends ItemSheet { /* -------------------------------------------- */ /** @override */ _updateObject(event, formData) { - if (this.item.type == 'sort') { - // Données de bonus de cases ? - formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue); + switch (this.item.type) { + case ITEM_TYPES.sort: + // Données de bonus de cases ? + formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue) + break + case ITEM_TYPES.competence: + if (formData['system.niveau'] == undefined) { + formData['system.niveau'] = formData['system.base'] + } } + return this.item.update(formData); } diff --git a/module/item/blessure.js b/module/item/blessure.js index 14c63724..b527249b 100644 --- a/module/item/blessure.js +++ b/module/item/blessure.js @@ -67,7 +67,7 @@ export class RdDItemBlessure extends RdDItem { } - static async createBlessure(actor, gravite, localisation = '', attacker) { + static async createBlessure(actor, gravite, localisation = '', attackerToken) { const definition = RdDItemBlessure.getDefinition(gravite) const blessure = { name: definition.label, @@ -77,7 +77,7 @@ export class RdDItemBlessure extends RdDItem { gravite: gravite, difficulte: - gravite, localisation: localisation, - origine: attacker?.name ?? "" + origine: attackerToken?.name ?? "" } } const blessures = await actor.createEmbeddedDocuments('Item', [blessure]) diff --git a/module/misc.js b/module/misc.js index c22fe21e..76a93ff3 100644 --- a/module/misc.js +++ b/module/misc.js @@ -139,7 +139,7 @@ export class Misc { } static join(params, separator = '') { - return params?.reduce(Misc.joining(separator)) ?? ''; + return (!params || params.length == 0) ? '' : params.reduce(Misc.joining(separator)) } static joining(separator = '') { @@ -195,7 +195,7 @@ export class Misc { return document } } - else if (Misc.isUniqueConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) { + else if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) { return document } return undefined @@ -206,14 +206,14 @@ export class Misc { } static isOwnerPlayerOrUniqueConnectedGM(actor) { - return Misc.isOwnerPlayer(actor) ?? Misc.isUniqueConnectedGM(); + return Misc.isOwnerPlayer(actor) ?? Misc.isFirstConnectedGM(); } /** * @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id */ - static isUniqueConnectedGM() { - return game.user.id == Misc.firstConnectedGMId(); + static isFirstConnectedGM() { + return game.user == Misc.firstConnectedGM(); } static firstConnectedGMId() { diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 68947438..35b6bf9f 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -42,7 +42,8 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ Hooks.on("getCombatTrackerEntryContext", (html, options) => { RdDCombatManager.pushInitiativeOptions(html, options); }); Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) }); - Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() }); + Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() }) + Hooks.on("deleteCombat", (combat, html, id) => { combat.onDeleteCombat() }) } /* -------------------------------------------- */ @@ -53,7 +54,7 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ async onPreDeleteCombat() { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { await this.finDeRound({ terminer: true }) ChatUtility.removeChatMessageContaining(`
`) game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined) @@ -61,20 +62,31 @@ export class RdDCombatManager extends Combat { RdDEmpoignade.deleteAllEmpoignades() } } - - /* -------------------------------------------- */ - async finDeRound(options = { terminer: false }) { - this.turns.forEach(turn => turn.actor.resetItemUse()); - - for (let combatant of this.combatants) { - if (combatant.actor) { - await combatant.actor.finDeRound(options); - } - else { - ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`) + async onDeleteCombat() { + if (Misc.isFirstConnectedGM()) { + if (game.combats.size <= 1) { + game.actors.forEach(actor => actor.resetItemUse()) } } } + + /* -------------------------------------------- */ + async finDeRound(options = { terminer: false }) { + + for (let combatant of this.combatants) { + if (!combatant.actor) { + ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`) + } + else if (!combatant.actor.isActorCombat()) { + ui.notifications.warn(`Le combatant ${combatant.name} ne peut pas combattre!`) + } + else { + await combatant.actor.finDeRound(options) + await combatant.actor.resetItemUse() + } + } + } + static calculAjustementInit(actor, arme) { const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0 const etatGeneral = actor.getEtatGeneral() ?? 0 @@ -125,7 +137,6 @@ export class RdDCombatManager extends Combat { } } } - //console.log("Combatat", c); const roll = combatant.getInitiativeRoll(rollFormula); if (!roll.total) { await roll.evaluate(); @@ -236,29 +247,12 @@ export class RdDCombatManager extends Combat { return attaque; } - static listActionsCreature(competences) { - return competences - .filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) - .map(it => RdDItemCompetenceCreature.armeCreature(it)) - .filter(it => it != undefined); - } - - static listActionsPossessions(actor) { - return RdDCombatManager._indexActions(actor.getPossessions().map(p => { - return { - name: p.name, - action: 'possession', - system: { - competence: p.name, - possessionid: p.system.possessionid, - } - } - })); - } - /* -------------------------------------------- */ static listActionsCombat(combatant) { const actor = combatant.actor; + if (!actor.isActorCombat()) { + return + } let actions = RdDCombatManager.listActionsPossessions(actor); if (actions.length > 0) { return actions; @@ -281,6 +275,26 @@ export class RdDCombatManager extends Combat { return RdDCombatManager._indexActions(actions); } + static listActionsCreature(competences) { + return competences + .filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) + .map(it => RdDItemCompetenceCreature.armeCreature(it)) + .filter(it => it != undefined); + } + + static listActionsPossessions(actor) { + return RdDCombatManager._indexActions(actor.getPossessions().map(p => { + return { + name: p.name, + action: 'possession', + system: { + competence: p.name, + possessionid: p.system.possessionid, + } + } + })); + } + static _indexActions(actions) { for (let index = 0; index < actions.length; index++) { actions[index].index = index; @@ -291,7 +305,7 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ static processPremierRoundInit() { // Check if we have the whole init ! - if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) { + if (Misc.isFirstConnectedGM() && game.combat.current.round == 1) { let initMissing = game.combat.combatants.find(it => !it.initiative); if (!initMissing) { // Premier round ! for (let combatant of game.combat.combatants) { @@ -454,11 +468,11 @@ export class RdDCombat { /* -------------------------------------------- */ static combatNouveauTour(combat) { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId); if (turn?.actor) { - RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token.id); // TODO Playaudio for player?? + RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token); } } } @@ -469,52 +483,51 @@ export class RdDCombat { } /* -------------------------------------------- */ - static rddCombatTarget(target, attacker) { - const defender = target?.actor; - const defenderTokenId = target?.id; - return new RdDCombat(attacker, defender, defenderTokenId, target) + static rddCombatTarget(target, attacker, attackerToken) { + return new RdDCombat(attacker, attackerToken?.id, target?.actor, target?.id, target) } /* -------------------------------------------- */ - static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) { - const attacker = game.actors.get(attackerId); - let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined; + static rddCombatForAttackerAndDefender(attackerId, attackerTokenId, defenderTokenId) { + const attacker = game.actors.get(attackerId) + const defenderToken = defenderTokenId ? canvas.tokens.get(defenderTokenId) : undefined + let defender = defenderToken?.actor; let target = undefined if (!defenderTokenId || !defender) { console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`); target = Targets.getTarget() if (!target) { - return; + return } defenderTokenId = target.id; defender = target.actor; if (!defenderTokenId || !defender) { - return; + return } } - return new RdDCombat(attacker, defender, defenderTokenId, target) + return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target) } /* -------------------------------------------- */ 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.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); - if (defenderToken && Misc.isUniqueConnectedGM()) { - const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); - rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme); - rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll); + let defenderToken = canvas.tokens.get(msg.defenderToken.id) + if (defenderToken && Misc.isFirstConnectedGM()) { + const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) + rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme) + rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll) } } @@ -545,6 +558,7 @@ export class RdDCombat { html.on("click", button, event => { const rddCombat = RdDCombat.rddCombatForAttackerAndDefender( event.currentTarget.attributes['data-attackerId']?.value, + event.currentTarget.attributes['data-attackerTokenId']?.value, event.currentTarget.attributes['data-defenderTokenId']?.value); if (rddCombat) { rddCombat.onEvent(button, event); @@ -560,22 +574,38 @@ export class RdDCombat { } /* -------------------------------------------- */ - constructor(attacker, defender, defenderTokenId, target) { + constructor(attacker, attackerTokenId, defender, defenderTokenId, target) { this.attacker = attacker this.defender = defender this.target = target this.attackerId = this.attacker.id this.defenderId = this.defender.id + this.attackerTokenId = attackerTokenId this.defenderTokenId = defenderTokenId + this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId) + this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, 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(defenderTokenId); + return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender) + } + + /* -------------------------------------------- */ async onEvent(button, event) { 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; const competence = event.currentTarget.attributes['data-competence']?.value; @@ -585,7 +615,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( @@ -702,7 +732,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) @@ -769,7 +799,7 @@ export class RdDCombat { } RdDEmpoignade.checkEmpoignadeEnCours(this.attacker) - let rollData = this._prepareAttaque(competence, arme); + let rollData = this._prepareAttaque(competence, arme) console.log("RdDCombat.attaque >>>", rollData); if (arme) { this.attacker.verifierForceMin(arme); @@ -795,15 +825,18 @@ export class RdDCombat { dialog.render(true); } + /* -------------------------------------------- */ _prepareAttaque(competence, arme) { let rollData = { + 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), - targetToken: Targets.extractTokenData(this.target), + sourceToken: this.attackerToken, + targetToken: this.defenderToken, essais: {} }; @@ -848,9 +881,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, - defenderTokenId: this.defenderTokenId, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, isForce: isForce, isFinesse: isFinesse, isRapide: isRapide, @@ -867,7 +901,7 @@ export class RdDCombat { attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite()); let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} } attackerRoll.show = { - cible: this.target ? this.defender.name : 'la cible', + cible: this.defenderToken?.name ?? 'la cible', isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge') } await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html'); @@ -898,7 +932,7 @@ export class RdDCombat { // # utilisation esquive const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) }); const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive()) - esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0); + esquives.forEach(e => e.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0); const paramChatDefense = { passeArme: attackerRoll.passeArme, @@ -908,7 +942,8 @@ export class RdDCombat { attacker: this.attacker, attackerId: this.attackerId, esquives: esquives, - defenderTokenId: this.defenderTokenId, + 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, @@ -919,7 +954,7 @@ export class RdDCombat { dmg: attackerRoll.dmg, }; - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { await this._chatMessageDefense(paramChatDefense, defenderRoll); } else { @@ -932,7 +967,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), }); @@ -946,8 +981,9 @@ export class RdDCombat { game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_defense", data: { attackerId: this.attacker?.id, + attackerToken: this.attackerToken, defenderId: this.defender?.id, - defenderTokenId: this.defenderTokenId, + defenderToken: this.defenderToken, defenderRoll: defenderRoll, paramChatDefense: paramChatDefense, rollMode: true @@ -956,20 +992,21 @@ export class RdDCombat { } /* -------------------------------------------- */ - _filterArmesParade(defender, competence) { - let items = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it)) - items.forEach(item => item.system.nbUsage = defender.getItemUse(item.id)); // Ajout du # d'utilisation ce round + _filterArmesParade(defender, competence, arme) { + let defenses = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it)) + defenses = foundry.utils.duplicate(defenses) + defenses.forEach(armeDefense => { + // Ajout du # d'utilisation ce round + armeDefense.nbUsage = defender.getItemUse(armeDefense.id) + armeDefense.typeParade = RdDItemArme.defenseArmeParade(arme, armeDefense) + }) switch (competence.system.categorie) { case 'tir': case 'lancer': - return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers') + return defenses.filter(armeDefense => RdDItemArme.getCategorieParade(armeDefense) == 'boucliers') default: - // Le fléau ne peut être paré qu’au bouclier p115 - if (competence.name == "Fléau") { - return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers') - } - return items.filter(item => RdDItemArme.getCategorieParade(item)); + return defenses.filter(armeDefense => armeDefense.typeParade != '') } } @@ -980,7 +1017,8 @@ export class RdDCombat { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { attackerId: this.attackerId, attacker: this.attacker, - defenderTokenId: this.defenderTokenId, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, essais: attackerRoll.essais }) }); @@ -1052,8 +1090,11 @@ export class RdDCombat { /* -------------------------------------------- */ _prepareParade(attackerRoll, armeParade, competenceParade) { let defenderRoll = { + alias: this.defenderToken?.name, passeArme: attackerRoll.passeArme, diffLibre: attackerRoll.diffLibre, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, attackerRoll: attackerRoll, competence: this.defender.getCompetence(competenceParade), arme: armeParade, @@ -1133,8 +1174,11 @@ export class RdDCombat { /* -------------------------------------------- */ _prepareEsquive(attackerRoll, competence) { let rollData = { + alias: this.defenderToken?.name, passeArme: attackerRoll.passeArme, diffLibre: attackerRoll.diffLibre, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken, attackerRoll: attackerRoll, competence: competence, surprise: this.defender.getSurprise(true), @@ -1276,9 +1320,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); @@ -1286,18 +1329,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, defenderRoll?.show, this.attackerToken, this.defenderToken); } 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, - defenderTokenId: defenderTokenId, - attackerRoll: attackerRoll + attackerRoll: attackerRoll, + attackerToken: this.attackerToken, + defenderToken: this.defenderToken } }); } @@ -1305,28 +1349,31 @@ export class RdDCombat { } /* -------------------------------------------- */ - static async displayActorCombatStatus(combat, actor, tokenId) { + static async displayActorCombatStatus(combat, actor, token) { + if (!actor?.isActorCombat()) { + return + } let formData = { combatId: combat._id, - alias: actor.name, + alias: token.name ?? actor.name, etatGeneral: actor.getEtatGeneral(), - isSonne: actor.getSonne(), + isSonne: actor.isSonne(), blessuresStatus: actor.computeResumeBlessure(), SConst: actor.getSConst(), actorId: actor.id, actor: actor, - tokenId: tokenId, + tokenId: token.id, isGrave: actor.countBlessures(it => it.isGrave()) > 0, isCritique: actor.countBlessures(it => it.isCritique()) > 0 } 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-main.js b/module/rdd-main.js index 85331625..497fd5f3 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -280,7 +280,7 @@ export class SystemReveDeDragon { /* Foundry VTT Initialization */ /* -------------------------------------------- */ game.system.rdd.calendrier = new RdDCalendrier() - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { new Migrations().migrate() this.messageDeBienvenue() import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => { 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-token-hud.js b/module/rdd-token-hud.js index 0cdf7adf..a230f8ee 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -37,7 +37,7 @@ export class RdDTokenHud { // initiative await RdDTokenHud.addExtensionHudInit(html, combatant, actions); // combat - await RdDTokenHud.addExtensionHudCombat(html, combatant, actions); + await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions); } @@ -68,8 +68,8 @@ export class RdDTokenHud { }); } - static async addExtensionHudCombat(html, combatant, actions) { - const hudData = { combatant, actions, commandes: [] }; + static async addExtensionHudCombat(html, combatant, token, actions) { + const hudData = { combatant, token, actions, commandes: [] }; const controlIconTarget = html.find('.control-icon[data-action=target]'); await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData, (event) => { @@ -80,7 +80,7 @@ export class RdDTokenHud { combatant.actor.conjurerPossession(possession); } else { - combatant.actor.rollArme(action); + combatant.actor.rollArme(action, 'competence', token) } }); } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 20b10526..59bc9809 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; @@ -741,6 +746,15 @@ export class RdDUtility { return undefined; } + static getSelectedToken(actor) { + if (canvas.tokens.controlled.length > 0) { + const tokens = canvas.tokens.controlled + .filter(it => it.actor.id == actor.id) + return tokens[0] + } + return undefined + } + static getSelectedActor(msgPlayer = undefined) { if (canvas.tokens.controlled.length == 1) { let token = canvas.tokens.controlled[0]; @@ -867,10 +881,10 @@ export class RdDUtility { /* -------------------------------------------- */ static afficherHeuresChanceMalchance(heureNaissance) { if (game.user.isGM) { - const heure = RdDTimestamp.findHeure(heureNaissance - 1); + const heure = RdDTimestamp.findHeure(heureNaissance) if (heureNaissance && heure) { - let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance); - const current = game.system.rdd.calendrier.heureCourante(); + const ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance) + const current = game.system.rdd.calendrier.heureCourante() ChatMessage.create({ content: `A l'heure de ${current.label}, le modificateur de Chance/Malchance est de ${Misc.toSignedString(ajustement)} pour l'heure de naissance ${heure.label}.`, whisper: ChatUtility.getGMs() 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" }, diff --git a/module/sommeil/app-astrologie.js b/module/sommeil/app-astrologie.js index 0e33a748..e8727294 100644 --- a/module/sommeil/app-astrologie.js +++ b/module/sommeil/app-astrologie.js @@ -186,7 +186,7 @@ export class AppAstrologie extends Application { date: this.html.find('[name="joursAstrologie"]').val(), userId: game.user.id } - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { game.system.rdd.calendrier.requestNombreAstral(socketData); } else { game.socket.emit(SYSTEM_SOCKET_ID, { diff --git a/module/targets.js b/module/targets.js index 09d83e5d..98f76f2a 100644 --- a/module/targets.js +++ b/module/targets.js @@ -13,18 +13,21 @@ export class Targets { static extractTokenData(target) { return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' }; } - + static buildActorTokenData(tokenId, actor) { + return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' }; + } static isTargetEntite(target) { return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE; } - static async selectOneToken(onSelectTarget = target => { }) { - const targets = Targets.listTargets(); + static async selectOneTargetToken(onSelectTarget = target => { }) { + const targets = Targets.listTargets() switch (targets.length) { - case 0: return; + case 0: + return case 1: - onSelectTarget(targets[0]); - return; + onSelectTarget(targets[0]) + return default: { const selectData = { @@ -32,7 +35,7 @@ export class Targets { label: "Choisir une seule des cibles", list: targets.map(it => Targets.extractTokenData(it)) }; - DialogSelect.select(selectData, onSelectTarget); + DialogSelect.select(selectData, onSelectTarget) } } } diff --git a/module/time/rdd-calendrier.js b/module/time/rdd-calendrier.js index b2a4129d..727599c2 100644 --- a/module/time/rdd-calendrier.js +++ b/module/time/rdd-calendrier.js @@ -48,7 +48,7 @@ export class RdDCalendrier extends Application { constructor() { super(); this.timestamp = RdDTimestamp.getWorldTime(); - if (Misc.isUniqueConnectedGM()) { // Uniquement si GM + if (Misc.isFirstConnectedGM()) { // Uniquement si GM RdDTimestamp.setWorldTime(this.timestamp); this.rebuildNombresAstraux(); // Ensure always up-to-date } @@ -258,7 +258,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ async rebuildNombresAstraux() { - if (Misc.isUniqueConnectedGM()) { + if (Misc.isFirstConnectedGM()) { const nombresAstraux = this.getNombresAstraux() let newNombresAstraux = []; for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) { @@ -337,7 +337,7 @@ export class RdDCalendrier extends Application { /* -------------------------------------------- */ async requestNombreAstral(request) { const actor = game.actors.get(request.id); - if (Misc.isUniqueConnectedGM()) { // Only once + if (Misc.isFirstConnectedGM()) { // Only once console.log(request); let jourDiff = this.getLectureAstrologieDifficulte(request.date); let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat); diff --git a/module/time/rdd-timestamp.js b/module/time/rdd-timestamp.js index 27a5a80f..b1cb827b 100644 --- a/module/time/rdd-timestamp.js +++ b/module/time/rdd-timestamp.js @@ -160,15 +160,21 @@ export class RdDTimestamp { } static findHeure(heure) { - heure = Grammar.toLowerCaseNoAccentNoSpace(heure); - let parHeureOuLabel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR)); - if (parHeureOuLabel.length == 1) { - return parHeureOuLabel[0]; + let filtered + if (Number.isInteger(Number(heure))) { + filtered = DEFINITION_HEURES.filter(it => it.heure == Misc.modulo(Number(heure) - 1, RDD_HEURES_PAR_JOUR)) } - let parLabelPartiel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure)); - if (parLabelPartiel.length > 0) { - parLabelPartiel.sort(Misc.ascending(h => h.label.length)); - return parLabelPartiel[0]; + else { + heure = Grammar.toLowerCaseNoAccentNoSpace(heure); + filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR)); + } + if (filtered.length == 1) { + return filtered[0] + } + filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure)); + if (filtered.length > 0) { + filtered.sort(Misc.ascending(h => h.label.length)); + return filtered[0] } return undefined; } diff --git a/styles/simple.css b/styles/simple.css index 491e0f7b..f9eb048f 100644 --- a/styles/simple.css +++ b/styles/simple.css @@ -1561,6 +1561,11 @@ div.control-icon.token-hud-icon { height: 100%; object-fit: contain; } +.chat-inline-icon { + border: 0; + padding: 1px; + vertical-align: text-top; +} #sidebar-tabs { flex: 0 0 28px; diff --git a/system.json b/system.json index c2c2c221..25c0e64d 100644 --- a/system.json +++ b/system.json @@ -1,8 +1,8 @@ { "id": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", - "version": "12.0.17", - "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.17.zip", + "version": "12.0.18", + "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.18.zip", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "compatibility": { diff --git a/templates/actor/combat.html b/templates/actor/combat.html index 776f2b34..8179a27b 100644 --- a/templates/actor/combat.html +++ b/templates/actor/combat.html @@ -25,7 +25,7 @@ {{plusMoins arme.system.niveau}} {{plusMoins arme.system.dommagesReels}} - {{arme.system.initiative}} + {{arme.system.initiative}} {{/each}} {{#each esquives as |esq key|}} diff --git a/templates/actor/export-scriptarium/actor-encart-sheet.hbs b/templates/actor/export-scriptarium/actor-encart-sheet.hbs index 91d943e6..1368d560 100644 --- a/templates/actor/export-scriptarium/actor-encart-sheet.hbs +++ b/templates/actor/export-scriptarium/actor-encart-sheet.hbs @@ -1,11 +1,17 @@
-
-
-
-

{{name}} -

+
+
+ +
+
+
+

{{name}}

-
+
+ + + + {{#if system.attributs.hautrevant.value}} @@ -17,10 +23,6 @@ {{/if}} - - - - {{#if @root.options.isGM}} {{/if}} diff --git a/templates/actor/export-scriptarium/arme.hbs b/templates/actor/export-scriptarium/arme.hbs index 80b3b77e..264fce9f 100644 --- a/templates/actor/export-scriptarium/arme.hbs +++ b/templates/actor/export-scriptarium/arme.hbs @@ -10,7 +10,11 @@
{{niveau}}
{{#if init}} -
{{init}}
+ {{#if name}} + + {{else}} +
{{init}}
+ {{/if}}
{{dommages}}
{{else}}
diff --git a/templates/actor/export-scriptarium/carac-compteur.hbs b/templates/actor/export-scriptarium/carac-compteur.hbs index d80779c9..0d81f2de 100644 --- a/templates/actor/export-scriptarium/carac-compteur.hbs +++ b/templates/actor/export-scriptarium/carac-compteur.hbs @@ -11,8 +11,6 @@
- {{log carac.colName carac.value (eq carac.value actuel.value) actuel.value}} - {{log carac.colName carac.value (eq 1 1) actuel.value}} {{carac.value}} {{#unless (eq carac.value actuel.value)}}(Actuel : {{actuel.value}}){{/unless}}
diff --git a/templates/actor/export-scriptarium/carac-derivee-compteur.hbs b/templates/actor/export-scriptarium/carac-derivee-compteur.hbs index 574a0590..e9c97687 100644 --- a/templates/actor/export-scriptarium/carac-derivee-compteur.hbs +++ b/templates/actor/export-scriptarium/carac-derivee-compteur.hbs @@ -2,7 +2,11 @@
{{upperFirst carac.colName}} + {{#if (eq carac.value actuel.value)}} + + {{else}} + {{/if}}
{{carac.value}} {{#unless (eq carac.value actuel.value)}}(Actuel : {{actuel.value}}){{/unless}} diff --git a/templates/actor/export-scriptarium/esquive.hbs b/templates/actor/export-scriptarium/esquive.hbs index 550cc470..d07a4d21 100644 --- a/templates/actor/export-scriptarium/esquive.hbs +++ b/templates/actor/export-scriptarium/esquive.hbs @@ -2,7 +2,7 @@
{{upperFirst name}}
-
{{niveau}}
+
{{numberFormat competence.system.niveau decimals=0 sign=true}}
diff --git a/templates/actor/export-scriptarium/fatigue.hbs b/templates/actor/export-scriptarium/fatigue.hbs index 6573afae..566d9eff 100644 --- a/templates/actor/export-scriptarium/fatigue.hbs +++ b/templates/actor/export-scriptarium/fatigue.hbs @@ -3,7 +3,11 @@ {{#if etat.fatigue.malus}} ({{etat.fatigue.malus}}) {{/if}} + {{#if (eq etat.fatigue.value 0)}} + + {{else}} + {{/if}}
diff --git a/templates/chat-demande-attaque-etotal.html b/templates/chat-demande-attaque-etotal.html index 6c88fc0f..c72007d7 100644 --- a/templates/chat-demande-attaque-etotal.html +++ b/templates/chat-demande-attaque-etotal.html @@ -3,20 +3,22 @@
{{#if (eq attacker.type 'personnage')}} {{#unless essais.attaqueChance}} - Faire appel à la chance + + Faire appel à la chance
{{/unless}} {{#if (gt attacker.system.compteurs.destinee.value 0)}} - Utiliser la destinée + + Utiliser la destinée
{{/if}} {{/if}} - + Tirer la maladresse !
\ No newline at end of file diff --git a/templates/chat-demande-defense.html b/templates/chat-demande-defense.html index 5d58505b..4a8a0bd7 100644 --- a/templates/chat-demande-defense.html +++ b/templates/chat-demande-defense.html @@ -1,17 +1,17 @@
{{#if (eq surprise 'totale')}} - {{defender.name}} est totalement surpris + {{defenderToken.name}} est totalement surpris {{else if essais.defense}} - {{defender.name}} doit : + {{defenderToken.name}} doit : {{else}} - {{defender.name}} doit se défendre + {{defenderToken.name}} doit se défendre {{~#if (eq surprise 'demi')}} avec une significative {{/if}} d'une attaque {{~#if attaqueParticuliere}} particulière en {{~#if (eq attaqueParticuliere 'finesse')}} finesse {{else if (eq attaqueParticuliere 'force')}} force {{else if (eq attaqueParticuliere 'rapidite')}} rapidité {{/if~}} - {{/if}} de {{attacker.name}} ({{attaqueArme.name}}): + {{/if}} de {{attackerToken.name}} ({{attaqueArme.name}}): {{/if}} @@ -20,49 +20,64 @@ {{#if essais.defense}} {{#unless essais.defenseChance}} {{#if (eq defender.type 'personnage')}} - Faire appel à la chance - -
- {{/if}} - {{#if (eq defender.type 'personnage')}} - {{#if (gt defender.system.compteurs.destinee.value 0)}} - Utiliser la destinée + + Faire appel à la chance
{{/if}} + {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} + + Utiliser la destinée + +
{{/if}} {{/unless}} {{else}} {{#each armes as |arme key|}} - - Parer avec {{arme.name}} à {{../diffLibre }}{{#if arme.system.nbUsage}} (Utilisations : {{arme.system.nbUsage}}){{/if}} - -
- {{/each}} - {{#if mainsNues}} - - Parer à mains nues à {{diffLibre}}{{#if arme.system.nbUsage}} (Utilisations : {{arme.system.nbUsage}}){{/if}} + + Parer avec {{arme.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if (eq arme.typeParade 'sign')}} + ×½ + {{/if}} + {{#if arme.nbUsage}}(Utilisations : {{arme.nbUsage}}){{/if}}
+ {{/each}} + {{#if mainsNues}} + + Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} + +
{{/if}} {{#if (ne attaqueCategorie 'tir')}} - {{#each esquives as |esquive key|}} - - {{log 'esquive' esquive}} - {{esquive.name}} à {{../diffLibre}} {{#if esquive.system.nbUsage}} (Utilisations : {{esquive.system.nbUsage}}){{/if}} + {{#each esquives as |esquive key|}} + + {{esquive.name}} + {{#if (or (eq ../attaqueCategorie 'tir') (eq ../attaqueCategorie 'lancer'))}} + (difficulté à déterminer) + {{else}}à {{../diffLibre }} + {{/if}} + {{#if esquive.nbUsage}}(Utilisations : {{esquive.nbUsage}}){{/if}}
{{/each}} {{/if}} {{/if}} {{/unless}} - + Encaisser à {{plusMoins dmg.total}} {{#if (eq dmg.mortalite 'non-mortel')~}} (non-mortel) ! diff --git a/templates/chat-resultat-encaissement.html b/templates/chat-resultat-encaissement.html index 737eef53..f10b9ee5 100644 --- a/templates/chat-resultat-encaissement.html +++ b/templates/chat-resultat-encaissement.html @@ -1,5 +1,4 @@ {{#if isGM}} -{{log this}} {{#if (gt endurance 0)}} De plus, {{alias}} a perdu {{endurance}} points d'endurance @@ -18,18 +17,18 @@
Jet d'encaissement de {{roll.total}} - {{#unless (eq armure 0)}}, l'armure a protègé de {{armure}} + {{~#unless (eq armure 0)}}, l'armure a protègé de {{armure}} {{~#unless (eq penetration 0)}} (pénétration de {{penetration}}){{/unless}} - {{~/unless}}, total: {{total}} + {{~/unless~}}, total: {{total}}
{{alias}} {{#if (eq dmg.mortalite 'entiteincarnee')}}subit le coup {{else if mort}}vient de mourir {{else if blessure}} {{#if (gt blessure.system.gravite 0)}}subit une blessure {{blessure.system.label}} - {{else}}subit une contusion + {{~else~}}subit une contusion {{~/if~}} - {{else}}s'en sort sans une égratignure + {{~else~}}s'en sort sans une égratignure {{~/if~}} {{~#unless (eq dmg.mortalite 'entiteincarnee')}} @@ -39,11 +38,11 @@ {{/unless~}} {{~#if (gt endurance 0)}} {{~#if hasPlayerOwner}}, a perdu {{endurance}} points d'endurance - {{#if (ne vie 0)}}, {{vie}} points de vie{{/if}} + {{~#if (ne vie 0)}}, {{vie}} points de vie{{/if~}} {{/if}} {{#if (ne dmg.mortalite 'entiteincarnee')}} {{#if (gt endurance 1)}}et - {{#if sonne}}est sonné jusqu'à la fin du prochain round{{else}}n'est pas sonné{{/if}}! + {{#if sonne}}est sonné jusqu'à la fin du prochain round{{else}}n'est pas sonné{{/if}}! {{#if hasPlayerOwner}}Jet d'endurance : {{jetEndurance}} / {{resteEndurance}}{{/if}} {{/if}} {{/if}}