RdDResolutionTable rolls
This commit is contained in:
parent
1fc3bf22f5
commit
5fa703241a
279
module/actor.js
279
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 = "<br>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 = "<br>Points de taches : " + rolled.tache + ", Points de qualité: " + rolled.qualite;
|
||||
|
||||
// Fight management !
|
||||
let defenseMsg;
|
||||
let encaisser = false;
|
||||
let specialStr = "<br>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 = "<br><strong>Attaque parée/esquivée !</strong>";
|
||||
} else {
|
||||
specialStr = "<br><strong>Esquive/Parade échouée, encaissement !</strong>";
|
||||
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 = "<br><strong>Cible</strong> : " + target.actor.data.name;
|
||||
}
|
||||
specialStr += "<br>Dommages : " + rollData.degats + "<br>Localisation : " + rollData.loc.label;
|
||||
} else {
|
||||
specialStr = "<br>Echec ! Pas de dommages";
|
||||
specialStr = "<br>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 = "<br>Lancement du sort <strong>" + rollData.selectedSort.name + "</strong> : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte +
|
||||
"/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve;
|
||||
specialStr = "<br>Lancement du sort <strong>" + rollData.selectedSort.name + "</strong> : " + draconic.charAt(0).toUpperCase() + draconic.slice(1) + "/" + rollData.selectedSort.data.difficulte +
|
||||
"/" + rollData.selectedSort.data.caseTMR + "/R" + rollData.selectedSort.data.ptreve;
|
||||
specialStr += "<br>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 += "<br>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 += "<br><strong>Echec TOTAL</strong> du sort : " + costReve + " Points de Rêve";
|
||||
} else {
|
||||
} else {
|
||||
specialStr += "<br>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: "<strong>Test : " + rollData.selectedCarac.label + " / " + lvl + "</strong><br>Jet : " +
|
||||
rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rollData.rollTarget.score + "%<br><strong>Résutat : </strong>" + result + "<br>" +
|
||||
"<strong>" + quality + "</strong>" + specialStr + xpmsg,
|
||||
user: game.user._id,
|
||||
title: "Résultat du test"
|
||||
}
|
||||
ChatMessage.create( chatOptions );
|
||||
|
||||
let chatOptions = {
|
||||
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + lvl + "</strong><br>Jet : " +
|
||||
rollData.selectedCarac.value + " / " + rollData.finalLevelStr + " -> " + rolled.score + "%<br><strong>Résutat : </strong>" + result + "<br>" +
|
||||
"<strong>" + quality + "</strong>" + 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();
|
||||
|
||||
|
@ -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 "<br>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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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 <strong>échoué</strong> à 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 <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score;
|
||||
if ( result >= scoreDef.etotal ) {
|
||||
let souffle = RdDRollTables.getSouffle(true);
|
||||
content += "<br>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 <strong>réussi</strong> votre maîtrise ! ("+ draconic.name +") :" + carac + " / " + level + " -> " + result + " / " + scoreDef.score;
|
||||
if ( result <= scoreDef.part ) {
|
||||
content += "<br>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 += "<br>Points d'expérience gagné ! " + xpcarac + " - " + xpcomp;
|
||||
if (!rolled.isSuccess) {
|
||||
content += "Vous êtes entré sur une case humide, et vous avez <strong>raté</strong> votre maîtrise ! Vous <strong>quittez les Terres Médianes</strong> !"
|
||||
}
|
||||
else {
|
||||
content += "Vous êtes entré sur une case humide, et vous avez <strong>réussi</strong> votre maîtrise !"
|
||||
}
|
||||
|
||||
content += " " + draconic.name + ": " + carac + " / " + level + " -> " + rolled.roll + " / " + rolled.score;
|
||||
|
||||
if (rolled.isETotal) {
|
||||
let souffle = RdDRollTables.getSouffle(true);
|
||||
content += "<br>Vous avez fait un Echec Total. Vous subissez un Souffle de Dragon : " + souffle.name;
|
||||
this.actor.createOwnedItem(souffle);
|
||||
}
|
||||
if (rolled.isPart) {
|
||||
content += "<br>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: '<i class="fas fa-check"></i>',
|
||||
label: "Fermer",
|
||||
callback: () => this.manageCaseHumideResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
let humideDiag = new Dialog( {title: "Case humide",
|
||||
content: content,
|
||||
buttons: {
|
||||
choice: { icon: '<i class="fas fa-check"></i>',
|
||||
label: "Fermer",
|
||||
callback: () => this.manageCaseHumideResult()
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
);
|
||||
humideDiag.render(true);
|
||||
}
|
||||
}
|
||||
|
@ -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 )
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user