Gestion des maladresses #68
This commit is contained in:
		| @@ -71,7 +71,7 @@ export class RdDItemArme extends Item { | ||||
|   static mainsNues() { | ||||
|     const mainsNues = { | ||||
|       name: "Mains nues", | ||||
|       data: { unemain: true, deuxmains: false, dommages: 0, dommagesReels: 0, mortalite: 'non-mortel', competence: 'Corps à corps' } | ||||
|       data: { unemain: true, deuxmains: false, dommages: 0, dommagesReels: 0, mortalite: 'non-mortel', competence: 'Corps à corps', sansArme:true } | ||||
|     }; | ||||
|     return mainsNues | ||||
|   } | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import { Misc } from "./misc.js"; | ||||
| import { RdDBonus } from "./rdd-bonus.js"; | ||||
| import { RdDResolutionTable } from "./rdd-resolution-table.js"; | ||||
| import { RdDRoll } from "./rdd-roll.js"; | ||||
| import { RdDRollTables } from "./rdd-rolltables.js"; | ||||
|  | ||||
| export class RdDCombat { | ||||
|  | ||||
| @@ -99,7 +100,7 @@ export class RdDCombat { | ||||
|     } | ||||
|     return rollData.rolled.isEchec; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isEchecTotal(rollData) { | ||||
|     if (rollData.arme && rollData.surprise == 'demi') { | ||||
| @@ -107,7 +108,7 @@ export class RdDCombat { | ||||
|     } | ||||
|     return rollData.rolled.isETotal; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isParticuliere(rollData) { | ||||
|     if (rollData.arme && rollData.surprise) { | ||||
| @@ -115,7 +116,7 @@ export class RdDCombat { | ||||
|     } | ||||
|     return rollData.rolled.isPart; | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isReussite(rollData) { | ||||
|     switch (rollData.surprise) { | ||||
| @@ -135,8 +136,10 @@ export class RdDCombat { | ||||
|     console.log("RdDCombat.attaque >>>", rollData); | ||||
|  | ||||
|     const dialog = await RdDRoll.create(this.attacker, rollData, | ||||
|       { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', | ||||
|         options: { height: 540 } }, { | ||||
|       { | ||||
|         html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', | ||||
|         options: { height: 540 } | ||||
|       }, { | ||||
|       name: 'jet-attaque', | ||||
|       label: 'Attaque: ' + (arme ? arme.name : competence.name), | ||||
|       callbacks: [ | ||||
| @@ -146,7 +149,7 @@ export class RdDCombat { | ||||
|         { condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) }, | ||||
|         { condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) }, | ||||
|       ] | ||||
|     } ); | ||||
|     }); | ||||
|     dialog.render(true); | ||||
|   } | ||||
|  | ||||
| @@ -213,15 +216,15 @@ export class RdDCombat { | ||||
|     let explications = ""; | ||||
|  | ||||
|     rollData.dmg = RdDBonus.dmg(rollData, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar()); | ||||
|      | ||||
|  | ||||
|     if (this.target) { | ||||
|       explications += "<br><strong>Cible</strong> : " + this.defender.data.name; | ||||
|     } | ||||
|     explications += "<br>Encaissement à " + Misc.toSignedString(rollData.dmg.total) + " (" + rollData.dmg.loc.label + ")"; | ||||
|      | ||||
|  | ||||
|     // Save rollData for defender | ||||
|     game.system.rdd.rollDataHandler[this.attackerId] = duplicate(rollData); | ||||
|      | ||||
|  | ||||
|     // Message spécial pour la rapidité, qui reste difficile à gérer automatiquement | ||||
|     if (rollData.particuliereAttaque == 'rapidite') { | ||||
|       explications += "<br>Vous avez attaqué en Rapidité. Vous pourrez faire une deuxième attaque, ou utiliser votre arme pour vous défendre."; | ||||
| @@ -230,12 +233,12 @@ export class RdDCombat { | ||||
|     // Final chat message | ||||
|     let chatOptions = { | ||||
|       content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>" | ||||
|       + "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat | ||||
|       + RdDResolutionTable.explain(rollData.rolled) | ||||
|       + explications | ||||
|         + "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat | ||||
|         + RdDResolutionTable.explain(rollData.rolled) | ||||
|         + explications | ||||
|     } | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.attacker.name) | ||||
|      | ||||
|  | ||||
|     if (this.target) { | ||||
|       this._messageDefenseur(rollData); | ||||
|     } | ||||
| @@ -309,11 +312,11 @@ export class RdDCombat { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _onAttaqueEchecTotal(rollData) { | ||||
|   async _onAttaqueEchecTotal(rollData) { | ||||
|     console.log("RdDCombat.onEchecTotal >>>", rollData); | ||||
|     // TODO: proposer un résultat d'échec total | ||||
|     let chatOptions = { | ||||
|       content: "<strong>Echec total à l'attaque!</strong>" | ||||
|       content: "<strong>Echec total à l'attaque!</strong> " | ||||
|         + await RdDRollTables.getMaladresse({ arme: rollData.arme && !rollData.arme.data.sansArme }) | ||||
|     } | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.attacker.name) | ||||
|   } | ||||
| @@ -347,8 +350,10 @@ export class RdDCombat { | ||||
|     let rollData = this._prepareParade(attackerRoll, arme); | ||||
|  | ||||
|     const dialog = await RdDRoll.create(this.defender, rollData, | ||||
|       { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', | ||||
|         options: { height: 540 } }, { | ||||
|       { | ||||
|         html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', | ||||
|         options: { height: 540 } | ||||
|       }, { | ||||
|       name: 'jet-parade', | ||||
|       label: 'Parade: ' + (arme ? arme.name : rollData.competence.name), | ||||
|       callbacks: [ | ||||
| @@ -358,7 +363,7 @@ export class RdDCombat { | ||||
|         { condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) }, | ||||
|         { condition: RdDCombat.isEchecTotal, action: r => this._onParadeEchecTotal(r) }, | ||||
|       ] | ||||
|     } ); | ||||
|     }); | ||||
|     dialog.render(true); | ||||
|   } | ||||
|  | ||||
| @@ -368,7 +373,7 @@ export class RdDCombat { | ||||
|       return armeItem.data; | ||||
|  | ||||
|     } | ||||
|     return RdDItemArme.mainsNues()  | ||||
|     return RdDItemArme.mainsNues() | ||||
|   } | ||||
|  | ||||
|   _prepareParade(attackerRoll, armeParade) { | ||||
| @@ -376,7 +381,7 @@ export class RdDCombat { | ||||
|     const compName = isCreature ? armeParade.name : armeParade.data.competence; | ||||
|     const competence = this.defender.getCompetence(compName); | ||||
|     const armeAttaque = attackerRoll.arme; | ||||
|      | ||||
|  | ||||
|     if (compName != competence.name) { | ||||
|       // TODO: toujours utiliser competence.name ... | ||||
|       ui.notifications.warn("Différence entre compétence " + competence.name + " et compétence de l'arme " + compName); | ||||
| @@ -429,12 +434,12 @@ export class RdDCombat { | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onParadeNormale(rollData) { | ||||
|     console.log("RdDCombat._onParadeNormale >>>", rollData); | ||||
|      | ||||
|  | ||||
|     let chatOptions = { | ||||
|       content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>" | ||||
|       + "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat | ||||
|       + RdDResolutionTable.explain(rollData.rolled) | ||||
|       + "<br><strong>Attaque parée!</strong>" | ||||
|         + "<br>Difficultés <strong>libre : " + rollData.diffLibre + "</strong> / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat | ||||
|         + RdDResolutionTable.explain(rollData.rolled) | ||||
|         + "<br><strong>Attaque parée!</strong>" | ||||
|     } | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.defender.name) | ||||
|     await this.computeRecul(rollData, false); | ||||
| @@ -442,11 +447,11 @@ export class RdDCombat { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _onParadeEchecTotal(rollData) { | ||||
|   async _onParadeEchecTotal(rollData) { | ||||
|     console.log("RdDCombat._onParadeEchecTotal >>>", rollData); | ||||
|     // TODO: proposer un résultat d'échec total | ||||
|     let chatOptions = { | ||||
|       content: "<strong>Echec total à la parade!</strong>" | ||||
|       content: "<strong>Echec total à la parade!</strong> " | ||||
|         + await RdDRollTables.getMaladresse({ arme: rollData.arme && !rollData.arme.data.sansArme }) | ||||
|     } | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.defender.name) | ||||
|   } | ||||
| @@ -536,15 +541,15 @@ export class RdDCombat { | ||||
|         + RdDResolutionTable.explain(rollData.rolled) | ||||
|         + "<br><strong>Attaque esquivée!</strong>" | ||||
|     } | ||||
|  | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.defender.name) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _onEsquiveEchecTotal(rollData) { | ||||
|   async _onEsquiveEchecTotal(rollData) { | ||||
|     console.log("RdDCombat._onEsquiveEchecTotal >>>", rollData); | ||||
|     // TODO: proposer un résultat d'échec total | ||||
|     let chatOptions = { | ||||
|       content: "<strong>Echec total à l'esquive'!</strong>" | ||||
|       content: "<strong>Echec total à l'esquive'!</strong> " | ||||
|         + await RdDRollTables.getMaladresse({ arme: false }) | ||||
|     } | ||||
|     ChatUtility.chatWithRollMode(chatOptions, this.defender.name) | ||||
|   } | ||||
| @@ -571,14 +576,14 @@ export class RdDCombat { | ||||
|     this.encaisser(rollData.attackerRoll); | ||||
|   } | ||||
|  | ||||
|    | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async computeDeteriorationArme( rollData ) { | ||||
|   async computeDeteriorationArme(rollData) { | ||||
|     const attackerRoll = rollData.attackerRoll; | ||||
|     if (rollData.arme && attackerRoll) { // C'est une parade | ||||
|       // Est-ce que l'attaque est une particulière, en force ou charge et que l'attaque n'en est pas une ? | ||||
|       if ( (rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.tactique == 'charge') | ||||
|       && !rollData.rolled.isPart ) { | ||||
|       if ((rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.tactique == 'charge') | ||||
|         && !rollData.rolled.isPart) { | ||||
|         const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor; | ||||
|         let resistance = Misc.toInt(rollData.arme.data.resistance); | ||||
|         let msg = ""; | ||||
| @@ -586,44 +591,49 @@ export class RdDCombat { | ||||
|         let resistRoll = await RdDResolutionTable.rollData({ | ||||
|           caracValue: resistance, | ||||
|           finalLevel: - dmg, | ||||
|           showDice: false}); | ||||
|           showDice: false | ||||
|         }); | ||||
|         if (resistRoll.isSuccess) { // Perte de résistance | ||||
|           msg = "Votre " + rollData.arme.name + " tient le choc de la parade. " | ||||
|         } else { | ||||
|           resistance -= dmg; | ||||
|           if ( resistance <= 0 ) { | ||||
|           if (resistance <= 0) { | ||||
|             this.defender.deleteEmbeddedEntity("OwnedItem", rollData.arme._id); | ||||
|             msg = "Sous la violence de la parade, votre " + rollData.arme.name + " s'est brisée sous le coup!"; | ||||
|           } else { | ||||
|             this.defender.updateEmbeddedEntity("OwnedItem", {_id: rollData.arme._id, 'data.resistance': resistance });  | ||||
|             this.defender.updateEmbeddedEntity("OwnedItem", { _id: rollData.arme._id, 'data.resistance': resistance }); | ||||
|             msg = "En parant, vous endommagez votre " + rollData.arme.name + ", qui perd  " + dmg + " de résistance. "; | ||||
|           } | ||||
|         } | ||||
|         // Jet de désarmement | ||||
|         if (resistance > 0 && !rollData.arme.name.toLowerCase().includes('bouclier') ) { // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132) | ||||
|         if (resistance > 0 && !rollData.arme.name.toLowerCase().includes('bouclier')) { // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132) | ||||
|           let desarme = await RdDResolutionTable.rollData({ | ||||
|             caracValue: this.defender.data.data.carac.force.value, | ||||
|             finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg, | ||||
|             showDice: false}); | ||||
|           if ( desarme.isEchec) { | ||||
|             showDice: false | ||||
|           }); | ||||
|           if (desarme.isEchec) { | ||||
|             msg += "Vous ne parvenez pas à garder votre arme en main, elle tombe au sol à vos pieds"; | ||||
|           } | ||||
|         } | ||||
|         ChatMessage.create( { content: msg, | ||||
|                               user: game.user._id, | ||||
|                               whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM") ] } ); | ||||
|         ChatMessage.create({ | ||||
|           content: msg, | ||||
|           user: game.user._id, | ||||
|           whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM")] | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   async computeRecul( rollData, encaisser = undefined ) { // Calcul du recul (p. 132) | ||||
|     if ( rollData.arme || encaisser ) {  | ||||
|       if ( (rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.tactique == 'charge') { | ||||
|         let reculNiveau = Misc.toInt(this.defender.data.data.carac.taille.value) - (rollData.attackerRoll.forceValue+rollData.attackerRoll.arme.data.dommagesReels); | ||||
|   async computeRecul(rollData, encaisser = undefined) { // Calcul du recul (p. 132) | ||||
|     if (rollData.arme || encaisser) { | ||||
|       if ((rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.tactique == 'charge') { | ||||
|         let reculNiveau = Misc.toInt(this.defender.data.data.carac.taille.value) - (rollData.attackerRoll.forceValue + rollData.attackerRoll.arme.data.dommagesReels); | ||||
|         let recul = await RdDResolutionTable.rollData({ | ||||
|           caracValue: 10, | ||||
|           finalLevel: reculNiveau, | ||||
|           showDice: false}); | ||||
|           showDice: false | ||||
|         }); | ||||
|  | ||||
|         let msg = ""; | ||||
|         if (recul.isSuccess) { | ||||
| @@ -632,16 +642,19 @@ export class RdDCombat { | ||||
|           let chute = await RdDResolutionTable.rollData({ | ||||
|             caracValue: this.defender.data.data.carac.agilite.value, | ||||
|             finalLevel: reculNiveau, | ||||
|             showDice: false}); | ||||
|           if ( !chute.isSuccess || recul.isETotal ) { | ||||
|             showDice: false | ||||
|           }); | ||||
|           if (!chute.isSuccess || recul.isETotal) { | ||||
|             msg = "Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round."; | ||||
|           } else { | ||||
|             msg = "La violence du choc vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round."; | ||||
|           } | ||||
|         }   | ||||
|         ChatMessage.create( {content: msg,  | ||||
|                       user: game.user._id, | ||||
|                       whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM") ] } ); | ||||
|         } | ||||
|         ChatMessage.create({ | ||||
|           content: msg, | ||||
|           user: game.user._id, | ||||
|           whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM")] | ||||
|         }); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -8,7 +8,6 @@ export class RdDRollTables { | ||||
|     const table = await pack.getEntity(entry._id); | ||||
|     const draw = await table.draw({ displayChat: toChat }); | ||||
|     console.log("RdDRollTables", tableName, toChat, ":", draw); | ||||
|     console.log("RdDRollTables", tableName, toChat, ":", draw.roll, draw.results); | ||||
|     return draw; | ||||
|   } | ||||
|  | ||||
| @@ -16,9 +15,25 @@ export class RdDRollTables { | ||||
|   static async drawItemFromRollTable(tableName, toChat) { | ||||
|     const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); | ||||
|     const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; | ||||
|     const pack = game.packs.get(drawnItemRef.collection); | ||||
|     return await pack.getEntity(drawnItemRef.resultId); | ||||
|     if (drawnItemRef.collection) { | ||||
|       const pack = game.packs.get(drawnItemRef.collection); | ||||
|       return await pack.getEntity(drawnItemRef.resultId); | ||||
|     } | ||||
|     ui.notifications.warn("le tirage ne correspond pas à une entrée d'un Compendium") | ||||
|     return drawnItemRef.text; | ||||
|   } | ||||
|    | ||||
|   /* -------------------------------------------- */ | ||||
|   static async drawTextFromRollTable(tableName, toChat) { | ||||
|     const draw = await RdDRollTables.genericGetTableResult(tableName, toChat); | ||||
|     const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined; | ||||
|     if (drawnItemRef.collection) { | ||||
|       ui.notifications.warn("le tirage correspond à une entrée d'un Compendium, on attendait un texte") | ||||
|       return await pack.getEntity(drawnItemRef.resultId); | ||||
|     } | ||||
|     return drawnItemRef.text; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async getSouffle(toChat = true) { | ||||
|     return await RdDRollTables.drawItemFromRollTable("Souffles de Dragon", toChat); | ||||
| @@ -48,4 +63,10 @@ export class RdDRollTables { | ||||
|   static async getTarot(toChat = true) { | ||||
|     return await RdDRollTables.drawItemFromRollTable("Tarot Draconique", toChat); | ||||
|   } | ||||
|  | ||||
|   static async getMaladresse(options = {toChat: false, arme: false}) { | ||||
|     return await RdDRollTables.drawTextFromRollTable( | ||||
|       options.arme ? "Maladresse armé" : "Maladresses non armé", | ||||
|       options.toChat); | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user