diff --git a/module/item-arme.js b/module/item-arme.js index ce733b5b..026af806 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -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 } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index 296f8638..55b6a2f8 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -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 += "
Cible : " + this.defender.data.name; } explications += "
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 += "
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: "Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "" - + "
Difficultés libre : " + rollData.diffLibre + " / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat - + RdDResolutionTable.explain(rollData.rolled) - + explications + + "
Difficultés libre : " + rollData.diffLibre + " / 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: "Echec total à l'attaque!" + content: "Echec total à l'attaque! " + + 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: "Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "" - + "
Difficultés libre : " + rollData.diffLibre + " / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat - + RdDResolutionTable.explain(rollData.rolled) - + "
Attaque parée!" + + "
Difficultés libre : " + rollData.diffLibre + " / conditions : " + Misc.toSignedString(rollData.diffConditions) + " / état : " + rollData.etat + + RdDResolutionTable.explain(rollData.rolled) + + "
Attaque parée!" } 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: "Echec total à la parade!" + content: "Echec total à la parade! " + + 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) + "
Attaque esquivée!" } - 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: "Echec total à l'esquive'!" + content: "Echec total à l'esquive'! " + + 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")] + }); } } } diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js index 3e2c3ea2..480b4f13 100644 --- a/module/rdd-rolltables.js +++ b/module/rdd-rolltables.js @@ -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); + } }