#42 Tchat message fin

parade, esquive

 inclus deterioration arme de parade
 inclus recul sous le choc
This commit is contained in:
Vincent Vandemeulebrouck 2021-01-02 04:28:43 +01:00
parent cd36331702
commit 0a3f578bf3
19 changed files with 428 additions and 337 deletions

View File

@ -204,6 +204,7 @@ export class RdDActor extends Actor {
getEncombrementTotal() {
return this.encTotal ? Math.floor(this.encTotal) : 0
}
/* -------------------------------------------- */
async deleteSortReserve(sortReserve) {
let reserve = duplicate(this.data.data.reve.reserve);
@ -212,7 +213,7 @@ export class RdDActor extends Actor {
let newTable = [];
for( i=0; i < len; i++) {
if (reserve.list[i].coord != sortReserve.coord && reserve.list[i].sort.name != sortReserve.sort.name )
newTable.push(reserve.list[i]);
newTable.push(reserve.list[i]);
}
if ( newTable.length != len ) {
reserve.list = newTable;
@ -220,6 +221,11 @@ export class RdDActor extends Actor {
}
}
/* -------------------------------------------- */
getDiviseurSignificative() {
return this.getSurprise() == 'demi' ? 2 : 1;
}
/* -------------------------------------------- */
getSurprise() {
if (this.isEntiteCauchemar()) {
@ -1512,8 +1518,7 @@ export class RdDActor extends Actor {
this.currentTMR.maximize(); // Re-display TMR
}
// Final chat message
let chatOptions = { content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-sort.html') }
ChatUtility.chatWithRollMode(chatOptions, this.name)
await RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-sort.html');
if (myReve.value == 0) { // 0 points de reve
ChatMessage.create({ content: this.name + " est réduit à 0 Points de Rêve, et tombe endormi !" });
@ -1525,7 +1530,7 @@ export class RdDActor extends Actor {
async rollCarac( caracName ) {
let rollData = {
selectedCarac: this.getCaracByName(caracName),
needSignificative : !this.isEntiteCauchemar() && this.data.data.sante.sonne.value
diviseur : this.getDiviseurSignificative()
};
const dialog = await RdDRoll.create(this, rollData,
@ -1535,7 +1540,7 @@ export class RdDActor extends Actor {
label: 'Jet ' + Grammar.apostrophe('de', rollData.selectedCarac.label),
callbacks: [
this.createCallbackExperience(),
{ action: this._rollCaracResult }
{ action: this._onRollCaracResult }
]
}
);
@ -1543,22 +1548,16 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
async _rollCaracResult(rollData) {
rollData.show = {
title: rollData.selectedCarac.label,
points: true
};
async _onRollCaracResult(rollData) {
// Final chat message
let chatOptions = { content: await RdDResolutionTable.explainRollDataV2(rollData) }
ChatUtility.chatWithRollMode(chatOptions, this.name)
await RdDResolutionTable.displayRollData(rollData, this.name);
}
/* -------------------------------------------- */
async rollCompetence( name ) {
let rollData = {
competence: this.getCompetence(name),
needSignificative : !this.isEntiteCauchemar() && this.data.data.sante.sonne.value
diviseur : this.getDiviseurSignificative()
}
if (rollData.competence.type == 'competencecreature') {
@ -1611,7 +1610,7 @@ export class RdDActor extends Actor {
competence.data.defaut_carac = tache.data.carac; // Patch !
let rollData = {
competence: competence,
needSignificative : this.data.data.sante.sonne.value,
diviseur : this.getDiviseurSignificative(),
tache: tache,
diffConditions: tache.data.difficulte,
editLibre: false,
@ -1642,9 +1641,7 @@ export class RdDActor extends Actor {
this.updateEmbeddedEntity( "OwnedItem", rollData.tache);
this.santeIncDec( "fatigue", rollData.tache.data.fatigue);
ChatUtility.chatWithRollMode({
content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-tache.html')
}, this.name);
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-tache.html');
}
/* -------------------------------------------- */
@ -1655,10 +1652,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async _competenceResult(rollData) {
rollData.show = {points:true};
ChatUtility.chatWithRollMode({
content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-competence.html')
}, this.name);
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-competence.html')
}
/* -------------------------------------------- */
@ -1682,6 +1676,7 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
async _appelChanceResult(rollData) {
// TODO:
const message = {
user: game.user._id,
alias: this.name,
@ -1693,9 +1688,7 @@ export class RdDActor extends Actor {
}
ChatMessage.create(message);
ChatUtility.chatWithRollMode({
content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-appelchance.html')
}, this.name);
RdDResolutionTable.displayRollData(rollData, this.name, 'chat-resultat-appelchance.html')
}
/* -------------------------------------------- */

View File

@ -1,4 +1,19 @@
const nomCcategorieParade = {
"sans-armes": "Sans arme / armes naturelles",
"hast": "Armes d'hast",
"batons": "Bâtons",
"boucliers": "Boucliers",
"dagues": "Dagues",
"epees-courtes": "Epées courtes",
"epees-longues": "Epées longues",
"epees-lourdes": "Epées lourdes",
"haches": "Haches",
"lances": "Lances",
}
export class RdDItemArme extends Item {
/* -------------------------------------------- */
@ -20,6 +35,12 @@ export class RdDItemArme extends Item {
return armeData;
}
/* -------------------------------------------- */
static getNomCategorieParade(it) {
const categorie = it.data? RdDItemArme.getCategorieParade(it) : it;
return nomCcategorieParade[categorie];
}
/* -------------------------------------------- */
static getCategorieParade(arme) {
if (arme.data.categorie_parade) {
@ -56,33 +77,34 @@ export class RdDItemArme extends Item {
return 'sans-armes';
}
/* -------------------------------------------- */
static isArmeParade(arme) {
return RdDItemArme.getCategorieParade(arme);
}
/* -------------------------------------------- */
static needParadeSignificative(armeAttaque, armeParade) {
// categories d'armes à la parade (cf. page 115 )
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
let defCategory = RdDItemArme.getCategorieParade(armeParade);
// bouclier et mêmes catégorie: peuvent se parer sans difficulté
if (defCategory == 'bouclier') {
if (defCategory == 'boucliers') {
return false;
}
if (attCategory == defCategory) {
// Parer avec une hache ou une arme dhast exige toujours une signi$cative
if (defCategory.match(/(hast|haches)/)) {
return true;
}
if (defCategory == attCategory) {
return false;
}
// les épées se parent entre elles
if (attCategory.match(/epees-/) && defCategory.match(/epees-/)) {
if (defCategory.match(/epees-/) && attCategory.match(/epees-/)) {
return false;
}
if (attCategory == 'dagues' && defCategory == 'epees-courtes') {
// l'épée gnome pare la dague
if (defCategory == 'epees-courtes' && attCategory == 'dagues') {
return false;
}
if (attCategory.match(/epees-(courtes|legeres)/) && defCategory == 'dagues') {
// la dague pare les épées courtes et légères
if (defCategory == 'dagues' && attCategory.match(/epees-(courtes|legeres)/)) {
return false;
}
// Manage weapon categories when parrying (cf. page 115 )
return true;
}

View File

@ -18,7 +18,9 @@ export class RdDCombat {
static createUsingTarget(attacker) {
const target = RdDCombat.getTarget();
if (target == undefined) {
ui.notifications.warn("Vous devez choisir une seule cible à attaquer!");
ui.notifications.warn((game.user.targets && game.user.targets.size > 1)
? "Vous devez choisir <strong>une seule</strong> cible à attaquer!"
: "Vous devez choisir une cible à attaquer!");
}
const defender = target ? target.actor : undefined;
const defenderTokenId = target ? target.data._id : undefined;
@ -124,7 +126,6 @@ export class RdDCombat {
/* -------------------------------------------- */
static isEchec(rollData) {
switch (rollData.surprise) {
case 'demi': return !rollData.rolled.isSign;
case 'totale': return true;
}
return rollData.rolled.isEchec;
@ -132,7 +133,7 @@ export class RdDCombat {
/* -------------------------------------------- */
static isEchecTotal(rollData) {
if (rollData.arme && rollData.surprise == 'demi') {
if (!rollData.attackerRoll && rollData.surprise) {
return rollData.rolled.isEchec;
}
return rollData.rolled.isETotal;
@ -140,7 +141,7 @@ export class RdDCombat {
/* -------------------------------------------- */
static isParticuliere(rollData) {
if (rollData.arme && rollData.surprise) {
if (!rollData.attackerRoll && rollData.surprise) {
return false;
}
return rollData.rolled.isPart;
@ -149,7 +150,6 @@ export class RdDCombat {
/* -------------------------------------------- */
static isReussite(rollData) {
switch (rollData.surprise) {
case 'demi': return rollData.rolled.isSign;
case 'totale': return false;
}
return rollData.rolled.isSuccess;
@ -216,7 +216,7 @@ export class RdDCombat {
if (rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0) {
message += `
<br><a class='chat-card-button' id='particuliere-attaque' data-mode='rapidite' data-attackerId='${this.attackerId}'>Attaquer en Rapidité</a>
<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerId='${this.attackerId}'>Attaquer en Finesse</a>";
<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerId='${this.attackerId}'>Attaquer en Finesse</a>
`
}
game.system.rdd.rollDataHandler[this.attackerId] = rollData;
@ -237,9 +237,7 @@ export class RdDCombat {
cible: this.target ? this.defender.data.name : 'la cible',
isRecul: (rollData.particuliereAttaque == 'force' || rollData.tactique == 'charge')
}
ChatUtility.chatWithRollMode(
{ content: await RdDResolutionTable.explainRollDataV2(rollData, 'chat-resultat-attaque.html') },
this.name)
await RdDResolutionTable.displayRollData(rollData, this.attacker.name, 'chat-resultat-attaque.html');
if (!await this.accorderEntite('avant-defense')) {
return;
@ -267,7 +265,7 @@ export class RdDCombat {
if (this.defender.getSurprise() != 'totale') {
// parades
for (const arme of this._filterArmesParade(this.defender.data.items, rollData.competence.data.categorie)) {
for (const arme of this._filterArmesParade(this.defender.data.items, rollData.competence, rollData.arme)) {
message += "<br><a class='chat-card-button' id='parer-button' data-attackerId='" + this.attackerId + "' data-defenderTokenId='" + this.defenderTokenId + "' data-armeid='" + arme._id + "'>Parer avec " + arme.name + "</a>";
}
// corps à corps
@ -288,18 +286,24 @@ export class RdDCombat {
}
/* -------------------------------------------- */
_filterArmesParade(items, categorie) {
switch (categorie) {
_filterArmesParade(items, competence) {
switch (competence.data.categorie) {
case 'tir':
case 'lancer':
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
default:
// Le fléau ne peut être paré quau bouclier p115
if (competence.name == "Fléau"){
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
}
return items.filter(item => RdDItemArme.getCategorieParade(item));
}
}
/* -------------------------------------------- */
async _onAttaqueEchecTotal(rollData) {
// TODO: remplacer par un chat message pour laisser le joueur choisir un appel à la chance _avant_
// https://gitlab.com/LeRatierBretonnien/foundryvtt-reve-de-dragon/-/issues/85
console.log("RdDCombat.onEchecTotal >>>", rollData);
let chatOptions = {
content: "<strong>Echec total à l'attaque!</strong> "
@ -308,15 +312,12 @@ export class RdDCombat {
ChatUtility.chatWithRollMode(chatOptions, this.attacker.name)
}
/* -------------------------------------------- */
_onAttaqueEchec(rollData) {
async _onAttaqueEchec(rollData) {
console.log("RdDCombat.onAttaqueEchec >>>", rollData);
let chatOptions = {
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
+ RdDResolutionTable.explainRollData(rollData)
+ (this.target ? "<br><strong>Cible</strong> : " + this.defender.data.name : "")
}
ChatUtility.chatWithRollMode(chatOptions, this.attacker.name)
await RdDResolutionTable.displayRollData(rollData, this.attacker.name, 'chat-resultat-attaque.html');
}
/* -------------------------------------------- */
@ -328,8 +329,7 @@ export class RdDCombat {
/* -------------------------------------------- */
async parade(attackerRoll, armeParadeId) {
let arme = this._findArmeParade(armeParadeId);
let arme = RdDItemArme.getArmeData(armeParadeId ? this.defender.getOwnedItem(armeParadeId) : null);
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
@ -353,32 +353,23 @@ export class RdDCombat {
dialog.render(true);
}
_findArmeParade(armeParadeId) {
return RdDItemArme.getArmeData(armeParadeId ? this.defender.getOwnedItem(armeParadeId) : null);
}
_prepareParade(attackerRoll, armeParade) {
const isCreature = this.defender.isCreature();
const compName = armeParade.data.competence;
const competence = this.defender.getCompetence(compName);
const armeAttaque = attackerRoll.arme;
if (compName != competence.name) {
// TODO: toujours utiliser competence.name ...
ui.notifications.warn("Différence entre compétence " + competence.name + " et compétence de l'arme " + compName);
}
let rollData = {
forceValue: this.defender.getForceValue(),
diffLibre: attackerRoll.diffLibre,
attackerRoll: attackerRoll,
competence: competence,
competence: this.defender.getCompetence(compName),
arme: armeParade,
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
needParadeSignificative: this.needParadeSignificative(attackerRoll, armeParade),
diviseur: this._getDiviseurSignificative(attackerRoll, armeParade),
needResist: this._needArmeResist(armeAttaque, armeParade),
carac: this.defender.data.data.carac,
show: {}
};
if (isCreature) {
RdDItemCompetence.setRollDataCreature(rollData);
@ -387,12 +378,29 @@ export class RdDCombat {
}
/* -------------------------------------------- */
_needSignificative(attackerRoll) {
return attackerRoll.particuliereAttaque == 'finesse';
_getDiviseurSignificative(attackerRoll, armeParade = undefined) {
let facteurSign = this.defender.getDiviseurSignificative();
if (RdDCombat.isAttaqueFinesse(attackerRoll)) {
facteurSign *= 2;
}
if (this.needParadeSignificative(attackerRoll, armeParade)) {
facteurSign *= 2;
}
return Math.min(4, facteurSign);
}
static isAttaqueFinesse(attackerRoll) {
return attackerRoll && attackerRoll.particuliereAttaque == 'finesse';
}
needParadeSignificative(attackerRoll, armeParade) {
return attackerRoll.arme && armeParade &&
RdDItemArme.needParadeSignificative(attackerRoll.arme, armeParade);
}
/* -------------------------------------------- */
_needResist(armeAttaque, armeParade) {
_needArmeResist(armeAttaque, armeParade) {
// Epées parant une arme de bois (cf. page 115 ), une résistance est nécessaire
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
let defCategory = RdDItemArme.getCategorieParade(armeParade);
@ -405,29 +413,27 @@ export class RdDCombat {
console.log("RdDCombat._onParadeParticuliere >>>", rollData);
if (!rollData.attackerRoll.isPart) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.chatWithRollMode({
content: `L'attaquant doit jouer résistance et peut être désarmé (p132)`
}, this.defender.name)
}
let chatOptions = {
content: "<strong>Vous pouvez utiliser votre arme pour une deuxième parade!</strong>"
}
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
}
/* -------------------------------------------- */
async _onParadeNormale(rollData) {
console.log("RdDCombat._onParadeNormale >>>", rollData);
let chatOptions = {
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
+ RdDResolutionTable.explainRollData(rollData)
+ "<br><strong>Attaque parée!</strong>"
}
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
await this.computeRecul(rollData, false);
await this.computeRecul(rollData);
await this.computeDeteriorationArme(rollData);
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-parade.html');
}
/* -------------------------------------------- */
async _onParadeEchecTotal(rollData) {
// TODO: remplacer par un chat message pour laisser le joueur choisir un appel à la chance _avant_
// https://gitlab.com/LeRatierBretonnien/foundryvtt-reve-de-dragon/-/issues/85
console.log("RdDCombat._onParadeEchecTotal >>>", rollData);
let chatOptions = {
content: "<strong>Echec total à la parade!</strong> "
@ -440,24 +446,11 @@ export class RdDCombat {
async _onParadeEchec(rollData) {
console.log("RdDCombat._onParadeEchec >>>", rollData);
let explications = "<br><strong>Parade échouée, encaissement !</strong> ";
explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
await this.computeRecul(rollData);
let chatOptions = {
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
+ RdDResolutionTable.explainRollData(rollData)
+ explications
}
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-parade.html');
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
await this.computeRecul(rollData, true);
// TODO: gestion message pour chance/encaissement
this._sendMessageEncaisser(rollData.attackerRoll);
}
/* -------------------------------------------- */
@ -494,8 +487,9 @@ export class RdDCombat {
competence: competence,
surprise: this.defender.getSurprise(),
surpriseDefenseur: this.defender.getSurprise(),
needSignificative: this._needSignificative(attackerRoll),
carac: this.defender.data.data.carac
diviseur: this._getDiviseurSignificative(attackerRoll),
carac: this.defender.data.data.carac,
show: {}
};
if (this.defender.isCreature()) {
@ -508,24 +502,22 @@ export class RdDCombat {
_onEsquiveParticuliere(rollData) {
console.log("RdDCombat._onEsquiveParticuliere >>>", rollData);
let chatOptions = {
content: "<strong>Vous pouvez esquiver une deuxième attaque!</strong>"
content: "<strong>Vous pouvez esquiver une deuxième esquive!</strong>"
}
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
}
/* -------------------------------------------- */
_onEsquiveNormale(rollData) {
async _onEsquiveNormale(rollData) {
console.log("RdDCombat._onEsquiveNormal >>>", rollData);
let chatOptions = {
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
+ RdDResolutionTable.explainRollData(rollData)
+ "<br><strong>Attaque esquivée!</strong>"
}
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-esquive.html');
}
/* -------------------------------------------- */
async _onEsquiveEchecTotal(rollData) {
// TODO: remplacer par un chat message pour laisser le joueur choisir un appel à la chance _avant_
// https://gitlab.com/LeRatierBretonnien/foundryvtt-reve-de-dragon/-/issues/85
console.log("RdDCombat._onEsquiveEchecTotal >>>", rollData);
let chatOptions = {
content: "<strong>Echec total à l'esquive'!</strong> "
@ -537,32 +529,23 @@ export class RdDCombat {
async _onEsquiveEchec(rollData) {
console.log("RdDCombat._onEsquiveEchec >>>", rollData);
let explications = "<br><strong>Esquive échouée, encaissement !</strong> ";
explications += RdDBonus.description(rollData.surprise);
if (rollData.needSignificative) {
explications += " Significative nécessaire!";
}
await this.computeRecul(rollData);
let chatOptions = {
content: "<strong>Test : " + rollData.selectedCarac.label + " / " + rollData.competence.name + "</strong>"
+ RdDResolutionTable.explainRollData(rollData)
+ explications
}
await RdDResolutionTable.displayRollData(rollData, this.defender.name, 'chat-resultat-esquive.html');
ChatUtility.chatWithRollMode(chatOptions, this.defender.name)
await this.computeRecul(rollData, true);
this._sendMessageEncaisser(rollData.attackerRoll);
}
/* -------------------------------------------- */
async computeDeteriorationArme(rollData) {
const attackerRoll = rollData.attackerRoll;
if (rollData.arme && attackerRoll) { // C'est une parade
// Est-ce que l'attaque est une particulière, en force ou charge et que l'attaque n'en est pas une ?
if ((rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.tactique == 'charge')
&& !rollData.rolled.isPart) {
// Est-ce une parade normale?
if (rollData.arme && attackerRoll && !rollData.rolled.isPart) {
// Est-ce que l'attaque est une particulière en force ou une charge
if (rollData.needResist || attackerRoll.particuliereAttaque == 'force' || attackerRoll.tactique == 'charge') {
rollData.show = rollData.show || {}
const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor;
let resistance = Misc.toInt(rollData.arme.data.resistance);
let msg = "";
@ -572,72 +555,66 @@ export class RdDCombat {
finalLevel: - dmg,
showDice: false
});
if (resistRoll.isSuccess) { // Perte de résistance
msg = "Votre " + rollData.arme.name + " tient le choc de la parade. "
if (resistRoll.rolled.isSuccess) { // Perte de résistance
rollData.show.deteriorationArme = 'resiste';
} else {
resistance -= dmg;
if (resistance <= 0) {
this.defender.deleteEmbeddedEntity("OwnedItem", rollData.arme._id);
msg = "Sous la violence de la parade, votre " + rollData.arme.name + " s'est brisée sous le coup!";
rollData.show.deteriorationArme = 'brise';
} else {
this.defender.updateEmbeddedEntity("OwnedItem", { _id: rollData.arme._id, 'data.resistance': resistance });
msg = "En parant, vous endommagez votre " + rollData.arme.name + ", qui perd " + dmg + " de résistance. ";
rollData.show.deteriorationArme = 'perte';
rollData.show.perteResistance = dmg;
}
}
// Jet de désarmement
if (resistance > 0 && !rollData.arme.name.toLowerCase().includes('bouclier')) { // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
if (resistance > 0 && !RdDItemArme.getCategorieParade(rollData.arme) == 'boucliers') {
let desarme = await RdDResolutionTable.rollData({
caracValue: this.defender.data.data.carac.force.value,
finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg,
showDice: false
});
if (desarme.isEchec) {
msg += "Vous ne parvenez pas à garder votre arme en main, elle tombe au sol à vos pieds";
rollData.show.desarme = desarme.rolled.isEchec;
if (desarme.rolled.isEchec) {
rollData.show.desarme = true;
}
}
ChatMessage.create({
content: msg,
user: game.user._id,
whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM")]
});
}
}
}
/* -------------------------------------------- */
async computeRecul(rollData, encaisser = undefined) { // Calcul du recul (p. 132)
if (rollData.arme || encaisser) {
if ((rollData.attackerRoll.particuliereAttaque && rollData.attackerRoll.particuliereAttaque == 'force') || rollData.attackerRoll.tactique == 'charge') {
let reculNiveau = Misc.toInt(this.defender.data.data.carac.taille.value) - (rollData.attackerRoll.forceValue + rollData.attackerRoll.arme.data.dommagesReels);
let recul = await RdDResolutionTable.rollData({
caracValue: 10,
finalLevel: reculNiveau,
showDice: false
});
async computeRecul(rollData) { // Calcul du recul (p. 132)
const attaque = rollData.attackerRoll;
if (this._isAttaqueCauseRecul(attaque)) {
let msg = "";
if (recul.isSuccess) {
msg = " Vous ne reculez pas malgré la force du coup.";
} else {
let chute = await RdDResolutionTable.rollData({
caracValue: this.defender.data.data.carac.agilite.value,
finalLevel: reculNiveau,
showDice: false
});
if (!chute.isSuccess || recul.isETotal) {
msg = "Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round.";
} else {
msg = "La violence du choc vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round.";
}
}
ChatMessage.create({
content: msg,
user: game.user._id,
whisper: [game.user._id, ChatMessage.getWhisperRecipients("GM")]
});
let impactRecul = this._computeImpactRecul(attaque);
const agilite = this.defender.data.data.carac.agilite.value;
let rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impactRecul, showDice: false });
if (rollRecul.isSuccess) {
rollData.show.recul = 'encaisse';
} else if (rollRecul.isETotal) {
rollData.show.recul = 'chute';
}
else {
let chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impactRecul, showDice: false });
rollData.show.recul = (chute.isSuccess)
? 'recul'
: 'chute';
}
}
}
_isAttaqueCauseRecul(attaque) {
return attaque.particuliereAttaque == 'force' || attaque.tactique == 'charge';
}
_computeImpactRecul(attaque) {
return Misc.toInt(this.defender.data.data.carac.taille.value) - (attaque.forceValue + attaque.arme.data.dommagesReels);
}
/* -------------------------------------------- */
_sendMessageEncaisser(rollData) {
let message = "<strong>" + this.defender.name + "</strong> doit:" + this._buildMessageEncaisser(rollData);

View File

@ -187,11 +187,11 @@ export class RdDCommands {
caracValue: carac,
finalLevel: diff,
showDice: true,
needSignificative: significative,
show: { title: "Table de résolution", points: true }
diviseur: significative ? 2 : 1,
show: { title: "Table de résolution" }
};
await RdDResolutionTable.rollData(rollData);
msg.content = await RdDResolutionTable.explainRollDataV2(rollData);
msg.content = await RdDResolutionTable.buildRollDataHtml(rollData);
ChatUtility.chatWithRollMode(msg, game.user.name);
}

View File

@ -1,6 +1,10 @@
import { ChatUtility } from "./chat-utility.js";
import { RdDItemArme } from "./item-arme.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCombat } from "./rdd-combat.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
/**
* difficultés au delà de -10
@ -82,25 +86,30 @@ export class RdDResolutionTable {
static explain(rolled) {
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
if (rolled.caracValue != null && rolled.finalLevel != null) {
message += (rolled.needSignificative ? "(significative sur " : "(")
message += (rolled.diviseur > 1 ? `(1/${rolled.diviseur} de ` : "(")
+ rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
}
message += '<strong>' + rolled.quality + '</strong>'
return message;
}
static async explainRollDataV2(rollData, template = 'chat-resultat-general.html') {
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.html') {
rollData.ajustements = RdDResolutionTable._buildAjustements(rollData);
rollData.show = rollData.show || {};
let html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
return html;
return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
}
static async displayRollData(rollData, userName, template = 'chat-resultat-general.html') {
let html = await RdDResolutionTable.buildRollDataHtml(rollData, template);
ChatUtility.chatWithRollMode({ content: html }, userName)
}
static _buildAjustements(rollData) {
let list = [];
if (rollData.competence) {
list.push({ label: rollData.competence.name, value: rollData.competence.data.niveau});
list.push({ label: rollData.competence.name, value: rollData.competence.data.niveau });
}
if (rollData.tactique) {
const surprise = RdDBonus.find(rollData.tactique);
@ -124,64 +133,61 @@ export class RdDResolutionTable {
list.push({ label: 'Moral', value: rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté' ? rollData.moral : undefined });
}
if (RdDResolutionTable.isAjustementAstrologique(rollData)) {
list.push({ label: 'Astrologique', value: rollData.ajustementAstrologique||0 });
list.push({ label: 'Astrologique', value: rollData.ajustementAstrologique || 0 });
}
if (rollData.rolled.bonus && rollData.selectedSort) {
list.push({ label: 'Bonus de case', value: rollData.rolled.bonus, unit: '%' });
list.push({ descr: `Bonus de case: ${rollData.rolled.bonus}%` });
}
if (rollData.diviseur > 1) {
list.push({ descr: `Facteur significative &times;${RdDResolutionTable._getFractionHtml(rollData.diviseur)}` });
}
if (RdDCombat.isAttaqueFinesse(rollData.attackerRoll)) {
list.push({ descr: 'Attaque particulière en finesse' });
}
if (rollData.needParadeSignificative) {
const catAttaque = RdDItemArme.getNomCategorieParade(rollData.attackerRoll.arme);
const catParade = RdDItemArme.getNomCategorieParade(rollData.arme);
list.push({ descr: `${catAttaque} vs ${catParade}` });
}
if (rollData.surprise) {
list.push({ descr: RdDBonus.find(rollData.surprise).descr });
}
return list;
}
static explainRollData(rollData) {
let parts = RdDResolutionTable._buildAjustementsList(rollData);
let message = parts.length > 0 ? "<br>Difficulté " + parts.reduce((a, b) => a + ' / ' + b) : "";
return message+ RdDResolutionTable.explain(rollData.rolled)
}
static _buildAjustementsList(rollData) {
let parts = [];
if (rollData.diffLibre != undefined) {
parts.push(`<strong>libre: ${rollData.diffLibre}</strong>`);
static _getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) {
case 2: return '&frac12;';
case 4: return '&frac14;';
default: return '1/' + diviseur;
}
if (rollData.diffConditions != undefined) {
parts.push(`conditions: ${Misc.toSignedString(rollData.diffConditions)}`);
}
if (rollData.etat != undefined) {
parts.push(`état: ${rollData.etat}`);
}
if (rollData.selectedCarac != undefined && rollData.moral != undefined && rollData.selectedCarac.label == 'Volonté') {
parts.push(`moral: ${rollData.moral}`);
}
return parts;
}
/* -------------------------------------------- */
static async rollData(rollData) {
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus, rollData.needSignificative, rollData.showDice);
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus, rollData.diviseur, rollData.showDice);
return rollData;
}
/* -------------------------------------------- */
static async roll(caracValue, finalLevel, bonus = undefined, needSignificative = undefined, showDice = true) {
static async roll(caracValue, finalLevel, bonus = undefined, diviseur = undefined, showDice = true) {
let chances = this.computeChances(caracValue, finalLevel);
this._updateChancesWithBonus(chances, bonus);
this._updateChancesNeedSignificative(chances, needSignificative);
this._updateChancesFactor(chances, diviseur);
chances.showDice = showDice;
let rolled = await this.rollChances(chances);
rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel;
rolled.bonus = bonus;
rolled.needSignificative = needSignificative;
rolled.factor = RdDResolutionTable._getFractionHtml(diviseur);
return rolled;
}
/* -------------------------------------------- */
static _updateChancesNeedSignificative(chances, needSignificative) {
if (needSignificative) {
let newScore = Math.floor(Number(chances.score) / 2);
static _updateChancesFactor(chances, diviseur) {
if (diviseur && diviseur > 1) {
let newScore = Math.floor(Number(chances.score) / diviseur);
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true });
}
}
@ -261,16 +267,7 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
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;
return reussites.find(x => x.condition(chances, roll));
}
/* -------------------------------------------- */

View File

@ -1,4 +1,3 @@
import { ChatUtility } from "./chat-utility.js";
import { Misc } from "./misc.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
@ -23,7 +22,7 @@ export class RdDRollResolution extends Dialog {
let defRollData = {
show: { title: titleTableDeResolution, points: true },
show: { title: titleTableDeResolution },
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: 0,
@ -64,8 +63,7 @@ export class RdDRollResolution extends Dialog {
async onAction(html) {
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolution -=>", this.rollData, this.rollData.rolled);
const message = { content: await RdDResolutionTable.explainRollDataV2(this.rollData) };
ChatUtility.chatWithRollMode(message, game.user.name)
await RdDResolutionTable.displayRollData(rollData, game.user.name)
}
/* -------------------------------------------- */

View File

@ -31,6 +31,7 @@ export class RdDRoll extends Dialog {
static _setDefaultOptions(actor, rollData) {
let defaultRollData = {
alias: actor.name,
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: actor.data.data.compteurs.etat.value,

View File

@ -200,6 +200,8 @@ export class RdDUtility {
// messages tchat
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-appelchance.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-attaque.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-parade.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-esquive.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-general.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-tache.html',

View File

@ -1,5 +1,6 @@
{"_id":"0Vgscex1VV4ybSUQ","name":"Bonnet de laine","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.05,"equipe":false,"resistance":0,"qualite":0,"cout":0.06},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/bonnet_laine.webp","effects":[]}
{"_id":"0ylGrNMzulUaKFP9","name":"Boralm","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"ingredient","data":{"description":"<p>Poudre brune apparaissant sur les parois des grottes.</p>\n<p>VUE/Alchimie &agrave; -1.</p>","niveau":0,"encombrement":0.001,"base":0,"quantite":1,"milieu":"Cavernes","rarete":"","categorie":"Alchimie","cout":0.03},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/boralm.webp","effects":[]}
{"_id":"1Dc4KzZageae7lhI","name":"Balles de jongleur","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":4,"encombrement":0.1,"equipe":false,"resistance":0,"qualite":0,"cout":0.32},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/balle_jongleur.webp","effects":[]}
{"_id":"1O7IJiQSDYxJ5VsD","name":"Bouclier moyen","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"","quantite":1,"encombrement":2,"equipe":false,"dommages":"0","force":"11","resistance":15,"competence":"Bouclier","cout":6,"portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"rapide":false,"deuxmains":false,"unemain":false,"categorie_parade":"boucliers","penetration":0},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/bouclier_moyen.webp","effects":[]}
{"_id":"2y61gBIFbATQaKDl","name":"1 m2 de laine","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.2,"equipe":false,"resistance":0,"qualite":0,"cout":0.1},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/tissu_laine.webp","effects":[]}
{"_id":"3DJePXhrDWQxbUeM","name":"Dé à jouer en os","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.01,"equipe":false,"resistance":0,"qualite":0,"cout":0.1},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/des_en_os.webp","effects":[]}
@ -137,6 +138,8 @@
{"_id":"hVgd4APvAW8sbXf0","name":"Grande hache","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"","quantite":1,"encombrement":3,"equipe":false,"dommages":"4","force":"13","resistance":8,"competence":"Hache à 2 mains","cout":15,"portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"rapide":false,"deuxmains":true,"unemain":false,"categorie_parade":"haches","penetration":0},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/grande_hache.webp","effects":[]}
{"_id":"hjsIxUmanyz5otLJ","name":"Marmite de fer (3 litres)","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"conteneur","data":{"description":"","capacite":1.5,"encombrement":0.6,"equipe":false,"qualite":0,"contenu":[],"cout":0.6},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/marmite.webp","effects":[]}
{"_id":"huvZ4dMPpn9gk9km","name":"Sel","permission":{"default":0,"Q4cUvqxCxMoTJXDL":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.01,"equipe":false,"resistance":0,"qualite":0,"cout":null},"flags":{"core":{"sourceId":"Item.fLEyryhRi8Nw37SP"}},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/sel.webp","effects":[]}
{"_id":"iCvphbPdxUcfqetd","name":"Aumônière","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"conteneur","data":{"description":"<p>Comme une bourse, mais sous forme d'une coque en cuir rigide.</p>","capacite":0.25,"encombrement":0,"equipe":false,"qualite":0,"cout":0.2,"contenu":[]},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/aumoniere.webp","effects":[]}
{"_id":"iGHudg5kBOfYWgwV","name":"Arc","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Nie jusqu'&agrave; 2 points d'armure.</p>\n<p>Rechargement 1/2 round (s'il tire en d&eacute;but de round, il pourra recharger durant le reste du round pour tirer de nouveau au d&eacute;but du round suivant).</p>","quantite":1,"encombrement":1,"equipe":false,"dommages":"2","force":"0","resistance":0,"competence":"Arc","cout":10,"portee_courte":10,"portee_moyenne":20,"portee_extreme":50,"penetration":2,"rapide":false,"deuxmains":false,"unemain":false},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/arc.webp","effects":[]}
{"_id":"ijCebH1Pr3LmzdOj","name":"Épée cyane","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Long <em>cimeterre </em>&agrave; l&rsquo;acier bleut&eacute;, exclusivement fabriqu&eacute; par les Cyans ou Hommes bleus.</p>","quantite":1,"encombrement":2,"equipe":false,"dommages":"3","force":"11","resistance":12,"competence":"Epée à 1 main","cout":25,"portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"rapide":true,"deuxmains":false,"unemain":true,"categorie_parade":"epees-lourdes","penetration":0},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_cyane.webp","effects":[]}
{"_id":"iq8ZZgphxOUgC1bi","name":"Flûte traversière de roseau","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.08,"equipe":false,"resistance":0,"qualite":0,"cout":0.12},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/flute_traversiere.webp","effects":[]}
{"_id":"iuSOVPBsK8Zg6hoY","name":"1 m² de bâche","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.5,"equipe":false,"resistance":0,"qualite":0,"cout":0.2},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/bache.webp","effects":[]}
@ -149,7 +152,7 @@
{"_id":"keLCmhsbxHK39UIy","name":"Mirobolant","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"potion","data":{"description":"<p>Fluide.</p>\n<p>Liquide rouge&acirc;tre clair et sans d&eacute;pot.</p>","quantite":1,"encombrement":0.1,"rarete":"","categorie":"Alchimie","cout":2},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/mirobolant.webp","effects":[]}
{"_id":"lJMKVPB5zlG9UqMD","name":"Pourpoint de velours","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.2,"equipe":false,"resistance":0,"qualite":0,"cout":8},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/pourpoint_velours.webp","effects":[]}
{"_id":"lKkYFkzWVs2TZDZP","name":"Petit pot de fard","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.04,"equipe":false,"resistance":0,"qualite":0,"cout":0.3},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/fard.webp","effects":[]}
{"_id":"lOI2HVu3B6EDY4sE","name":"Arbalète","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Nie jusqu'&agrave; 2 points d'armure.</p>\n<p>Rechargement 1 round.</p>","quantite":1,"encombrement":3,"equipe":false,"dommages":"3","force":"0","resistance":0,"competence":"Arbalète","cout":30,"portee_courte":15,"portee_moyenne":30,"portee_extreme":70,"penetration":2,"rapide":false,"deuxmains":false,"unemain":false,"categorie_parade":""},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/arbalete.webp","effects":[]}
{"_id":"lOI2HVu3B6EDY4sE","name":"Arbalète","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Nie jusqu'&agrave; 2 points d'armure.</p>\n<p>Rechargement 1 round.</p>","quantite":1,"encombrement":3,"equipe":false,"dommages":"3","force":"0","resistance":0,"competence":"Arbalète","cout":30,"portee_courte":15,"portee_moyenne":30,"portee_extreme":70,"penetration":2,"rapide":false,"deuxmains":false,"unemain":false},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/arbalete.webp","effects":[]}
{"_id":"lq7pjDQESNbZOQ3n","name":"1 m2 de soie ou de velours","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0,"equipe":false,"resistance":0,"qualite":0,"cout":3},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/tissu_velours.webp","effects":[]}
{"_id":"m9yuZjp9DK7pSqPK","name":"Lanterne à bougie","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"conteneur","data":{"description":"","capacite":0.1,"encombrement":1,"equipe":false,"qualite":0,"contenu":[],"cout":3},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/lanterne_bougie.webp","effects":[]}
{"_id":"mOZodpJYobvmZO9o","name":"Le Narcolepton","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"livre","data":{"description":"<p>Cet ouvrage ne peut &ecirc;tre assimil&eacute; que si l&rsquo;on poss&egrave;de un niveau minimum de z&eacute;ro en voie de Narcos. Il conf&egrave;re un bonus de synth&egrave;se de +3 aux sept &Eacute;cailles de Protection pr&eacute;sent&eacute;es dans les r&egrave;gles (Venin, Maladie, Feu, Magie, Projectiles, Lames, Griffes et crocs), mais aucun bonus de points de sorts. Sa difficult&eacute; de lecture est de -4, son assimilation requiert 24 points de t&acirc;che, p&eacute;riodicit&eacute; une heure.</p>","auteur":"anonyme","quantite":1,"difficulte":-4,"points_de_tache":24,"encombrement":0,"xp":"","cout":0,"competence":""},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/competence_narcos.png","effects":[]}
@ -197,7 +200,3 @@
{"_id":"zQWlnUsd8bPySujd","name":"Aiguille à coudre","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":1,"encombrement":0.01,"equipe":false,"resistance":0,"qualite":0,"cout":0.1},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/aiguille.webp","effects":[]}
{"_id":"zYI8mDiysWtmsSyy","name":"Carquois","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"conteneur","data":{"description":"","capacite":2,"encombrement":0.1,"equipe":false,"qualite":0,"cout":0.5},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/carquois.webp","effects":[]}
{"_id":"zlDa1vwmls6Uf4pt","name":"Bourse de cuir","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"conteneur","data":{"description":"","capacite":0.5,"encombrement":0.01,"equipe":false,"qualite":0,"contenu":[],"cout":0.1},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/bourse.webp","effects":[]}
{"_id":"iCvphbPdxUcfqetd","name":"Aumônière","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"conteneur","data":{"description":"<p>Comme une bourse, mais sous forme d'une coque en cuir rigide.</p>","capacite":0.25,"encombrement":0,"equipe":false,"qualite":0,"cout":0.2,"contenu":[]},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/aumoniere.webp","effects":[]}
{"_id":"iGHudg5kBOfYWgwV","name":"Arc","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Nie jusqu'&agrave; 2 points d'armure.</p>\n<p>Rechargement 1/2 round (s'il tire en d&eacute;but de round, il pourra recharger durant le reste du round pour tirer de nouveau au d&eacute;but du round suivant).</p>","quantite":1,"encombrement":1,"equipe":false,"dommages":"2","force":"0","resistance":0,"competence":"Arc","cout":10,"portee_courte":10,"portee_moyenne":20,"portee_extreme":50,"penetration":2,"rapide":false,"deuxmains":false,"unemain":false},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/arc.webp","effects":[]}
{"_id":"1Dc4KzZageae7lhI","name":"Balles de jongleur","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"objet","data":{"description":"","quantite":4,"encombrement":0.1,"equipe":false,"resistance":0,"qualite":0,"cout":0.32},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/balle_jongleur.webp","effects":[]}
{"_id":"lOI2HVu3B6EDY4sE","name":"Arbalète","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"arme","data":{"description":"<p>Nie jusqu'&agrave; 2 points d'armure.</p>\n<p>Rechargement 1 round.</p>","quantite":1,"encombrement":3,"equipe":false,"dommages":"3","force":"0","resistance":0,"competence":"Arbalète","cout":30,"portee_courte":15,"portee_moyenne":30,"portee_extreme":70,"penetration":2,"rapide":false,"deuxmains":false,"unemain":false},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/objets/arbalete.webp","effects":[]}

View File

@ -5,7 +5,7 @@
"version": "1.2.0",
"minimumCoreVersion": "0.7.5",
"compatibleCoreVersion": "0.7.8",
"templateVersion": 75,
"templateVersion": 76,
"author": "LeRatierBretonnien",
"esmodules": [ "module/rdd-main.js", "module/hook-renderChatLog.js" ],
"styles": ["styles/simple.css"],

View File

@ -1,19 +1,23 @@
<h4>
Appel à la chance:
<span class="tooltip">
{{alias}} fait appel à la chance
<br><span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</span> = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
{{~#if rolled.isSuccess}}
<hr>
<span class="rdd-roll-part">Un point de chance est dépensé, l'action peut être retentée!</span>
<span>Un point de chance est dépensé, l'action peut être retentée!</span>
{{/if}}

View File

@ -1,53 +1,57 @@
<h4>
Attaque {{arme.name}}
<br>{{selectedCarac.label}} / {{competence.name}}
à {{diffLibre}}
<br>
<span class="tooltip">
{{alias}} attaque: {{arme.name}}
<br>{{selectedCarac.label}} / {{competence.name}}, difficulté {{diffLibre}}
<br><span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}">{{item.label}}: {{numberFormat item.value decimals=0
sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
<hr>
{{#if tactique}}
<div>
{{#if (eq tactique 'charge')}}
<img class="chat-icon" src="icons/svg/thrust.svg" alt="charge" height="32" width="32" />
C'est une charge, vos parades auront un -4 et vous ne pouvez pas esquiver!
{{ else if (eq tactique 'feinte')}}
<img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" alt="feinte" height="32" width="32" />
<div>
{{#if (eq tactique 'charge')}}
<img class="chat-icon" src="icons/svg/thrust.svg" alt="charge" height="32" width="32" />
C'est une charge, vos parades auront un -4 et vous ne pourrez pas esquiver!
{{ else if (eq tactique 'feinte')}}
<img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" alt="feinte" height="32" width="32" />
Votre feinte peut faire mouche!
{{/if}}
</div>
{{/if}}
<div>
{{#if rolled.isSuccess}}
<span><strong>{{show.cible}}</strong> doit se défendre à <strong>{{diffLibre}}</strong>, ou encaisser à
{{~#if (eq dmg.mortalite 'non-mortel')}}
<span class="rdd-roll-norm">({{numberFormat dmg.total decimals=0 sign=true}})</span> (dommages non-mortel)
{{else if (eq dmg.mortalite 'mortel')}}
<span class="rdd-roll-echec">{{numberFormat dmg.total decimals=0 sign=true}}</span>.
{{else}}
<span class="rdd-roll-etotal">{{numberFormat dmg.total decimals=0 sign=true}}</span> (entités de cauchemar)
{{~/if}}.
{{#if show.isRecul}}Si votre adversaire n'esquive pas, il devra résister à l'impact ou reculer sous le choc!{{/if}}
Le coup vise: {{dmg.loc.label}}.
</span>
</div>
{{#if (eq particuliereAttaque 'rapidite')}}
<div>
<span>
<br>Votre attaque rapide vous permet une deuxième attaque, ou défense supplémentaire!
</span>
{{/if}}
{{else}}
Votre attaque a échoué!
{{/if}}
</div>
{{/if}}
<div>
<span><strong>{{show.cible}}</strong> doit se défendre à <strong>{{diffLibre}}</strong>, ou encaisser à
{{~#if (eq dmg.mortalite 'non-mortel')}}
<span class="rdd-roll-norm">({{numberFormat dmg.total decimals=0 sign=true}})</span> (dommages non-mortel)
{{else if (eq dmg.mortalite 'mortel')}}
<span class="rdd-roll-echec">{{numberFormat dmg.total decimals=0 sign=true}}</span>.
{{else}}
<span class="rdd-roll-etotal">{{numberFormat dmg.total decimals=0 sign=true}}</span> (entités de cauchemar)
{{~/if}}.
{{#if show.isRecul}}Si votre adversaire n'esquive pas, il devra résister à l'impact ou reculer sous le choc!{{/if}}
Le coup vise: {{dmg.loc.label}}.
</span>
</div>
{{#if (eq particuliereAttaque 'rapidite')}}
<div>
<span>
<br>Votre attaque rapide vous permet une deuxième attaque, ou défense supplémentaire!
</span>
</div>
{{/if}}

View File

@ -1,32 +1,31 @@
<h4>
{{#if show.title}}{{show.title}}: {{/if}}
{{alias}} {{#if show.title}}{{show.title}}: {{/if}}
{{#if selectedCarac}}{{selectedCarac.label}}
{{#if competence}} / {{competence.name}}{{/if}}
{{/if}}
<br>
<span class="tooltip">
<br><span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
{{#if show.points}}
<hr>
<div>
<span>{{rolled.ptTache}} points de tâche{{#if rolled.ptQualite}}, ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}}</span>
<span>{{#if rolled.ptTache}}{{rolled.ptTache}} points de tâche{{/if}}{{#if rolled.ptQualite}}{{#if rolled.ptTache}},{{/if}} ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}}</span>
</div>
{{/if}}
{{~#if show.explications}}
{{#unless show.points}}<hr>{{/unless}}
<div>
{{show.explications}}
</div>

View File

@ -0,0 +1,50 @@
<h4>
{{alias}} esquive: {{selectedCarac.label}} / {{competence.name}}, difficulté {{diffLibre}}
<br><span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
</span>
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
<hr>
<div>
{{#if rolled.isSuccess}}
<span>Attaque esquivée!</span>
{{#if rolled.isPart}}
<!-- TODO: cas de parade à mains nues, texte à modifier -->
<span><strong>Vous pouvez faire une deuxième esquive!</strong></span>
{{/if}}
{{else}}
<span>Votre esquive a échoué!</span>
{{/if}}
</div>
{{#if (eq show.recul 'encaisse')}}<div>Vous ne reculez pas malgré la violence du coup.</div>
{{else if (eq show.recul 'chute')}}<div>Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round.</div>
{{else if (eq show.recul 'recul')}}<div>La violence du choup vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round.</div>
{{/if}}
{{#if attackerRoll.tactique}}
<div>
{{#if (eq attackerRoll.tactique 'charge')}}
<img class="chat-icon" src="icons/svg/thrust.svg" alt="charge" height="32" width="32" />
C'était une charge, les parades de votre adversaire auront un -4 et il ne pourra pas esquiver!
{{ else if (eq attackerRoll.tactique 'feinte')}}
<img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" alt="feinte" height="32"
width="32" />
C'était une feinte!
{{/if}}
</div>
{{/if}}

View File

@ -1,32 +1,33 @@
<h4>
{{#if show.title}}{{show.title}}: {{/if}}
{{alias}} {{#if show.title}}{{show.title}}: {{/if}}
{{#if selectedCarac}}{{selectedCarac.label}}
{{#if competence}} / {{competence.name}}{{/if}}
{{/if}}
<br>
<span class="tooltip">
<br><span {{#if ajustements}}class="tooltip"{{/if}}>
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
{{#if show.points}}
<hr>
<div>
<span>{{rolled.ptTache}} points de tâche{{#if rolled.ptQualite}}, ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}}</span>
<span>{{#if rolled.ptTache}}{{rolled.ptTache}} points de tâche{{/if}}{{#if rolled.ptQualite}}{{#if rolled.ptTache}},{{/if}} ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}}</span>
</div>
{{/if}}
{{~#if show.explications}}
{{#unless show.points}}<hr>{{/unless}}
<div>
{{show.explications}}
</div>

View File

@ -0,0 +1,63 @@
<h4>
{{alias}} pare: {{arme.name}}
<br>{{selectedCarac.label}} / {{competence.name}}, difficulté {{diffLibre}}
<br><span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
</span>
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
<hr>
<div>
{{#if rolled.isSuccess}}
<span>Attaque parée!</span>
{{#if rolled.isPart}}
<!-- TODO: cas de parade à mains nues, texte à modifier -->
<span><strong>Vous pouvez utiliser votre arme pour une deuxième parade!</strong></span>
{{/if}}
{{else}}
<span>Votre parade a échoué!</span>
{{/if}}
</div>
{{#if (eq show.recul 'encaisse')}}<div>Vous ne reculez pas malgré la violence du coup.</div>
{{else if (eq show.recul 'brise')}}<div>Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round.</div>
{{else if (eq show.recul 'perte')}}<div>La violence du choup vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round.</div>
{{/if}}
{{#if (eq show.deteriorationArme 'resiste')}}
<div>Votre {{arme.name}} résiste au choc de la parade.</div>
{{else if (eq show.deteriorationArme 'resiste')}}
<div>Sous la violence de la parade, votre {{arme.name}} s'est brisée!</div>
{{else if (eq show.deteriorationArme 'resiste')}}
<div>En parant, vous endommagez votre {{arme.name}} qui perd {{show.perteResistance}} de résistance.</div>
{{/if}}
{{#if show.desarme}}
<div>Vous ne parvenez pas à garder votre arme en main, elle tombe à vos pieds.</div>
{{/if}}
{{#if attackerRoll.tactique}}
<div>
{{#if (eq attackerRoll.tactique 'charge')}}
<img class="chat-icon" src="icons/svg/thrust.svg" alt="charge" height="32" width="32" />
C'était une charge, les parades de votre adversaire auront un -4 et il ne pourra pas esquiver!
{{ else if (eq attackerRoll.tactique 'feinte')}}
<img class="chat-icon" src="systems/foundryvtt-reve-de-dragon/icons/heures/hd06.svg" alt="feinte" height="32"
width="32" />
C'était une feinte!
{{/if}}
</div>
{{/if}}

View File

@ -1,30 +0,0 @@
<h4>
{{#if show.title}}{{show.title}}: {{/if}}
<br>
<span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
{{/each}}
</div>
{{/if}}
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
{{#if show.points}}
<hr>
<div>
<span>{{rolled.ptTache}} points de tâche{{#if rolled.ptQualite}}, ajustement Qualité {{numberFormat rolled.ptQualite decimals=0 sign=true}}{{/if}}</span>
</div>
{{/if}}
{{~#if show.explications}}
{{#unless show.points}}<hr>{{/unless}}
<div>
{{show.explications}}
</div>
{{/if}}

View File

@ -1,17 +1,24 @@
<h4>
{{#if isSortReserve}}Mise en réserve{{else}}Lancement{{/if}} du sort {{selectedSort.name}} (r {{selectedSort.data.ptreve_reel}})
{{alias}} {{#if isSortReserve}}met en réserve{{else}}lance{{/if}} le
{{selectedSort.data.isrituel}}rituel{{else}}sort{{/if}}
{{selectedSort.name}} (r {{selectedSort.data.ptreve_reel}})
<br>
<span class="tooltip">
{{competence.name}}: {{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div>Pour {{selectedSort.data.ptreve_reel}} points de rêve en {{coordLabel}} ({{coord}})</div>
<div>

View File

@ -1,18 +1,22 @@
<h4>
{{tache.name}}: T&acirc;che {{selectedCarac.label}} / {{competence.name}}
{{alias}} travaille à sa t&acirc;che {{tache.name}}
<br>{{selectedCarac.label}} / {{competence.name}}
<span class="tooltip">
{{rolled.caracValue}} à {{numberFormat rolled.finalLevel decimals=0 sign=true}}
{{#if ajustements}}
<div class="tooltiptext ttt-ajustements">
<div>Ajustements</div>
{{#each ajustements as |item key|}}
<div class="{{#if item.strong}}strong-text{{/if}}" >{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}{{#if item.unit}}{{item.unit}}{{/if}}</div>
<div class="{{#if item.strong}}strong-text{{/if}}">
{{#if item.descr}}
{{{item.descr}}}
{{else}}
{{item.label}}: {{numberFormat item.value decimals=0 sign=true}}
{{/if}}
</div>
{{/each}}
</div>
{{/if}}
</span>
{{#if rolled.needSignificative}}<label class="rdd-need-significative">(&times;&frac12;)</label>{{/if}} =
{{rolled.score}}%
{{#if rolled.factor}}<label class="rdd-need-significative">(&times;{{{rolled.factor}}})</label>{{/if}} = {{rolled.score}}%
</h4>
<div><span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span></div>
<hr>