diff --git a/icons/moral-heureux.svg b/icons/moral-heureux.svg
new file mode 100644
index 00000000..60be4967
--- /dev/null
+++ b/icons/moral-heureux.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/icons/moral-malheureux.svg b/icons/moral-malheureux.svg
new file mode 100644
index 00000000..d4b32e93
--- /dev/null
+++ b/icons/moral-malheureux.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/icons/moral-neutre.svg b/icons/moral-neutre.svg
new file mode 100644
index 00000000..e9361418
--- /dev/null
+++ b/icons/moral-neutre.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/module/actor-sheet.js b/module/actor-sheet.js
index 5792026f..d0f05218 100644
--- a/module/actor-sheet.js
+++ b/module/actor-sheet.js
@@ -450,6 +450,18 @@ export class RdDActorSheet extends ActorSheet {
this.actor.stressTest();
this.render(true);
});
+ html.find('#moral-malheureux').click((event) => {
+ this.actor.jetDeMoral('malheureuse');
+ this.render(true);
+ });
+ html.find('#moral-neutre').click((event) => {
+ this.actor.jetDeMoral('neutre');
+ this.render(true);
+ });
+ html.find('#moral-heureux').click((event) => {
+ this.actor.jetDeMoral('heureuse');
+ this.render(true);
+ });
html.find('#ethylisme-test').click((event) => {
this.actor.ethylismeTest();
this.render(true);
diff --git a/module/actor.js b/module/actor.js
index d2375ce2..c30866b2 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -125,6 +125,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
getBonusDegat() {
+ // TODO: gérer séparation et +dom créature/entité indépendament de la compétence
return Misc.toInt(this.data.data.attributs.plusdom.value);
}
@@ -169,54 +170,13 @@ export class RdDActor extends Actor {
}
}
- /* -------------------------------------------- */
- async performRoll(rollData, attacker = undefined) {
- rollData.surprise = this.getSurprise();
-
- // Manage weapon categories when parrying (cf. page 115 )
- if (rollData.arme && rollData.attackerRoll) { // Manage parade depending on weapon type, and change roll results
- let attCategory = RdDItemArme.getCategorieArme(rollData.attackerRoll.arme);
- let defCategory = RdDItemArme.getCategorieArme(rollData.arme);
- if (defCategory == "bouclier")
- rollData.needSignificative = false;
- else if (attCategory != defCategory)
- rollData.needSignificative = true;
- // Do we need to make resistance roll for defender ?
- if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"))
- rollData.needResist = true;
- }
- if (!this.isEntiteCauchemar() && rollData.particuliereAttaque == "finesse") {
- rollData.needSignificative = true;
- }
-
- // garder le résultat
- await RdDResolutionTable.rollData(rollData);
-
- //console.log("performRoll", rollData)
- if ( !rollData.attackerRoll) {// Store in the registry if not a defense roll
- game.system.rdd.rollDataHandler[this.data._id] = rollData;
- }
-
- if (rollData.rolled.isPart && rollData.arme && !rollData.attackerRoll) { // Réussite particulière avec attaque -> choix !
- let message = "Réussite particulière en attaque";
- message = message + "
Attaquer en Force";
- // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
- if (rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0 ) {
- message = message + "
Attaquer en Rapidité";
- message = message + "
Attaquer en Finesse";
- }
- ChatMessage.create( {content : message, whisper: ChatMessage.getWhisperRecipients( this.name ) } );
- } else {
- this.continueRoll(rollData, attacker);
- }
- }
/* -------------------------------------------- */
async computeDeteriorationArme( rollData ) {
const attackerRoll = rollData.attackerRoll;
if (rollData.arme && attackerRoll) { // C'est une parade
// Est-ce que l'attaque est une particulière, en force ou charge et que l'attaque n'en est pas une ?
- if ( (rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.isCharge)
+ if ( (rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.tactique == 'charge')
&& !rollData.rolled.isPart ) {
const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor;
let resistance = Misc.toInt(rollData.arme.data.resistance);
@@ -252,7 +212,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async computeRecul( rollData, encaisser = undefined ) { // Calcul du recul (p. 132)
if ( rollData.arme || encaisser ) {
- if ( (rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.isCharge) {
+ if ( (rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.tactique == 'charge') {
let reculNiveau = Misc.toInt(this.data.data.carac.taille.value) - (rollData.attackerRoll.forceValue+rollData.attackerRoll.arme.data.dommagesReels);
let recul = await RdDResolutionTable.roll( 10, reculNiveau );
let msg = "";
@@ -273,103 +233,12 @@ export class RdDActor extends Actor {
}
}
- /* -------------------------------------------- */
- async continueRoll(rollData, attacker = undefined) {
- let rolled = rollData.rolled;
- let quality = rolled.quality
-
- console.log(">>> ROLL", rollData, rolled);
- this._appliquerAjoutExperience(rollData)
-
- let resumeCompetence = (rollData.competence) ? rollData.competence.name : (rollData.diffLibre + rollData.diffConditions);
- let explications = "
Points de taches : " + rolled.ptTache + ", ajustement qualité: " + rolled.ptQualite;
-
- // Fight management !
- let defenseMsg;
- let encaisser = false;
- if (rollData.arme || (rollData.competence && rollData.competence.name.toLowerCase() == 'esquive') ) {
- explications = ""
- // 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.isSign || (!rollData.needSignificative && rolled.isSuccess)) {
- await this.computeDeteriorationArme( rollData );
- explications += "
Attaque parée/esquivée !";
- } else {
- explications += "
Esquive/Parade échouée, encaissement !";
- if (rollData.needSignificative)
- explications += " Significative nécessaire!";
- }
- encaisser = rollData.needSignificative ? !rolled.isSign : !rolled.isSuccess;
- await this.computeRecul( rollData, encaisser );
- } else { // This is the attack roll!
- if (rolled.isSuccess) {
- let target = this._getTarget();
- if (await this.targetEntiteNonAccordee(target, 'avant-defense')) {
- return;
- }
-
- // Message spécial pour la rapidité, qui reste difficile à gérer automatiquement
- if ( rollData.particuliereAttaque == 'rapidite') {
- ChatMessage.create( { content: "Vous avez attaqué en Rapidité. Ce cas n'est pas géré autmatiquement, donc suivez les directives de votre MJ pour gérer ce cas.",
- whisper: ChatMessage.getWhisperRecipients( this.name ) } );
- }
-
- rollData.dmg = RdDCombat.calculBonusDegats(rollData, this);
-
- if (target)
- {
- rollData.mortalite = RdDActor._calculMortaliteEncaissement(rollData, target);
- defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData);
- explications += "
Cible : " + target.actor.data.name;
- }
- explications += "
Encaissement : " + rollData.degats + "
Localisation : " + rollData.dmg.loc.label;
- } else {
- explications = "
Echec ! Pas de dégâts";
- }
- }
- }
-
- // Save it for fight in the flags area
- game.system.rdd.rollDataHandler[this.data._id] = duplicate(rollData);
-
- // Final chat message
- let chatOptions = {
- content: "Test : " + rollData.selectedCarac.label + " / " + resumeCompetence + ""
- + "
Difficultés libre : " + rollData.diffLibre + " / conditions : " + Misc.toSignedString(rollData.diffConditions) +" / état : " + rollData.etat
- + RdDResolutionTable.explain(rolled)
- + explications
- }
-
- ChatUtility.chatWithRollMode(chatOptions, this.name)
-
- // This an attack, generate the defense message
- if (defenseMsg) {
- defenseMsg.rollData = duplicate(rollData);
- if (defenseMsg.toSocket) {
- game.socket.emit("system.foundryvtt-reve-de-dragon", {
- msg: "msg_defense",
- data: defenseMsg
- });
- if ( game.user.isGM ) { // Always push the message to the MJ
- ChatMessage.create(defenseMsg);
- }
- } else {
- defenseMsg.whisper = [game.user];
- ChatMessage.create(defenseMsg);
- }
- }
-
- // Get damages!
- if (encaisser) {
- this.encaisserDommages(rollData.attackerRoll, attacker);
- }
- }
-
/* -------------------------------------------- */
getSurprise() {
if (this.isEntiteCauchemar()) {
return '';
}
+ // TODO: gérer une liste de flags demi-surprise (avec icône sur le token)?
if ( this.data.data.sante.sonne.value) {
return 'demi';
}
@@ -386,13 +255,6 @@ export class RdDActor extends Actor {
return this.getSurprise() == 'totale';
}
- /* -------------------------------------------- */
- static _calculMortaliteEncaissement(rollData, target) {
- const mortalite = target.actor.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
- console.log("Mortalité : ", mortalite, target.actor.data.type);
- return mortalite;
- }
-
/* -------------------------------------------- */
async dormirChateauDormant() {
let message = {
@@ -1189,6 +1051,45 @@ export class RdDActor extends Actor {
this.update( { "data.blessures": blessures } );
}
+ async jetDeMoral(situation) {
+ let jetMoral = new Roll("1d20").roll();
+ RdDDice.show(jetMoral);
+ let compteurs = duplicate(this.data.data.compteurs);
+ compteurs.moral.value = Misc.toInt(compteurs.moral.value);
+ const succes = jetMoral.total <= 10 + compteurs.moral.value;
+ let ajustementMoral = this._calculAjustementMoral(succes, compteurs.moral, situation);
+ if (ajustementMoral != 0) {
+ compteurs.moral.value += ajustementMoral;
+ if (compteurs.moral.value>3) {
+ // exaltation
+ compteurs.moral.value --;
+ compteurs.exaltation.value = Misc.toInt(compteurs.exaltation.value) + 1;
+ }
+ if (compteurs.moral.value<-3) {
+ // dissolution
+ compteurs.moral.value ++;
+ compteurs.dissolution.value = Misc.toInt(compteurs.dissolution.value) + 1;
+ }
+ await this.update( { 'data.compteurs': compteurs} );
+ }
+ ChatMessage.create({
+ whisper: ChatMessage.getWhisperRecipients(game.user.name),
+ content: "Jet de moral ("+ jetMoral.total + ")" + (succes? "réussi": "manqué") + " en situation "+situation+", vous "+(ajustementMoral>0? "gagnez du moral":ajustementMoral<0? "perdez du moral": "gardez votre moral")
+ });
+ }
+
+ _calculAjustementMoral(succes, moral, situation)
+ {
+ switch (situation) {
+ case 'heureuse': return succes ? 1 : 0;
+ case 'malheureuse':return succes ? 0 : -1;
+ case 'neutre':
+ if (succes && moral <= 0) return 1;
+ if (!succes && moral > 0) return -1;
+ }
+ return 0;
+
+ }
/* -------------------------------------------- */
async ethylismeTest() {
let rollData = {
@@ -1648,7 +1549,7 @@ export class RdDActor extends Actor {
// Cas de désir lancinant, pas d'expérience sur particulière
if ( this.checkDesirLancinant() ) {
ChatMessage.create( { content: `Vous souffrez au moins d'un Désir Lancinant, vous ne pouvez pas gagner d'expérience sur une Particulière tant que le désir n'est pas assouvi`,
- whisper: ChatMessage.getWhisperRecipients(game.user.name) } ).create();
+ whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
return { result:false, xpcarac:0, xpCompetence: 0 };
}
@@ -1672,7 +1573,7 @@ export class RdDActor extends Actor {
await this.update( {"data.carac": carac } );
} else {
ChatMessage.create( { content: `Vous avez ${xpCarac} à répartir pour la caractérisque dérivée ${caracName}. Vous devez le faire manuellement.`,
- whisper: ChatMessage.getWhisperRecipients(game.user.name) } ).create();
+ whisper: ChatMessage.getWhisperRecipients(game.user.name) } );
}
return { result:true, xpcarac:xpCarac, xpCompetence: xpComp }; //XP
}
@@ -1866,7 +1767,7 @@ export class RdDActor extends Actor {
armure: armure
}).roll();
RdDDice.show(rollEncaissement);
- let result = RdDUtility.computeBlessuresSante(rollEncaissement.total, attackerRoll.mortalite, attackerRoll.dmg.loc);
+ let result = RdDUtility.computeBlessuresSante(rollEncaissement.total, attackerRoll.dmg.mortalite, attackerRoll.dmg.loc);
result.endurance = Math.max(result.endurance, -Number(this.data.data.sante.endurance.value));
await this.santeIncDec("vie", result.vie);
await this.santeIncDec("endurance", result.endurance, (result.critiques > 0));
diff --git a/module/item-arme.js b/module/item-arme.js
index cb5e587e..feedde73 100644
--- a/module/item-arme.js
+++ b/module/item-arme.js
@@ -44,26 +44,34 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */
static armeUneOuDeuxMains(arme, aUneMain) {
- arme.data.unemain = arme.data.unemain || !arme.data.deuxmains;
- const uneOuDeuxMains = arme.data.unemain && arme.data.deuxmains;
- const containsSlash = !Number.isInteger(arme.data.dommages) && arme.data.dommages.includes("/");
- if (containsSlash) { // Sanity check
- arme = duplicate(arme);
+ if (arme) {
+ arme.data.unemain = arme.data.unemain || !arme.data.deuxmains;
+ const uneOuDeuxMains = arme.data.unemain && arme.data.deuxmains;
+ const containsSlash = !Number.isInteger(arme.data.dommages) && arme.data.dommages.includes("/");
+ if (containsSlash) { // Sanity check
+ arme = duplicate(arme);
- const tableauDegats = arme.data.dommages.split("/");
- if (aUneMain)
- arme.data.dommagesReels = Number(tableauDegats[0]);
- else // 2 mains
- arme.data.dommagesReels = Number(tableauDegats[1]);
- }
- else {
- arme.data.dommagesReels = Number(arme.data.dommages);
- }
+ const tableauDegats = arme.data.dommages.split("/");
+ if (aUneMain)
+ arme.data.dommagesReels = Number(tableauDegats[0]);
+ else // 2 mains
+ arme.data.dommagesReels = Number(tableauDegats[1]);
+ }
+ else {
+ arme.data.dommagesReels = Number(arme.data.dommages);
+ }
- if (uneOuDeuxMains != containsSlash) {
- ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
+ if (uneOuDeuxMains != containsSlash) {
+ ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
+ }
}
return arme;
}
+ static mainsNues() {
+ return {
+ name: "Mains nues",
+ data: { unemain: true, deuxmains: false, dommages: 0, dommagesReels: 0, mortalite: 'non-mortel' }
+ }
+ }
}
diff --git a/module/rdd-bonus.js b/module/rdd-bonus.js
new file mode 100644
index 00000000..88c6d1b2
--- /dev/null
+++ b/module/rdd-bonus.js
@@ -0,0 +1,86 @@
+import { RdDUtility } from "./rdd-utility.js";
+
+const conditionsTactiques = [
+ { type: '', descr: '', dmg: 0, attaque: 0, parade: 0, esquive: true },
+ { type: 'charge', descr: 'Charge', dmg: 2, attaque: 4, parade: -4, esquive: false },
+ { type: 'feinte', descr: 'Feinte', dmg: 1, attaque: 1, parade: 0, esquive: true },
+ { type: 'pret', descr: 'prêt', dmg: 0, attaque: 0, parade: 0, esquive: true },
+ { type: 'demi', descr: 'Demi-surprise', dmg: 1, attaque: 0, parade: 0, esquive: true },
+ { type: 'totale', descr: 'Surprise totale', dmg: 10, attaque: 6, parade: 0, esquive: true },
+];
+
+/* -------------------------------------------- */
+export class RdDBonus {
+
+ /* -------------------------------------------- */
+ static _find(condition) {
+ return conditionsTactiques.find(e => e.type == condition) || conditionsTactiques.find(e => e.type == 'pret');
+ }
+
+ /* -------------------------------------------- */
+ static dmg(rollData, dmgActor, isCauchemar = false) {
+ let dmg = { total: 0, loc: RdDUtility.getLocalisation() };
+ if (rollData.arme && rollData.arme.name.toLowerCase() == "esquive") {
+ // Specific case management
+ ui.notifications.warn("Calcul de bonus dégats sur eswquive");
+ } else {
+ dmg.dmgArme = RdDBonus._dmgArme(rollData);
+ dmg.ignoreArmure = 0; // TODO: calculer pour arcs et arbaletes, gérer pour lmes créatures
+ dmg.dmgTactique = RdDBonus.dmgBonus(rollData.tactique);
+ dmg.dmgParticuliere = RdDBonus._dmgParticuliere(rollData);
+ dmg.dmgSurprise = RdDBonus.dmgBonus(rollData.surpriseDefenseur);
+ dmg.dmgActor = rollData.selectedCarac ? RdDBonus._dmgPerso(dmgActor, rollData.selectedCarac.label, dmg.dmgArme) : 0;
+ dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
+ dmg.mortalite = RdDBonus._calculMortalite(rollData, isCauchemar)
+ }
+ return dmg;
+ }
+
+ /* -------------------------------------------- */
+ static description(condition) {
+ return RdDBonus._find(condition).descr;
+ }
+
+ /* -------------------------------------------- */
+ static dmgBonus(condition) {
+ return RdDBonus._find(condition).dmg;
+ }
+
+ /* -------------------------------------------- */
+ static bonusAttaque(condition) {
+ return RdDBonus._find(condition).attaque;
+ }
+
+ /* -------------------------------------------- */
+ static _calculMortalite(rollData, isCauchemar) {
+ if (isCauchemar){
+ return "cauchemar";
+ }if (rollData.dmg && rollData.dmg.mortalite) {
+ return rollData.dmg.mortalite;
+ }
+ if (rollData.arme && rollData.arme.data.mortalite) {
+ return rollData.arme.data.mortalite;
+ }
+ return "mortel";
+ }
+
+ /* -------------------------------------------- */
+ static _dmgArme(rollData) {
+ return rollData.arme ? parseInt(rollData.arme.data.dommages) : 0;
+ }
+
+ /* -------------------------------------------- */
+ static _dmgPerso(dmgActor, categorie, dmgArme) {
+ switch (categorie) {
+ case "Tir": return 0;
+ case "Lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
+ }
+ return dmgActor;
+ }
+
+ /* -------------------------------------------- */
+ static _dmgParticuliere(rollData) {
+ return rollData.particuliereAttaque == 'force' ? 5 : 0;
+ }
+
+}
\ No newline at end of file
diff --git a/module/rdd-combat.js b/module/rdd-combat.js
index 05ceae6f..be291876 100644
--- a/module/rdd-combat.js
+++ b/module/rdd-combat.js
@@ -1,11 +1,10 @@
-import { RdDActor } from "./actor.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js";
+import { RdDBonus } from "./rdd-bonus.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js";
-import { RdDUtility } from "./rdd-utility.js";
export class RdDCombat {
@@ -80,7 +79,6 @@ export class RdDCombat {
ui.notifications.warn("Action automatisée impossible, le jet de l'attaquant a été perdu (suite à un raffraichissement?)")
return;
}
- // TODO: enlever le ChatMessage?
switch (button) {
case '#particuliere-attaque': return await this.choixParticuliere(rollData, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': return this.parade(rollData, event.currentTarget.attributes['data-armeid'].value);
@@ -89,6 +87,41 @@ export class RdDCombat {
}
}
+
+ /* -------------------------------------------- */
+ static isEchec(rollData) {
+ switch (rollData.surprise) {
+ case 'demi': return !rollData.rolled.isSign;
+ case 'totale': return true;
+ }
+ return rollData.rolled.isEchec;
+ }
+
+ /* -------------------------------------------- */
+ static isEchecTotal(rollData) {
+ if (rollData.arme && rollData.surprise == 'demi') {
+ return rollData.rolled.isEchec;
+ }
+ return rollData.rolled.isETotal;
+ }
+
+ /* -------------------------------------------- */
+ static isParticuliere(rollData) {
+ if (rollData.arme && rollData.surprise) {
+ return false;
+ }
+ return rollData.rolled.isPart;
+ }
+
+ /* -------------------------------------------- */
+ static isReussite(rollData) {
+ switch (rollData.surprise) {
+ case 'demi': return rollData.rolled.isSign;
+ case 'totale': return false;
+ }
+ return rollData.rolled.isSuccess;
+ }
+
/* -------------------------------------------- */
async attaque(competence, arme) {
if (!await this.accorderEntite('avant-attaque')) {
@@ -105,10 +138,10 @@ export class RdDCombat {
label: 'Attaque: ' + (arme ? arme.name : competence.name),
callbacks: [
this.attacker.createCallbackExperience(),
- { condition: RdDResolutionTable.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
- { condition: r => (RdDResolutionTable.isReussite(r) && !RdDResolutionTable.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
- { condition: RdDResolutionTable.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
- { condition: RdDResolutionTable.isEchec, action: r => this._onAttaqueEchec(r) }
+ { condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
+ { condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
+ { condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
+ { condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) }
]
} );
dialog.render(true);
@@ -119,16 +152,21 @@ export class RdDCombat {
let rollData = {
coupsNonMortels: false,
competence: competence,
- surprise: this.attacker.getSurprise()
+ surprise: this.attacker.getSurprise(),
+ surpriseDefenseur: this.defender.getSurprise()
};
if (this.attacker.isCreature()) {
this._modifieRollDataCreature(rollData, competence);
}
- else {
+ else if (arme) {
// Usual competence
rollData.arme = RdDItemArme.armeUneOuDeuxMains(arme, RdDItemCompetence.isArmeUneMain(competence));
}
+ else {
+ // sans armes: à mains nues
+ rollData.arme = RdDItemArme.mainsNues();
+ }
return rollData;
}
@@ -145,6 +183,11 @@ export class RdDCombat {
dommagesReels: competence.data.dommages
}
};
+
+ // rollData.dmg = {
+ // dmgArme: competence.data.dommages,
+ // total: competence.data.dommages
+ // };
}
/* -------------------------------------------- */
@@ -178,13 +221,12 @@ export class RdDCombat {
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
});
}
- rollData.dmg = RdDCombat.calculBonusDegats(rollData, this.attacker);
+ rollData.dmg = RdDBonus.dmg(rollData, this.attacker.getBonusDegat(), this.defender.isEntiteCauchemar());
if (this.target) {
- rollData.mortalite = this._calculMortaliteEncaissement(rollData);
explications += "
Cible : " + this.defender.data.name;
}
- explications += "
Encaissement à "+ Misc.toSignedString(rollData.dmg.total)+ " (" + rollData.dmg.loc.label+")";
+ explications += "
Encaissement à " + Misc.toSignedString(rollData.dmg.total) + " (" + rollData.dmg.loc.label + ")";
// Save rollData for defender
game.system.rdd.rollDataHandler[this.attackerId] = duplicate(rollData);
@@ -208,15 +250,16 @@ export class RdDCombat {
let content = "" + this.defender.name + " doit se défendre :";
- // parades
- let filterArmesParade = this._getFilterArmesParade(rollData.competence.data.categorie);
- for (const arme of this.defender.data.items.filter(filterArmesParade)) {
- content += "
Parer avec " + arme.name + "";
- }
-
- // esquive
- if (rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == "lancer" || rollData.competence.data.categorie == 'competencecreature') {
- content += "
Esquiver";
+ if (this.defender.getSurprise() != 'totale') {
+ // parades
+ for (const arme of this._filterArmesParade(this.defender.data.items, rollData.competence.data.categorie)) {
+ content += "
Parer avec " + arme.name + "";
+ }
+
+ // esquive
+ if (rollData.competence.data.categorie == 'melee' || rollData.competence.data.categorie == "lancer" || rollData.competence.data.categorie == 'competencecreature') {
+ content += "
Esquiver";
+ }
}
// encaisser
@@ -246,24 +289,25 @@ export class RdDCombat {
}
/* -------------------------------------------- */
- _getFilterArmesParade(categorie) {
+ _filterArmesParade(items, categorie) {
switch (categorie) {
case 'tir':
case 'lancer':
- return arme => arme.type == "arme" && arme.data.competence.toLowerCase().match("bouclier");
+ return items.filter(item => item.data.competence.toLowerCase().match("bouclier"));
default:
- return arme => (arme.type == "arme" && RdDItemCompetence.isCompetenceMelee(arme.data.competence)) || (arme.type == "competencecreature" && arme.data.isparade)
+ return items.filter(item => {
+ if (item.type == 'competencecreature') {
+ return item.data.isparade;
+ }
+ if (item.type == 'arme') {
+ const comp = this.defender.getCompetence(item.data.competence);
+ return comp && comp.data.categorie == 'melee';
+ }
+ return false;
+ });
}
}
- /* -------------------------------------------- */
- _calculMortaliteEncaissement(rollData) {
- const mortalite = this.defender.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
- console.log("Mortalité : ", mortalite, this.defender.data.type);
- return mortalite;
- }
-
-
/* -------------------------------------------- */
_onAttaqueEchecTotal(rollData) {
console.log("RdDCombat.onEchecTotal >>>", rollData);
@@ -308,10 +352,10 @@ export class RdDCombat {
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
callbacks: [
this.defender.createCallbackExperience(),
- { condition: RdDResolutionTable.isParticuliere, action: r => this._onParadeParticuliere(r) },
- { condition: RdDResolutionTable.isReussite, action: r => this._onParadeNormale(r) },
- { condition: RdDResolutionTable.isEchecTotal, action: r => this._onParadeEchecTotal(r) },
- { condition: RdDResolutionTable.isEchec, action: r => this._onParadeEchec(r) }
+ { condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) },
+ { condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) },
+ { condition: RdDCombat.isEchecTotal, action: r => this._onParadeEchecTotal(r) },
+ { condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) }
]
} );
dialog.render(true);
@@ -336,6 +380,7 @@ export class RdDCombat {
competence: competence,
arme: arme.data,
surprise: this.defender.getSurprise(),
+ surpriseDefenseur: this.defender.getSurprise(),
needSignificative: this._needSignificative(attackerRoll) || RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
needResist: this._needResist(armeAttaque, armeParade),
carac: this.defender.data.data.carac
@@ -403,7 +448,7 @@ export class RdDCombat {
console.log("RdDCombat._onParadeEchec >>>", rollData);
let explications = "
Parade échouée, encaissement ! ";
- explications += RdDCombat.descriptionSurprise(rollData.surprise);
+ explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
@@ -438,10 +483,10 @@ export class RdDCombat {
label: 'Esquiver',
callbacks: [
this.defender.createCallbackExperience(),
- { condition: RdDResolutionTable.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
- { condition: RdDResolutionTable.isReussite, action: r => this._onEsquiveNormale(r) },
- { condition: RdDResolutionTable.isEchecTotal, action: r => this._onEsquiveEchecTotal(r) },
- { condition: RdDResolutionTable.isEchec, action: r => this._onEsquiveEchec(r) },
+ { condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
+ { condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) },
+ { condition: RdDCombat.isEchecTotal, action: r => this._onEsquiveEchecTotal(r) },
+ { condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) },
]
});
dialog.render(true);
@@ -454,6 +499,7 @@ export class RdDCombat {
attackerRoll: attackerRoll,
competence: competence,
surprise: this.defender.getSurprise(),
+ surpriseDefenseur: this.defender.getSurprise(),
needSignificative: this._needSignificative(attackerRoll),
carac: this.defender.data.data.carac
};
@@ -499,7 +545,7 @@ export class RdDCombat {
console.log("RdDCombat._onEsquiveEchec >>>", rollData);
let explications = "
Esquive échouée, encaissement ! ";
- explications += RdDCombat.descriptionSurprise(rollData.surprise);
+ explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
@@ -569,65 +615,4 @@ export class RdDCombat {
return rolled.isSuccess;
}
- /* -------------------------------------------- */
- static calculBonusDegats(rollData, actor) {
- let dmg = { total: 0, loc: RdDUtility.getLocalisation() };
- if (rollData.arme.name.toLowerCase() == "esquive") {
- // Specific case management
- ui.notifications.warn("Calcul de bonus dégats sur eswquive")
- return dmg;
- }
- dmg.dmgArme = RdDCombat._dmgArme(rollData);
- dmg.ignoreArmure = 0; // TODO: calculer pour arcs et arbaletes, gérer pour lmes créatures
- dmg.dmgTactique= RdDCombat._dmgTactique(rollData);
- dmg.dmgParticuliere= RdDCombat._dmgParticuliere(rollData);
- dmg.dmgSurprise= RdDCombat._dmgSurprise(rollData);
- dmg.dmgActor = RdDCombat._dmgActor(actor.getBonusDegat(), rollData.selectedCarac.label, dmg.dmgArme);
- dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
- return dmg;
- }
-
- static _dmgArme(rollData) {
- return parseInt(rollData.arme.data.dommages);
- }
-
- static _dmgActor(bonusDegat, categorie, dmgArme) {
- switch (categorie) {
- case "Tir": return 0;
- case "Lancer": return Math.max(0, Math.min(dmgArme, bonusDegat));
- }
- return bonusDegat;
- }
-
- static _dmgTactique(rollData) {
- return rollData.isCharge ? 2 : 0;
- }
-
- static _dmgParticuliere(rollData) {
- return rollData.particuliereAttaque == 'force' ? 5 : 0;
- }
-
-
- static _dmgSurprise(rollData) {
- if (rollData.surprise) {
- switch (rollData.surprise) {
- case 'demi': return 1;
- case 'totale': return 10;
- }
- }
- return 0;
- }
-
- /* -------------------------------------------- */
- static descriptionSurprise(surprise) {
- if (surprise) {
- switch (surprise) {
- case 'demi': return 'demi-surprise';
- case 'totale': return 'surprise totale';
- }
- }
- return '';
- }
-
-
}
\ No newline at end of file
diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js
index a2d3acf5..06cbe388 100644
--- a/module/rdd-resolution-table.js
+++ b/module/rdd-resolution-table.js
@@ -242,10 +242,9 @@ export class RdDResolutionTable {
static buildHTMLResults( caracValue, levelValue) {
let cell = this.computeChances( caracValue, levelValue);
let descr = $('');
- descr.append("Réussite : "+cell.score+ " - Particulière : " + cell.part + " - Significative : " + cell.sign);
+ descr.append("Particulière : " + cell.part+ " - Significative : " + cell.sign + " - Réussite : "+cell.score);
descr.append("
Echec Particulier : " + cell.epart + " - Echec Total : " + cell.etotal );
descr.append("");
-
return descr;
}
diff --git a/module/rdd-roll-encaisser.js b/module/rdd-roll-encaisser.js
index 2464b388..3b7d8ddb 100644
--- a/module/rdd-roll-encaisser.js
+++ b/module/rdd-roll-encaisser.js
@@ -37,8 +37,8 @@ export class RdDEncaisser extends Dialog {
dmg:{
total: Number(this.modifier),
loc: { result: 0, label: "Corps" },
- },
- mortalite: mortalite
+ mortalite: mortalite
+ }
});
}
diff --git a/module/rdd-roll.js b/module/rdd-roll.js
index 526a3d70..48d5993f 100644
--- a/module/rdd-roll.js
+++ b/module/rdd-roll.js
@@ -1,16 +1,17 @@
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
+import { RdDBonus } from "./rdd-bonus.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
/**
* Extend the base Dialog entity to select roll parameters
* @extends {Dialog}
*/
-/* -------------------------------------------- */
+/* -------------------------------------------- */
export class RdDRoll extends Dialog {
- /* -------------------------------------------- */
+ /* -------------------------------------------- */
static async create(actor, rollData, dialogConfig, ...actions) {
RdDRoll._ensureCorrectActions(actions);
@@ -25,7 +26,7 @@ export class RdDRoll extends Dialog {
return new RdDRoll(actor, rollData, html, options, actions);
}
- /* -------------------------------------------- */
+ /* -------------------------------------------- */
static _setDefaultOptions(actor, rollData) {
let defaultRollData = {
@@ -38,7 +39,7 @@ export class RdDRoll extends Dialog {
diffLibre: 0,
editLibre: true,
editConditions: true,
- forceValue : actor.getForceValue(),
+ forceValue: actor.getForceValue(),
malusArmureValue: (actor.type == 'personnage ' && actor.data.data.attributs && actor.data.data.attributs.malusarmure) ? actor.data.data.attributs.malusarmure.value : 0,
surencMalusFlag: actor.type == 'personnage ' ? (actor.data.data.compteurs.surenc.value < 0) : false,
surencMalusValue: actor.type == 'personnage ' ? actor.data.data.compteurs.surenc.value : 0,
@@ -48,10 +49,10 @@ export class RdDRoll extends Dialog {
encValueForNatation: actor.encombrementTotal ? Math.floor(actor.encombrementTotal) : 0,
ajustementAstrologique: actor.ajustementAstrologique()
}
- mergeObject(rollData, defaultRollData, { overwrite: false } );
+ mergeObject(rollData, defaultRollData, { overwrite: false });
}
- /* -------------------------------------------- */
+ /* -------------------------------------------- */
static _ensureCorrectActions(actions) {
if (actions.length == 0) {
throw 'No action defined';
@@ -63,7 +64,7 @@ export class RdDRoll extends Dialog {
});
}
- /* -------------------------------------------- */
+ /* -------------------------------------------- */
constructor(actor, rollData, html, options, actions) {
let conf = {
title: actions[0].label,
@@ -81,7 +82,7 @@ export class RdDRoll extends Dialog {
this.rollData = rollData;
}
- /* -------------------------------------------- */
+ /* -------------------------------------------- */
async onAction(action, html) {
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
@@ -101,19 +102,26 @@ export class RdDRoll extends Dialog {
this.bringToTop();
var rollData = this.rollData;
+ var actor = this.actor;
function updateRollResult(rollData) {
let caracValue = parseInt(rollData.selectedCarac.value)
let rollLevel = RdDRoll._computeFinalLevel(rollData);
-
+ rollData.dmg = rollData.attackerRoll ? rollData.attackerRoll.dmg : RdDBonus.dmg(rollData, actor.getBonusDegat());
rollData.finalLevel = rollLevel;
- rollData.caracValue = caracValue
+ rollData.caracValue = caracValue;
+ rollData.diffConditions = RdDBonus.bonusAttaque(rollData.surpriseDefenseur);
+ rollData.coupsNonMortels = (rollData.attackerRoll ? rollData.attackerRoll.dmg.mortalite : rollData.dmg.mortalite) == 'non-mortel';
+ let dmgText = Misc.toSignedString(rollData.dmg.total);
+ if (rollData.coupsNonMortels) {
+ dmgText = '(' + dmgText + ')';
+ }
HtmlUtility._showControlWhen(".etat-general", !RdDRoll._isIgnoreEtatGeneral(rollData));
// Sort management
if (rollData.selectedSort) {
- rollData.bonus = RdDItemSort.getCaseBonus( rollData.selectedSort, rollData.coord ),
+ rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord),
//console.log("Toggle show/hide", rollData.selectedSort);
HtmlUtility._showControlWhen("#div-sort-difficulte", RdDItemSort.isDifficulteVariable(rollData.selectedSort))
HtmlUtility._showControlWhen("#div-sort-ptreve", RdDItemSort.isCoutVariable(rollData.selectedSort))
@@ -122,6 +130,9 @@ export class RdDRoll extends Dialog {
// Mise à jour valeurs
$("#roll-param").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
$("#compdialogTitle").text(RdDRoll._getTitle(rollData));
+ $('#coupsNonMortels').prop('checked', rollData.coupsNonMortels);
+ $("#dmg-arme-actor").text(dmgText);
+ $("#defenseur-surprise").text(RdDBonus.description(rollData.surpriseDefenseur));
$(".table-resolution").remove();
$("#resolutionTable").append(RdDResolutionTable.buildHTMLTableExtract(caracValue, rollLevel));
$(".span-valeur").remove();
@@ -168,7 +179,7 @@ export class RdDRoll extends Dialog {
html.find('#sort').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort = rollData.sortList[sortKey]; // Update the selectedCarac
- this.rollData.bonus = RdDItemSort.getCaseBonus( rollData.selectedSort, rollData.coord );
+ this.rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.coord);
RdDItemSort.setCoutReveReel(rollData.selectedSort);
//console.log("RdDRollSelectDialog - Sort selection", rollData.selectedSort);
updateRollResult(rollData);
@@ -186,10 +197,12 @@ export class RdDRoll extends Dialog {
updateRollResult(rollData);
});
html.find('#coupsNonMortels').change((event) => {
- this.rollData.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
+ this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
+ updateRollResult(rollData);
});
- html.find('#isCharge').change((event) => {
- this.rollData.isCharge = event.currentTarget.checked;
+ html.find('#tactique-combat').change((event) => {
+ this.rollData.tactique = event.currentTarget.value;
+ updateRollResult(rollData);
});
html.find('#surencMalusApply').change((event) => {
this.rollData.surencMalusApply = event.currentTarget.checked;
@@ -209,11 +222,38 @@ export class RdDRoll extends Dialog {
static _computeFinalLevel(rollData) {
const etat = RdDRoll._isIgnoreEtatGeneral(rollData) ? 0 : Misc.toInt(rollData.etat);
const diffConditions = Misc.toInt(rollData.diffConditions);
- let malusEnc = (rollData.surencMalusApply) ? rollData.surencMalusValue : 0;
- let diffLibre = Misc.toInt(rollData.diffLibre);
- let malusEncNatation = (rollData.useEncForNatation) ? -rollData.encValueForNatation : 0;
- let ajustementChance = rollData.selectedCarac.label.toLowerCase().includes('chance') ? rollData.ajustementAstrologique : 0;
+ const malusEnc = (rollData.surencMalusApply) ? rollData.surencMalusValue : 0;
+ const bonusTactique = RdDBonus.bonusAttaque(rollData.tactique);
+ const malusEncNatation = (rollData.useEncForNatation) ? -rollData.encValueForNatation : 0;
+ const ajustementChance = rollData.selectedCarac.label.toLowerCase().includes('chance') ? rollData.ajustementAstrologique : 0;
// Gestion malus armure
+ const malusArmureValue = RdDRoll._computeMalusArmure(rollData);
+
+ const diffLibre = RdDRoll._computeDiffLibre(rollData);
+ const diffCompetence = RdDRoll._computeDiffCompetence(rollData);
+
+ return etat + diffCompetence + diffLibre + diffConditions + malusEnc + malusEncNatation + malusArmureValue + ajustementChance + bonusTactique;
+ }
+
+ static _computeDiffCompetence(rollData) {
+ if (rollData.competence) {
+ return Misc.toInt(rollData.competence.data.niveau);
+ }
+ if (rollData.draconicList) {
+ return Misc.toInt(rollData.selectedDraconic.data.niveau);
+ }
+ return 0;
+ }
+
+ static _computeDiffLibre(rollData) {
+ let diffLibre = Misc.toInt(rollData.diffLibre);
+ if (rollData.draconicList && rollData.selectedSort) {
+ return RdDItemSort.getDifficulte(rollData.selectedSort, diffLibre);
+ }
+ return diffLibre;
+ }
+
+ static _computeMalusArmure(rollData) {
let malusArmureValue = 0;
if (rollData.malusArmureValue != 0 && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
$("#addon-message").text("Malus armure appliqué : " + rollData.malusArmureValue);
@@ -221,17 +261,7 @@ export class RdDRoll extends Dialog {
} else {
$("#addon-message").text("");
}
-
- let diffCompetence = 0;
- if (rollData.competence) {
- diffCompetence = Misc.toInt(rollData.competence.data.niveau);
- }
- else if (rollData.draconicList) {
- diffCompetence = Misc.toInt(rollData.selectedDraconic.data.niveau);
- diffLibre = RdDItemSort.getDifficulte(rollData.selectedSort, diffLibre);
- }
-
- return etat + diffCompetence + diffLibre + diffConditions + malusEnc + malusEncNatation + malusArmureValue + ajustementChance;
+ return malusArmureValue;
}
/* -------------------------------------------- */
diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js
index 83cdd43d..815f4acf 100644
--- a/module/rdd-tmr-dialog.js
+++ b/module/rdd-tmr-dialog.js
@@ -285,14 +285,6 @@ export class RdDTMRDialog extends Dialog {
return rencontre;
}
- /* -------------------------------------------- */
- performRoll(html) {
- if (this.viewOnly) {
- return;
- }
- this.actor.performRoll(this.rollData);
- }
-
/* -------------------------------------------- */
updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value");
diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html
index 61c7b8f8..e868b0e2 100644
--- a/templates/actor-sheet.html
+++ b/templates/actor-sheet.html
@@ -133,7 +133,7 @@
Chance actuelle
- Utiliser
+ Utiliser
{{#each data.compteurs as |compteur key|}}
{{#if compteur.isChance}}
@@ -141,15 +141,19 @@
{{compteur.label}}
- {{#if compteur.isStress}}
+
+ {{#if compteur.isStress}}
Transformer
- {{else}}
- {{#if (eq compteur.label 'Ethylisme')}}
+ {{else if (eq compteur.label 'Ethylisme')}}
Jet d'Ethylisme
+ {{else if (eq compteur.label 'Moral')}}
+
+
+
{{else}}
- {{/if}}
{{/if}}
+
{{/if}}
{{/each}}
diff --git a/templates/dialog-competence.html b/templates/dialog-competence.html
index 67a5e024..6cfb1a2d 100644
--- a/templates/dialog-competence.html
+++ b/templates/dialog-competence.html
@@ -9,8 +9,13 @@
{{/each}}
{{/select}}
+
+ {{#if attackerRoll}}
+
+
+ {{else}}
+ {{/if}}
-
{{#if arme}}
-
-
-
-
-
-
-{{#unless attackerRoll}}
-
-
-
-
-{{/unless}}
+
+ {{#if attackerRoll}}
+ {{#if attackerRoll.tactique}}
+
+ {{/if}}
+
+
+ {{else}}
+
+
+
+
+
+ {{/if}}
+ {{#if surpriseDefenseur}}
+
+ {{/if}}
+
{{/if}}
+
+
+
+
+
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html"}}
{{>"systems/foundryvtt-reve-de-dragon/templates/dialog-roll-natation.html"}}
-
-
-
-
-
-