diff --git a/module/actor.js b/module/actor.js
index c99fd5e6..031d20f6 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 {
@@ -91,20 +92,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);
@@ -122,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 {
@@ -271,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 )
{
@@ -638,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();
@@ -727,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-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-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);
+ }
+}
diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js
index b6dbea2c..255fa290 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 +
@@ -157,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: {
@@ -198,7 +188,7 @@ export class RdDTMRDialog extends Dialog {
}
}
} );
- diag.render(true);
+ dialog.render(true);
}
}
@@ -232,46 +222,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..fe5b48ef 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 )
{
@@ -451,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"))
}
/* -------------------------------------------- */
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;
}
}
}