From 1fc3bf22f51df0c4a576658346bd255da5c56376 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 12 Nov 2020 14:20:10 +0100 Subject: [PATCH 1/5] clean getBestDraconic * peut utiliser getDraconicList * list.sort pour trouver le meilleur * dupliquer seulement le meilleur --- module/actor.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/module/actor.js b/module/actor.js index c99fd5e6..c6e68da7 100644 --- a/module/actor.js +++ b/module/actor.js @@ -91,20 +91,17 @@ export class RdDActor extends Actor { getCurrentReve() { return this.data.data.reve.reve.value; } - + /* -------------------------------------------- */ getBestDraconic() { - - let draconic = {name: "none", niveau: -11 }; - for (const item of this.data.items) { - //console.log(item); - if ( item.data.categorie && item.data.categorie.toLowerCase() == "draconic") { - if (item.data.niveau > draconic.niveau) draconic = duplicate(item); - } + const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau); + if (list.length==0) + { + return { name: "none", niveau: -11 }; } - return draconic; + return duplicate(list[0]); } - + /* -------------------------------------------- */ async deleteSortReserve(coordTMR) { let reserve = duplicate(this.data.data.reve.reserve); From 5fa703241a09627d957a90b4607530fad32cc7bd Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 12 Nov 2020 16:35:51 +0100 Subject: [PATCH 2/5] RdDResolutionTable rolls --- module/actor.js | 279 +++++++++++++-------------------- module/rdd-resolution-table.js | 120 ++++++++++++-- module/rdd-roll-dialog.js | 16 +- module/rdd-tmr-dialog.js | 83 +++++----- module/rdd-utility.js | 42 +---- 5 files changed, 277 insertions(+), 263 deletions(-) diff --git a/module/actor.js b/module/actor.js index c6e68da7..0b61b321 100644 --- a/module/actor.js +++ b/module/actor.js @@ -7,6 +7,7 @@ import { RdDUtility } from "./rdd-utility.js"; import { TMRUtility } from "./tmr-utility.js"; import { RdDRollDialog } from "./rdd-roll-dialog.js"; import { RdDTMRDialog } from "./rdd-tmr-dialog.js"; +import { RdDResolutionTable } from "./rdd-resolution-table.js"; export class RdDActor extends Actor { @@ -119,148 +120,110 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async performRoll( rollData ) { - - let result = new Roll("d100").roll().total; - let quality = "Echec"; - let xpmsg = ""; - let tache = 0; - //console.log(">>> ROLL", rollData.selectedCarac.label, rollData.rollTarget.score, myroll.total ); - if (result <= rollData.rollTarget.part) { - quality = "Réussite Particulière!"; - if ( rollData.finalLevel < 0 ) { - let xpcarac = Math.floor( Math.abs(rollData.finalLevel) / 2); - let xpcomp = (Math.abs(rollData.finalLevel) % 2 == 1) ? xpcarac+1 : xpcarac; - xpmsg = "
Points d'expérience gagné ! " + xpcarac + " - " + xpcomp; - } - rollData.pointsDeTache = 4; - rollData.qualite = 2; - } else if (result <= (rollData.rollTarget.score /2) ) { - quality = "Réussite Significative"; - rollData.pointsDeTache = 2; - rollData.qualite = 1; - } else if (result <= (rollData.rollTarget.score) ) { - quality = "Réussite Normale"; - rollData.pointsDeTache = 1; - rollData.qualite = 0; - } else if (result < (rollData.rollTarget.epart) ) { - quality = "Echec Normal"; - rollData.pointsDeTache = 0; - rollData.qualite = -2; - } else if (result < (rollData.rollTarget.etotal) ) { - quality = "Echec Particulier"; - rollData.pointsDeTache = -2; - rollData.qualite = -4; - } else if (result >= (rollData.rollTarget.etotal) ) { - quality = "Echec Total"; - rollData.pointsDeTache = -4; - rollData.qualite = -6; - } - + async performRoll(rollData) { + // Manage weapon categories when parrying (cf. page 115 ) - let need_significative = false; // Do we need to have a sgnificative ? - let need_resist = false; // Do we need to have a sgnificative ? - if ( rollData.arme && rollData.attackerRoll ) { // Manage parade depeding on weapon type, and change roll results - let attCategory = RdDUtility.getArmeCategory( rollData.attackerRoll.arme ); - let defCategory = RdDUtility.getArmeCategory( rollData.arme ); - if ( defCategory == "bouclier" ) - need_significative = true; - else if ( attCategory != defCategory ) - need_significative = true; - if ( attCategory.match("epee") && ( defCategory == "hache" || defCategory == "lance") ) + let need_resist = false; // Do we need to make resistance roll for defender ? + if (rollData.arme && rollData.attackerRoll) { // Manage parade depeding on weapon type, and change roll results + let attCategory = RdDUtility.getArmeCategory(rollData.attackerRoll.arme); + let defCategory = RdDUtility.getArmeCategory(rollData.arme); + if (defCategory == "bouclier") + rollData.needSignificative = true; + else if (attCategory != defCategory) + rollData.needSignificative = true; + if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance")) need_resist = true; } - - // Sonne management or if need_significative is set - if ( this.data.data.sante.sonne.value || need_significative) { - if (rollData.pointsDeTache >= 2 ) { // Reussite normale dès que significative - quality = "Réussite Normale"; - rollData.pointsDeTache = 1; - rollData.qualite = 0; - } else if (rollData.pointsDeTache < 2 ) { // Not a "significative" - quality = "Echec Normal"; - rollData.pointsDeTache = 0; - rollData.qualite = -2; - } + if (this.data.data.sante.sonne.value) + { + rollData.needSignificative = true; } - + + let rolled = RdDResolutionTable.rollChances(rollData.rollTarget); + let result = rolled.roll; + let quality = rolled.quality + + console.log(">>> ROLL", rollData, rolled); + let xpmsg = RdDResolutionTable.buildXpMessage(rolled, rollData.finalLevel); + + let specialStr = "
Points de taches : " + rolled.tache + ", Points de qualité: " + rolled.qualite; + // Fight management ! let defenseMsg; let encaisser = false; - let specialStr = "
Points de taches : " + rollData.pointsDeTache; // Per default - if ( rollData.arme ) { // In case of fight, replace the "tache" message per dommages + localization. "tache" indicates if result is OK or not - if ( rollData.attackerRoll) { // Defense case ! - if ( rollData.pointsDeTache > 0 ) { // Réussite ! + if (rollData.arme) { + // In case of fight, replace the message per dommages + localization. it indicates if result is OK or not + if (rollData.attackerRoll) { // Defense case ! + if (rolled.isSuccess) { specialStr = "
Attaque parée/esquivée !"; } else { specialStr = "
Esquive/Parade échouée, encaissement !"; - encaisser = true; - } + encaisser = true; + } } else { // This is the attack roll! - if ( rollData.pointsDeTache > 0 ) { - let myroll = new Roll("2d10"); - myroll.roll(); + if (rolled.isSuccess > 0) { rollData.domArmePlusDom = parseInt(rollData.arme.data.dommages); - if ( rollData.selectedCarac.label == "Mêlée" ) // +dom only for Melee + if (rollData.selectedCarac.label == "Mêlée") // +dom only for Melee rollData.domArmePlusDom += parseInt(this.data.data.attributs.plusdom.value); - if ( rollData.selectedCarac.label == "Lancer" ) { // +dom only for Melee/Lancer + if (rollData.selectedCarac.label == "Lancer") { // +dom only for Melee/Lancer let bdom = parseInt(this.data.data.attributs.plusdom.value); - if ( bdom > parseInt(rollData.arme.data.dommages)) + if (bdom > parseInt(rollData.arme.data.dommages)) bdom = parseInt(rollData.arme.data.dommages); rollData.domArmePlusDom += bdom } - rollData.degats = parseInt(myroll.result) + rollData.domArmePlusDom; + let encaissement = new Roll("2d10 + @domArmePlusDom", {domArmePlusDom : rollData.domArmePlusDom}); + rollData.degats = parseInt(encaissement.roll().total); rollData.loc = RdDUtility.getLocalisation(); for (let target of game.user.targets) { - defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData ); + defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData); specialStr = "
Cible : " + target.actor.data.name; } specialStr += "
Dommages : " + rollData.degats + "
Localisation : " + rollData.loc.label; } else { - specialStr = "
Echec ! Pas de dommages"; + specialStr = "
Echec ! Pas de dommages"; } } } - + // Sort management let lvl = "" - if ( rollData.selectedSort) { // Lancement de sort ! + if (rollData.selectedSort) { // Lancement de sort ! let draconic = rollData.selectedSort.data.draconic; - specialStr = "
Lancement du sort " + rollData.selectedSort.name + " : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte + - "/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve; + specialStr = "
Lancement du sort " + rollData.selectedSort.name + " : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte + + "/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve; specialStr += "
Depuis la case " + rollData.coord + " (" + TMRUtility.getTMRDescription(rollData.coord).label + ")"; - lvl = rollData.selectedDraconic.name +"/"+ rollData.selectedSort.name; + lvl = rollData.selectedDraconic.name + "/" + rollData.selectedSort.name; let costReve = rollData.selectedSort.data.ptreve; let myReve = duplicate(this.data.data.reve.reve); - if ( rollData.pointsDeTache > 0 ) { // Réussite du sort ! - if (rollData.pointsDeTache >= 4 ) costReve = Math.ceil(costReve/2); - if (costReve < 1 ) costReve = 1; + if (rollData.tache > 0) { // Réussite du sort ! + if (rollData.tache >= 4) costReve = Math.ceil(costReve / 2); + if (costReve < 1) costReve = 1; myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!! if (myReve.value < 0) myReve.value = 0; - await this.update( {"data.reve.reve": myReve } ); + await this.update({ "data.reve.reve": myReve }); specialStr += "
Réussite du sort pour " + costReve + " Points de Rêve"; - if ( !rollData.isSortReserve) { + if (!rollData.isSortReserve) { this.currentTMR.close(); // Close TMR ! } else { // Mise en réserve let reserve = duplicate(this.data.data.reve.reserve); - reserve.list.push( { coord: rollData.coord, sort: duplicate(rollData.selectedSort), draconic: duplicate(rollData.selectedDraconic) }); - await this.update( {"data.reve.reserve": reserve} ); + reserve.list.push({ coord: rollData.coord, sort: duplicate(rollData.selectedSort), draconic: duplicate(rollData.selectedDraconic) }); + await this.update({ "data.reve.reserve": reserve }); this.currentTMR.updateSortReserve(); } } else { - if ( rollData.pointsDeTache == -4) { // Echec total ! + if (rollData.tache == -4) { // Echec total ! costReve *= 2; myReve.value = myReve.value - costReve; // Todo 0 pts de reve !!!! if (myReve.value < 0) myReve.value = 0; - await this.update( {"data.reve.reve": myReve } ); + await this.update({ "data.reve.reve": myReve }); specialStr += "
Echec TOTAL du sort : " + costReve + " Points de Rêve"; - } else { + } else { specialStr += "
Echec du sort !"; } this.currentTMR.close(); // Close TMR ! } if (myReve.value == 0) { // 0 points de reve - ChatMessage.create( {title: "Zero Points de Reve !", content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" } ); + ChatMessage.create({ title: "Zero Points de Reve !", content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" }); this.currentTMR.close(); // Close TMR ! } } else { @@ -268,37 +231,38 @@ export class RdDActor extends Actor { } // Save it for fight in the flags area - await this.setFlag( 'world', 'rollData', null ); - await this.setFlag( 'world', 'rollData', rollData ); - + await this.setFlag('world', 'rollData', null); + await this.setFlag('world', 'rollData', rollData); + // Final chat message - let chatOptions = { content: "Test : " + rollData.selectedCarac.label + " / " + lvl + "
Jet : " + - rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rollData.rollTarget.score + "%
Résutat : " + result + "
" + - "" + quality + "" + specialStr + xpmsg, - user: game.user._id, - title: "Résultat du test" - } - ChatMessage.create( chatOptions ); - + let chatOptions = { + content: "Test : " + rollData.selectedCarac.label + " / " + lvl + "
Jet : " + + rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rolled.score + "%
Résutat : " + result + "
" + + "" + quality + "" + specialStr + xpmsg, + user: game.user._id, + title: "Résultat du test" + } + ChatMessage.create(chatOptions); + // This an attack, generate the defense message - if ( defenseMsg ) { - if ( defenseMsg.toSocket) { + if (defenseMsg) { + if (defenseMsg.toSocket) { game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_defense", - data: defenseMsg - } ); - } else { - defenseMsg.whisper = [ game.user]; - ChatMessage.create( defenseMsg ); + data: defenseMsg + }); + } else { + defenseMsg.whisper = [game.user]; + ChatMessage.create(defenseMsg); } } // Get damages! - if ( encaisser ) { - this.encaisserDommages( rollData.attackerRoll ); + if (encaisser) { + this.encaisserDommages(rollData.attackerRoll); } -} - + } + /* -------------------------------------------- */ updateCarac( caracName, caracValue ) { @@ -635,62 +599,45 @@ export class RdDActor extends Actor { this.update( { "data.blessures": blessures } ); } - - /* -------------------------------------------- */ - async stressTest( ) { + + /* -------------------------------------------- */ + async stressTest() { + let target = RdDResolutionTable.computeChances(this.data.data.carac.reve.value, 0); + let stressRoll = this._stressRoll(target); + let compteurs = duplicate(this.data.data.compteurs); - let stress = compteurs.stress; - let xp = compteurs.experience; + let convertion = Math.floor(compteurs.stress.value * stressRoll.factor); + + compteurs.experience.value += convertion; + compteurs.stress.value = Math.max(compteurs.stress.value - convertion - 1, 0); - let scoreTarget = RdDUtility.getResolutionField( this.data.data.carac.reve.value, 0 ); - scoreTarget.sig = Math.floor(scoreTarget.score / 2); - - let scoreValue = new Roll("d100").roll().total; - let newXP = xp.value; - let factor = 0; - let comment = "Echec Total (0%)" - - if (scoreValue <= scoreTarget.part ) { - scoreValue = new Roll("d100").roll().total; - if (scoreValue <= scoreTarget.sig) { - factor = 1.5; - comment = "Double Particulière (150%)" - } else { - factor = 1; - comment = "Particulière (100%)" - } - } else { - if ( scoreValue <= scoreTarget.sig ) { - factor = 0.75; - comment = "Significative (75%)" - } else { - if ( scoreValue <= scoreTarget.score ) { - factor = 0.5; - comment = "Normale (50%)" - } else if (scoreValue <= scoreTarget.epart) { - factor = 0.2; - comment = "Echec (20%)" - } else if (scoreValue <= scoreTarget.etotal) { - factor = 0.1; - comment = "Echec (10%)" - } - } - } - - let xpValue = Math.floor(stress.value * factor); - stress.value -= xpValue; - stress.value -= 1; - if (stress.value < 0 ) stress.value = 0; - - ChatMessage.create( { title: "Jet de Stress", content: "Vous avez transformé "+ xpValue + " points de Stress en Expérience avec une réussite " + comment , - whisper: ChatMessage.getWhisperRecipients(game.user.name) } ); - - xp.value += xpValue; - await this.update( { "data.compteurs": compteurs } ); + ChatMessage.create({ + title: "Jet de Stress", content: "Vous avez transformé " + convertion + " points de Stress en Expérience avec une réussite " + stressRoll.comment, + whisper: ChatMessage.getWhisperRecipients(game.user.name) + }); + await this.update({ "data.compteurs": compteurs }); } - /* -------------------------------------------- */ - async rollUnSort( coord ) { + _stressRoll(target) { + let result = RdDResolutionTable.rollChances(target) + switch (result.quality) { + case "sign": return { factor: 0.75, comment: "Significative (75%) - " + result.roll } + case "norm": return { factor: 0.5, comment: "Normale (50%) - " + result.roll } + case "echec": return { factor: 0.2, comment: "Echec (20%) - " + result.roll } + case "epart": return { factor: 0.1, comment: "Echec particulier(10%) - " + result.roll } + case "etotal": return { factor: 0, comment: "Echec Total (0%) - " + result.roll } + } + let second = RdDResolutionTable.rollChances(target) + switch (second.qualite) { + case "part": case "sign": + return { factor: 1.5, comment: "Double Particulière (150%) - " + result + " puis " + second } + default: + return { factor: 1, comment: "Particulière (100%) - " + result + " puis " + second } + } + } + + /* -------------------------------------------- */ + async rollUnSort(coord) { let draconicList = this.getDraconicList(); let sortList = this.getSortList(); diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index 5aa236fa..f49b4748 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -1,4 +1,58 @@ +/** + * difficultés au delà de -10 + */ +const levelDown = [ + { level: -11, score: 1, sign: 0, part: 0, epart: 2, etotal: 90 }, + { level: -12, score: 1, sign: 0, part: 0, epart: 2, etotal: 70 }, + { level: -13, score: 1, sign: 0, part: 0, epart: 2, etotal: 50 }, + { level: -14, score: 1, sign: 0, part: 0, epart: 2, etotal: 30 }, + { level: -15, score: 1, sign: 0, part: 0, epart: 2, etotal: 10 }, + { level: -16, score: 1, sign: 0, part: 0, epart: 0, etotal: 2 } +]; +const levelImpossible = { score: 0, sign: 0, part: 0, epart: 0, etotal: 1 }; +/** + * Table des résultats spéciaux - inutilisée, conservée si on veut afficher la table + */ +const specialResults = [ + { part: 0, epart: 0, etotal: 0, min: 0, max: 0 }, + { part: 1, epart: 81, etotal: 92, min: 1, max: 5 }, + { part: 2, epart: 82, etotal: 92, min: 6, max: 10 }, + { part: 3, epart: 83, etotal: 93, min: 11, max: 15 }, + { part: 4, epart: 84, etotal: 93, min: 16, max: 20 }, + { part: 5, epart: 85, etotal: 94, min: 21, max: 25 }, + { part: 6, epart: 86, etotal: 94, min: 26, max: 30 }, + { part: 7, epart: 87, etotal: 95, min: 31, max: 35 }, + { part: 8, epart: 88, etotal: 95, min: 36, max: 40 }, + { part: 9, epart: 89, etotal: 96, min: 41, max: 45 }, + { part: 10, epart: 90, etotal: 96, min: 46, max: 50 }, + { part: 11, epart: 91, etotal: 97, min: 51, max: 55 }, + { part: 12, epart: 92, etotal: 97, min: 56, max: 60 }, + { part: 13, epart: 93, etotal: 98, min: 61, max: 65 }, + { part: 14, epart: 94, etotal: 98, min: 65, max: 70 }, + { part: 15, epart: 95, etotal: 99, min: 71, max: 75 }, + { part: 16, epart: 96, etotal: 99, min: 76, max: 80 }, + { part: 17, epart: 97, etotal: 100, min: 81, max: 85 }, + { part: 18, epart: 98, etotal: 100, min: 86, max: 90 }, + { part: 19, epart: 99, etotal: 100, min: 81, max: 95 }, + { part: 20, epart: 100, etotal: 100, min: 96, max: 100 } +]; + + +const reussites = [ + { code: "etotal", isPart: false, isSign: false, isSuccess: false, isEPart: true, isETotal: true, tache: -4, qualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 }, + { code: "epart", isPart: false, isSign: false, isSuccess: false, isEPart: true, isETotal: false, tache: -2, qualite: -4, quality: "Echec particulier", condition: (target, roll) => (roll >= target.epart && roll < target.etotal) }, + { code: "echec", isPart: false, isSign: false, isSuccess: false, isEPart: false, isETotal: false, tache: 0, qualite: -2, quality: "Echec normal", condition: (target, roll) => (roll > target.score && roll < target.etotal) }, + { code: "norm", isPart: false, isSign: false, isSuccess: true, isEPart: false, isETotal: false, tache: 1, qualite: 0, quality: "Réussite normale", condition: (target, roll) => (roll > target.sign && roll <= target.score) }, + { code: "sign", isPart: false, isSign: true, isSuccess: true, isEPart: false, isETotal: false, tache: 2, qualite: 1, quality: "Réussite significative", condition: (target, roll) => (roll > target.part && roll <= target.sign) }, + { code: "part", isPart: true, isSign: true, isSuccess: true, isEPart: false, isETotal: false, tache: 3, qualite: 2, quality: "Réussite Particulière!", condition: (target, roll) => (roll > 0 && roll <= target.part) }, + { code: "error", isPart: false, isSign: false, isSuccess: false, isEPart: true, isETotal: true, tache: 0, qualite: 0, quality: "Jet de dés invalide", condition: (target, roll) => (roll <= 0 || roll > 100) } +]; + +const reussiteSignificative = reussites.find(r => r.code == "sign"); +const reussiteNormale = reussites.find(r => r.code == "norm"); +const echecNormal = reussites.find(r => r.code == "echec"); + export class RdDResolutionTable { static resolutionTable = this.build() @@ -12,25 +66,71 @@ export class RdDResolutionTable { } /* -------------------------------------------- */ + static roll(carac, difficulte) { + return this.rollChances(this.computeChances(carac, difficulte)); + } + + static rollChances(chances) { + chances.roll = new Roll("d100").roll().total; + mergeObject(chances, this._computeReussite(chances, chances.roll)); + return chances; + } + + static computeChances(carac, difficulte) { + if (difficulte < -16) { + return duplicate(levelImpossible); + } + if (difficulte < -10) { + return duplicate(levelDown.find(levelData => levelData.level == difficulte)); + } + return duplicate(this.resolutionTable[carac][difficulte + 10]); + } + + static buildXpMessage(rolled, level) + { + if (rolled.isPart && level < 0) { + const xp = Math.abs(level); + const xpcarac = Math.floor(xp / 2); + const xpcomp = xp - xpcarac; + return "
Points d'expérience gagnés ! Carac: " + xpcarac + ", Comp: " + xpcomp; + } + return ""; + } + + + /* -------------------------------------------- */ + static _computeReussite(chances, roll) { + const reussite = reussites.find(x => x.condition(chances, roll)); + if (chances.needSignificative) { + if (reussite.isSign) { + return reussiteNormale; + } + if (reussite.isSuccess){ + return echecNormal; + } + } + return reussite; + } + static _computeRow(carac) { let dataRow = [ - this._computeScore(-10, Math.max(Math.floor(carac / 4), 1)), - this._computeScore(-9, Math.max(Math.floor(carac / 2), 1)) + this._computeCell(-10, Math.max(Math.floor(carac / 4), 1)), + this._computeCell(-9, Math.max(Math.floor(carac / 2), 1)) ] for (var diff = -8; diff <= 22; diff++) { - dataRow[diff + 10] = this._computeScore(diff, Math.max(Math.floor(carac * (diff + 10) / 2), 1)); + dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(carac * (diff + 10) / 2), 1)); } return dataRow; } - static _computeScore(diff, score) { + static _computeCell(niveau, percentage) { return { - niveau: diff, - score: score, - sign: this._reussiteSignificative(score), - part: this._reussitePart(score), - epart: this._echecParticulier(score), - etotal: this._echecTotal(score) + niveau: niveau, + score: percentage, + sign: this._reussiteSignificative(percentage), + part: this._reussitePart(percentage), + epart: this._echecParticulier(percentage), + etotal: this._echecTotal(percentage) } } diff --git a/module/rdd-roll-dialog.js b/module/rdd-roll-dialog.js index c66316ae..d56978be 100644 --- a/module/rdd-roll-dialog.js +++ b/module/rdd-roll-dialog.js @@ -1,5 +1,4 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js"; -import { RdDUtility } from "./rdd-utility.js"; /** * Extend the base Dialog entity by defining a custom window to perform roll. @@ -67,7 +66,7 @@ export class RdDRollDialog extends Dialog { rollData.finalLevel = rollLevel; rollData.finalLevelStr = (rollLevel > 0 ? "+" : "") + rollLevel; - rollData.rollTarget = RdDUtility.getResolutionField(rollData.selectedCarac.value, rollData.finalLevel); + rollData.rollTarget = RdDResolutionTable.computeChances(rollData.selectedCarac.value, rollData.finalLevel); $("#roll-param").text(rollData.selectedCarac.value + " / " + rollData.finalLevelStr); $("#compdialogTitle").text(RdDRollDialog._getTitle(rollData)); @@ -80,7 +79,8 @@ export class RdDRollDialog extends Dialog { // Update html, according to data if (rollData.competence) { // Set the default carac from the competence item - console.log(rollData.competence.data.defaut_carac, rollData.carac); + console.log("RdDDialogRoll", rollData.competence.data.defaut_carac, rollData.carac); + rollData.selectedCarac = rollData.carac[rollData.competence.data.defaut_carac]; $("#carac").val(rollData.competence.data.defaut_carac); } @@ -91,30 +91,32 @@ export class RdDRollDialog extends Dialog { // Update ! html.find('#bonusmalus').click((event) => { rollData.bmValue = event.currentTarget.value; // Update the selected bonus/malus - //console.log("BM CLICKED !!!", rollData.bmValue, rollData.competence.data.niveau, parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) ); + console.debug("RdDRollDialog","BM CLICKED !!!", rollData.bmValue, rollData.competence.data.niveau, parseInt(rollData.competence.data.niveau) + parseInt(rollData.bmValue) ); updateRollResult(rollData); }); html.find('#carac').click((event) => { let caracKey = event.currentTarget.value; rollData.selectedCarac = rollData.carac[caracKey]; // Update the selectedCarac - //console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); + console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); updateRollResult(rollData); }); html.find('#draconic').click((event) => { let draconicKey = event.currentTarget.value; rollData.selectedDraconic = rollData.draconicList[draconicKey]; // Update the selectedCarac - //console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); + console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); updateRollResult(rollData); }); html.find('#sort').click((event) => { let sortKey = event.currentTarget.value; rollData.selectedSort = rollData.sortList[sortKey]; // Update the selectedCarac - //console.log("CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); + console.debug("RdDRollDialog","CARAC CLICKED !!!", rollData.selectedCarac, rollData.competence.data.niveau, rollData.bmValue); updateRollResult(rollData); }); } + + /* -------------------------------------------- */ static _computeFinalLevel(rollData) { let etat = rollData.etat === undefined ? 0 : parseInt(rollData.etat); if (rollData.competence) { diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index b6dbea2c..d3a24fd2 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -5,6 +5,7 @@ import { RdDUtility } from "./rdd-utility.js"; import { TMRUtility } from "./tmr-utility.js"; import { RdDRollTables } from "./rdd-rolltables.js"; +import { RdDResolutionTable } from "./rdd-resolution-table.js"; /** Helper functions */ export class RdDTMRDialog extends Dialog { @@ -130,13 +131,14 @@ export class RdDTMRDialog extends Dialog { this.actor.deleteTMRRencontreAtPosition( ); // Remove the stored rencontre if necessary this.updatePreviousRencontres(); - let draconic = this.actor.getBestDraconic(); - let carac = this.actor.getCurrentReve(); - let level = draconic.data.niveau - this.currentRencontre.force; + const draconic = this.actor.getBestDraconic(); + const carac = this.actor.getCurrentReve(); + const difficulte = draconic.data.niveau - this.currentRencontre.force; console.log("Maitriser", carac, draconic.data.niveau, this.currentRencontre.force); - let scoreDef = CONFIG.RDD.resolutionTable[carac][level+10]; - let result = new Roll("d100").roll().total; - if ( result > scoreDef.score ) { + + const roll = RdDResolutionTable.roll(carac, difficulte); + + if ( roll.roll > scoreDef.score ) { TMRUtility.processRencontreEchec( this.actor, this.currentRencontre); ChatMessage.create( { title: "TMR", content: "Vous avez échoué à votre maîtrise d'un " . this.currentRencontre.name + " de force " + this.currentRencontre.force + @@ -232,46 +234,49 @@ export class RdDTMRDialog extends Dialog { this.close(); } - /* -------------------------------------------- */ - async manageCaseHumide( cellDescr ) { - if ( cellDescr.type == "lac" || cellDescr.type == "fleuve" || cellDescr.type == "marais" ) { + /* -------------------------------------------- */ + async manageCaseHumide(cellDescr) { + if (cellDescr.type == "lac" || cellDescr.type == "fleuve" || cellDescr.type == "marais") { let draconic = this.actor.getBestDraconic(); let carac = this.actor.getCurrentReve(); let level = draconic.data.niveau - 7; - let scoreDef = CONFIG.RDD.resolutionTable[carac][level+10]; - let result = new Roll("d100").roll().total; + let rolled = RdDResolutionTable.roll(carac, level);//RdDResolutionTable.computeChances(carac, level); + + console.log(">>>>", rolled); + + this.toclose = rolled.isSuccess; let content = ""; - let mycallback; - console.log(">>>>", scoreDef); - if ( result > scoreDef.score ) { - content = "Vous êtes entré sur une case humide, et vous avez raté votre maîtrise ! Vous quittez les Terres Médianes ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score; - if ( result >= scoreDef.etotal ) { - let souffle = RdDRollTables.getSouffle(true); - content += "
Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name ; - this.actor.createOwnedItem( souffle ); - } - this.toclose = true; - } else { - content = "Vous êtes entré sur une case humide, et vous avez réussi votre maîtrise ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score; - if ( result <= scoreDef.part ) { - content += "
Vous avez fait une Réussite Particulière"; - if ( level < 0 ) { - let xpcarac = Math.floor( Math.abs(level) / 2); - let xpcomp = (Math.abs(level) % 2 == 1) ? xpcarac+1 : xpcarac; - content += "
Points d'expérience gagné ! " + xpcarac + " - " + xpcomp; + if (!rolled.isSuccess) { + content += "Vous êtes entré sur une case humide, et vous avez raté votre maîtrise ! Vous quittez les Terres Médianes !" + } + else { + content += "Vous êtes entré sur une case humide, et vous avez réussi votre maîtrise !" + } + + content += " " + draconic.name + ": " + carac + " / " + level + " -> " + rolled.roll + " / " + rolled.score; + + if (rolled.isETotal) { + let souffle = RdDRollTables.getSouffle(true); + content += "
Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name; + this.actor.createOwnedItem(souffle); + } + if (rolled.isPart) { + content += "
Vous avez fait une Réussite Particulière"; + content += RdDResolutionTable.buildXpMessage(rolled, level) + } + + let humideDiag = new Dialog({ + title: "Case humide", + content: content, + buttons: { + choice: { + icon: '', + label: "Fermer", + callback: () => this.manageCaseHumideResult() } } } - let humideDiag = new Dialog( {title: "Case humide", - content: content, - buttons: { - choice: { icon: '', - label: "Fermer", - callback: () => this.manageCaseHumideResult() - } - } - } - ); + ); humideDiag.render(true); } } diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 47910657..5e71b654 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -22,39 +22,11 @@ const competence_xp = { "-6" : [ 10, 20, 35, 50, 65, 80, 100, 120, 140], "-4" : [ 15, 30, 45, 60, 80, 100, 120] } + // This table starts at 0 -> niveau -10 const competence_xp_par_niveau = [ 5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100]; const carac_array = [ "taille", "apparence", "constitution", "force", "agilite", "dexterite", "vue", "ouie", "odoratgout", "volonte", "intellect", "empathie", "reve", "chance", "melee", "tir", "lancer", "derobee"]; const bonusmalus = [-10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10]; -const specialResults = [ { "part": 0, "epart": 0, "etotal": 0 }, // 0 - { "part": 1, "epart": 81, "etotal": 92 }, // 01-05 - { "part": 2, "epart": 82, "etotal": 92 }, // 06-10 - { "part": 3, "epart": 83, "etotal": 93 }, // 11-15 - { "part": 4, "epart": 84, "etotal": 93 }, // 16-20 - { "part": 5, "epart": 85, "etotal": 94 }, // 21-25 - { "part": 6, "epart": 86, "etotal": 94 }, // 26-30 - { "part": 7, "epart": 87, "etotal": 95 }, // 31-35 - { "part": 8, "epart": 88, "etotal": 95 }, // 36-40 - { "part": 9, "epart": 89, "etotal": 96 }, // 41-45 - { "part": 10, "epart": 90, "etotal": 96 }, // 46-50 - { "part": 11, "epart": 91, "etotal": 97 }, // 51-55 - { "part": 12, "epart": 92, "etotal": 97 }, // 56-60 - { "part": 13, "epart": 93, "etotal": 98 }, // 61-65 - { "part": 14, "epart": 94, "etotal": 98 }, // 65-70 - { "part": 15, "epart": 95, "etotal": 99 }, // 71-75 - { "part": 16, "epart": 96, "etotal": 99 }, // 76-80 - { "part": 17, "epart": 97, "etotal": 100 }, // 81-85 - { "part": 18, "epart": 98, "etotal": 100 }, // 86-90 - { "part": 19, "epart": 99, "etotal": 100 }, // 81-95 - { "part": 20, "epart": 100, "etotal": 100 } // 96-00 - ]; -const levelDown = [ { "level": -11, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 90 }, - { "level": -12, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 70 }, - { "level": -13, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 50 }, - { "level": -14, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 30 }, - { "level": -15, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 10 }, - { "level": -16, "score": 1, "sign": 0, "part": 0, "epart": 2, "etotal": 2 } - ]; const fatigueMatrix = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // Dummy filler for the array. [2, 3, 3, 2, 3, 3, 2, 3, 3, 2, 3, 3 ], [2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3 ], @@ -239,18 +211,6 @@ export class RdDUtility { return false; } - /* -------------------------------------------- */ - static getResolutionField(caracValue, levelValue ) - { - if ( levelValue < -16 ) { - return { score: 0, sign:0, part: 0, epart: 1, etotal: 1}; - } - if ( levelValue < -10 ) { - return levelDown.find(levelData => levelData.level == levelValue); - } - return CONFIG.RDD.resolutionTable[caracValue][levelValue+10]; - } - /* -------------------------------------------- */ static computeCompetenceXPCost( competence ) { From bc32cd1ad4bb754a6dd81ad45dd4ce0c8dc381fb Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 12 Nov 2020 18:41:43 +0100 Subject: [PATCH 3/5] Simplification des recherches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit + fix: ne pas chercher les compétences ailleurs que dans les compétences --- module/actor.js | 22 ++++++---------------- module/rdd-utility.js | 7 +------ 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/module/actor.js b/module/actor.js index 0b61b321..031d20f6 100644 --- a/module/actor.js +++ b/module/actor.js @@ -671,24 +671,14 @@ export class RdDActor extends Actor { new RdDRollDialog("carac", html, rollData, this ).render(true); } - /* -------------------------------------------- */ - getSortList( ) { - let sortList = [] - for (const item of this.data.items) { - if (item.type == "sort" ) - sortList.push(item); - } - return sortList; + /* -------------------------------------------- */ + getSortList() { + return this.data.items.filter(item => item.type == "sort"); } - /* -------------------------------------------- */ - getDraconicList( ) { - let draconicList = [] - for (const item of this.data.items) { - if (item.type == "competence" && item.data.categorie == 'draconic' ) - draconicList.push(item); - } - return draconicList; + /* -------------------------------------------- */ + getDraconicList() { + return this.data.items.filter(item => item.data.categorie == 'draconic') } /* -------------------------------------------- */ diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 5e71b654..fe5b48ef 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -411,12 +411,7 @@ export class RdDUtility { /* -------------------------------------------- */ static findCompetence(compList, compName) { - for (const item of compList) { - if (item.name == compName) { - //console.log("Found item !", item); - return item; - } - } + return compList.find(item => item.name == compName && (item.type =="competence" || item.type =="competencecreature")) } /* -------------------------------------------- */ From 1cb7d1f251231ece162ac6bb271e4f75cb57ae94 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 12 Nov 2020 18:42:41 +0100 Subject: [PATCH 4/5] Fix regression /table --- module/rdd-rolltables.js | 52 +++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js index 0cf0a1cb..5f06a355 100644 --- a/module/rdd-rolltables.js +++ b/module/rdd-rolltables.js @@ -1,45 +1,43 @@ export class RdDRollTables { - + /* -------------------------------------------- */ - static async genericGetTableResult( tableName, toChat) - { - let pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses"); - await pack.getIndex(); - let entry = pack.index.find(e => e.name === tableName); - let rollQueues = await pack.getEntity(entry._id); - let result = await rollQueues.draw( { displayChat: toChat } ); - console.log("CAT", result); + static async genericGetTableResult(tableName, toChat) { + const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses"); + const index = await pack.getIndex(); + const entry = index.find(e => e.name === tableName); + const table = await pack.getEntity(entry._id); + const result = await table.draw({ displayChat: toChat }); + console.log("RdDRollTables", tableName, toChat, ":", result); return result; } - + /* -------------------------------------------- */ - static async getSouffle( toChat ) { - return genericGetTableResult( "Souffles de Dragon", toChat); + static async getSouffle(toChat) { + return RdDRollTables.genericGetTableResult("Souffles de Dragon", toChat); } /* -------------------------------------------- */ - static async getQueue( toChat = true) { - return genericGetTableResult( "Queues de dragon", toChat); + static async getQueue(toChat = true) { + return RdDRollTables.genericGetTableResult("Queues de dragon", toChat); } /* -------------------------------------------- */ - static async getTete( toChat = true ) { - return genericGetTableResult( "Têtes de Dragon pour haut-rêvants", toChat); - } - - /* -------------------------------------------- */ - static async getTeteHR( toChat = true ) { - return genericGetTableResult( "Têtes de Dragon pour tous personnages", toChat); + static async getTete(toChat = true) { + return RdDRollTables.genericGetTableResult("Têtes de Dragon pour haut-rêvants", toChat); } /* -------------------------------------------- */ - static async getOmbre( toChat = true ) { - return genericGetTableResult( "Ombre de Thanatos", toChat); + static async getTeteHR(toChat = true) { + return RdDRollTables.genericGetTableResult("Têtes de Dragon pour tous personnages", toChat); } /* -------------------------------------------- */ - static async getTarot( toChat = true ) { - return genericGetTableResult( "Tarot Draconique", toChat); + static async getOmbre(toChat = true) { + return RdDRollTables.genericGetTableResult("Ombre de Thanatos", toChat); } - -} \ No newline at end of file + + /* -------------------------------------------- */ + static async getTarot(toChat = true) { + return RdDRollTables.genericGetTableResult("Tarot Draconique", toChat); + } +} From 6b50dc20d6315b0b4a11f6b88090f82e3be788a7 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 12 Nov 2020 18:44:47 +0100 Subject: [PATCH 5/5] Clean Recontres MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1d7 ne peut pas être 8 --- module/rdd-tmr-dialog.js | 26 +++++++------------------- module/tmr-utility.js | 7 ++++--- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index d3a24fd2..255fa290 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -159,28 +159,16 @@ export class RdDTMRDialog extends Dialog { async manageRencontre(coordTMR, cellDescr) { // Roll until diffent than '8' - let rencontre this.currentRencontre = undefined; - for (let previousRencontre of this.rencontresExistantes ) { - if ( previousRencontre.coord == coordTMR) - rencontre = previousRencontre.rencontre; + + let rencontre = this.rencontresExistantes.find(prev => prev.coord == coordTMR); + if (rencontre == undefined && new Roll("d7").roll().total == 7) { + rencontre = TMRUtility.rencontreTMRRoll(coordTMR, cellDescr); } - if ( rencontre == undefined ) { - let val = 8; - while (val == 8) { - let myroll = new Roll("d7"); - myroll.roll(); - val = myroll.total; - if ( val == 7 ) { - rencontre = TMRUtility.rencontreTMRRoll(coordTMR, cellDescr); - rencontre.force = new Roll(rencontre.data.force).roll().total; - } - } - } - + if (rencontre) { // Manages it this.currentRencontre = duplicate(rencontre); - let diag = new Dialog( { title: "Rencontre en TMR!", + let dialog = new Dialog( { title: "Rencontre en TMR!", content: "Vous recontrez un " + rencontre.name + " de force " + rencontre.force + "
", buttons: { derober: { @@ -200,7 +188,7 @@ export class RdDTMRDialog extends Dialog { } } } ); - diag.render(true); + dialog.render(true); } } diff --git a/module/tmr-utility.js b/module/tmr-utility.js index b3df2293..7ed0a3b1 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -269,13 +269,14 @@ export class TMRUtility { let val = new Roll("d100").roll().total; //console.log("Rencontre !!!!", val, coordTMR, cellDescr); - for( let renc of rencontresTable) { - let scoreDef = renc.data[cellDescr.type]; + for( let rencontre of rencontresTable) { + let scoreDef = rencontre.data[cellDescr.type]; let min = scoreDef.substr(0,2); let max = scoreDef.substr(3,2); //console.log(val, scoreDef, min, max); if ( val >= min && val <= max) { - return renc; + rencontre.force = new Roll(rencontre.data.force).roll().total; + return rencontre; } } }