forked from public/foundryvtt-reve-de-dragon
#42 Tchat message fin
parade, esquive inclus deterioration arme de parade inclus recul sous le choc
This commit is contained in:
@ -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,13 +213,18 @@ 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;
|
||||
await this.update( {"data.reve.reserve": reserve } );
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDiviseurSignificative() {
|
||||
return this.getSurprise() == 'demi' ? 2 : 1;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getSurprise() {
|
||||
@ -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')
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -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 d’hast 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;
|
||||
}
|
||||
|
||||
|
@ -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é qu’au 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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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 ×${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 '½';
|
||||
case 4: return '¼';
|
||||
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));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
@ -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,
|
||||
|
@ -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',
|
||||
|
Reference in New Issue
Block a user