diff --git a/module/actor.js b/module/actor.js
index 84bc05c0..d90a164b 100644
--- a/module/actor.js
+++ b/module/actor.js
@@ -31,8 +31,9 @@ export class RdDActor extends Actor {
static async create(data, options) {
// Case of compendium global import
- if (data instanceof Array)
+ if (data instanceof Array) {
return super.create(data, options);
+ }
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
if (data.items) {
return super.create(data, options);
@@ -126,15 +127,18 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- async performRoll(rollData) {
- let rolled = await RdDResolutionTable.roll(rollData.caracValue, rollData.finalLevel);
- //rolled.isPart = true; // Pour tester le particulières
- rollData.rolled = rolled; // garder le résultat
- //console.log("performRoll", rollData, rolled)
- if ( !rollData.attackerRoll) // Store in the registry if not a defense roll
- game.system.rdd.rollDataHandler[this.data._id] = rollData;
+ async performRoll(rollData, attacker = undefined) {
- if (rolled.isPart && rollData.arme && !rollData.attackerRoll) { // Réussite particulière avec attaque -> choix !
+ // garder le résultat
+ rollData.rolled = await RdDResolutionTable.roll(rollData.caracValue, rollData.finalLevel);
+
+
+ //console.log("performRoll", rollData)
+ if ( !rollData.attackerRoll) {// Store in the registry if not a defense roll
+ game.system.rdd.rollDataHandler[this.data._id] = rollData;
+ }
+
+ if (rollData.rolled.isPart && rollData.arme && !rollData.attackerRoll) { // Réussite particulière avec attaque -> choix !
let message = "Réussite particulière en attaque";
message = message + "
Attaquer en Force";
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
@@ -144,19 +148,18 @@ export class RdDActor extends Actor {
}
ChatMessage.create( {content : message, whisper: ChatMessage.getWhisperRecipients( this.name ) } );
} else {
- this.continueRoll(rollData);
+ this.continueRoll(rollData, attacker);
}
}
/* -------------------------------------------- */
- async continueRoll(rollData) {
+ async continueRoll(rollData, attacker = undefined) {
let rolled = rollData.rolled;
- let result = rolled.roll;
let quality = rolled.quality
// Manage weapon categories when parrying (cf. page 115 )
let need_resist = false; // Do we need to make resistance roll for defender ?
- if (rollData.arme && rollData.attackerRoll) { // Manage parade depeding on weapon type, and change roll results
+ if (rollData.arme && rollData.attackerRoll) { // Manage parade depending on weapon type, and change roll results
let attCategory = RdDUtility.getArmeCategory(rollData.attackerRoll.arme);
let defCategory = RdDUtility.getArmeCategory(rollData.arme);
if (defCategory == "bouclier")
@@ -166,7 +169,7 @@ export class RdDActor extends Actor {
if (attCategory.match("epee") && (defCategory == "hache" || defCategory == "lance"))
need_resist = true;
}
- if (this.data.type != 'entite' && (this.data.data.sante.sonne.value || rollData.particuliereAttaque == "finesse")) {
+ if (!this.isEntiteCauchemar() && (this.data.data.sante.sonne.value || rollData.particuliereAttaque == "finesse")) {
rollData.needSignificative = true;
}
@@ -183,18 +186,21 @@ export class RdDActor extends Actor {
explications = ""
// In case of fight, replace the message per dommages + localization. it indicates if result is OK or not
if (rollData.attackerRoll) { // Defense case !
- if (rollData.needSignificative && rolled.isSign ) {
- explications += "
Attaque parée/esquivée !";
- } else if ( !rollData.needSignificative && rolled.isSuccess) {
+ if (rolled.isSign || (!rollData.needSignificative && rolled.isSuccess)) {
explications += "
Attaque parée/esquivée !";
} else {
explications += "
Esquive/Parade échouée, encaissement !";
if (rollData.needSignificative)
- explications += "Significative nécessaire!";
- encaisser = true;
+ explications += " Significative nécessaire!";
}
+ encaisser = rollData.needSignificative ? !rolled.isSign : !rolled.isSuccess;
} else { // This is the attack roll!
if (rolled.isSuccess) {
+ let target = this.getTarget();
+ if (await this.targetEntiteNonAccordee(target, 'avant-defense')) {
+ return;
+ }
+
// Message spécial pour la rapidité, qui reste difficile à gérer automatiquement
if ( rollData.particuliereAttaque == 'rapidite') {
ChatMessage.create( { content: "Vous avez attaqué en Rapidité. Ce cas n'est pas géré autmatiquement, donc suivez les directives de votre MJ pour gérer ce cas.",
@@ -203,14 +209,14 @@ export class RdDActor extends Actor {
rollData.domArmePlusDom = this._calculBonusDommages(rollData.selectedCarac, rollData.arme, rollData.particuliereAttaque == 'force' );
rollData.degats = new Roll("2d10").roll().total + rollData.domArmePlusDom;
rollData.loc = RdDUtility.getLocalisation();
- for (let target of game.user.targets) {
- rollData.mortalite = (rollData.mortalite) ? rollData.mortalite : "mortel";// Force default
- rollData.mortalite = (target.actor.data.type == 'entite') ? "cauchemar" : rollData.mortalite;
- console.log("Mortalité : ", rollData.mortalite, target.actor.data.type);
+
+ if (target)
+ {
+ rollData.mortalite = RdDActor._calculMortaliteEncaissement(rollData, target);
defenseMsg = RdDUtility.buildDefenseChatCard(this, target, rollData);
explications += "
Cible : " + target.actor.data.name;
}
- explications += "
Dégâts : " + rollData.degats + "
Localisation : " + rollData.loc.label;
+ explications += "
Encaissement : " + rollData.degats + "
Localisation : " + rollData.loc.label;
} else {
explications = "
Echec ! Pas de dégâts";
}
@@ -256,10 +262,16 @@ export class RdDActor extends Actor {
// Get damages!
if (encaisser) {
- this.encaisserDommages(rollData.attackerRoll);
+ this.encaisserDommages(rollData.attackerRoll, attacker);
}
}
+ static _calculMortaliteEncaissement(rollData, target) {
+ const mortalite = target.actor.isEntiteCauchemar() ? "cauchemar" : (rollData.mortalite ? rollData.mortalite : "mortel");
+ console.log("Mortalité : ", mortalite, target.actor.data.type);
+ return mortalite;
+ }
+
/* -------------------------------------------- */
_calculBonusDommages(carac, arme, isForce=false) {
if ( arme.name.toLowerCase() == "esquive") return 0; // Specific case management
@@ -919,6 +931,9 @@ export class RdDActor extends Actor {
async santeIncDec(name, inc, isCritique = false) {
const sante = duplicate(this.data.data.sante);
let data = sante[name];
+ if (data==undefined) {
+ return;
+ }
let minValue = 0;
if (this.type == 'personnage') {
// TODO: les animaux/humanoïdes on théoriquement aussi un sconst, mais la SPA n'est pas passé par là
@@ -1221,7 +1236,7 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- async rollCompetence( name, armeItem=undefined, attackerRoll=undefined ) {
+ async rollCompetence( name, armeItem=undefined, attackerRoll=undefined, attacker = undefined) {
let competence = RdDUtility.findCompetence( this.data.items, name);
console.log("rollCompetence !!!", competence, armeItem, attackerRoll);
// Common rollData values
@@ -1275,11 +1290,23 @@ export class RdDActor extends Actor {
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html', rollData);
if (rollData.arme) {
- new RdDRollDialog("arme", html, rollData, this ).render(true);
+ if (await this.targetEntiteNonAccordee(this.getTarget(), 'avant-attaque')) {
+ return;
+ }
+ new RdDRollDialog("arme", html, rollData, this, attacker).render(true);
} else {
- new RdDRollDialog("competence", html, rollData, this ).render(true);
+ new RdDRollDialog("competence", html, rollData, this, attacker).render(true);
}
}
+
+ getTarget() {
+ if (game.user.targets && game.user.targets.size == 1) {
+ for (let target of game.user.targets) {
+ return target;
+ }
+ }
+ return undefined;
+ }
/* -------------------------------------------- */
async equiperObjet( itemID )
@@ -1321,7 +1348,13 @@ export class RdDActor extends Actor {
}
/* -------------------------------------------- */
- async encaisserDommages( attackerRoll ) {
+ async encaisserDommages( attackerRoll, attacker = undefined ) {
+
+
+ if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
+ return;
+ }
+
console.log("encaisserDommages", attackerRoll )
const armure = this.computeArmure( attackerRoll.loc, attackerRoll.domArmePlusDom);
let degatsReel = attackerRoll.degats - armure;
@@ -1356,17 +1389,17 @@ export class RdDActor extends Actor {
/* -------------------------------------------- */
- parerAttaque( attackerRoll, armeId )
+ parerAttaque( attackerRoll, armeId, attacker = undefined )
{
let armeItem = this.getOwnedItem(armeId); // Item.data.data !
console.log("Going to PARY !!!!!!!!!", armeItem, attackerRoll.diffLibre);
- this.rollCompetence( armeItem.data.data.competence, armeItem.data, attackerRoll );
+ this.rollCompetence( armeItem.data.data.competence, armeItem.data, attackerRoll, attacker);
}
/* -------------------------------------------- */
- esquiverAttaque( attackerRoll )
+ esquiverAttaque( attackerRoll, attacker = undefined )
{
- this.rollCompetence( "esquive", undefined, attackerRoll );
+ this.rollCompetence( "esquive", undefined, attackerRoll, attacker );
}
/* -------------------------------------------- */
@@ -1376,7 +1409,73 @@ export class RdDActor extends Actor {
return data;
}
+
+
+ /* -- entites -- */
+ /* retourne true si on peut continuer, false si on ne peut pas continuer */
+ async targetEntiteNonAccordee(target, when='avant-encaissement')
+ {
+ if (target)
+ {
+ return !await this.accorder(target.actor, when);
+ }
+ return false;
+ }
+ async accorder(entite, when = 'avant-encaissement')
+ {
+ if (when != game.settings.get("foundryvtt-reve-de-dragon", "accorder-entite-cauchemar")
+ || !entite.isEntiteCauchemar()
+ || entite.isEntiteCauchemarAccordee(this)) {
+ return true;
+ }
+
+ let rolled = await RdDResolutionTable.roll( this.getReveActuel(), - Number(entite.data.data.carac.niveau.value));
+
+ let message = {
+ content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "
",
+ whisper: ChatMessage.getWhisperRecipients(this.name)
+ };
+
+ if (rolled.isSuccess) {
+ await entite.setEntiteReveAccordee(this);
+ message.content += this.name + " s'est accordé avec " + entite.name;
+ }
+ else {
+ message.content+= this.name + " n'est pas accordé avec " + entite.name;
+ }
+
+ ChatMessage.create( message );
+ return rolled.isSuccess;
+ }
+
+ isEntiteCauchemar()
+ {
+ return this.data.type == 'entite';
+ }
+
+ isEntiteCauchemarAccordee(attaquant)
+ {
+ if (!this.isEntiteCauchemar()) { return true; }
+ let resonnance = this.data.data.sante.resonnance;
+ return (resonnance.actors.find(it => it == attaquant._id));
+ }
+
+ async setEntiteReveAccordee(attaquant)
+ {
+ if (!this.isEntiteCauchemar()) {
+ ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve");
+ return;
+ }
+ let resonnance = duplicate(this.data.data.sante.resonnance);
+ if (resonnance.actors.find(it => it == attaquant._id)){
+ // déjà accordé
+ return;
+ }
+ resonnance.actors.push(attaquant._id);
+ await this.update( {"data.sante.resonnance": resonnance});
+ return;
+ }
}
diff --git a/module/rdd-main.js b/module/rdd-main.js
index bbc31000..f2a7d055 100644
--- a/module/rdd-main.js
+++ b/module/rdd-main.js
@@ -105,9 +105,23 @@ Hooks.once("init", async function() {
rollDataHandler: {},
TMRUtility: TMRUtility
}
- // Create specific settings
+ game.settings.register("foundryvtt-reve-de-dragon", "accorder-entite-cauchemar", {
+ name: "Accorder le rêve aux entités",
+ hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
+ scope: "world",
+ config: true,
+ type: String,
+ choices: { // If choices are defined, the resulting setting will be a select menu
+ "avant-attaque": "Avant l'attaque",
+ "avant-defense": "Avant la défense",
+ "avant-encaissement": "Avant l'encaissement",
+ },
+ default: "avant-encaissement"
+ });
+
+ // Create specific settings
// game.settings.register("foundryvtt-reve-de-dragon", "configuration", {
- // name: "configuration",
+ // name: "configuration",
// scope: "world",
// config: false,
// type: Object
@@ -119,7 +133,7 @@ Hooks.once("init", async function() {
config: true,
default: false,
type: Boolean
- });
+ });
//game.settings.get("","") to retrieve it and game.settings.set("","", )
/**
diff --git a/module/rdd-roll-dialog.js b/module/rdd-roll-dialog.js
index 18594137..db7854ce 100644
--- a/module/rdd-roll-dialog.js
+++ b/module/rdd-roll-dialog.js
@@ -9,7 +9,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
export class RdDRollDialog extends Dialog {
/* -------------------------------------------- */
- constructor(mode, html, rollData, actor) {
+ constructor(mode, html, rollData, actor, attacker = undefined) {
let myButtons
if (mode == "sort") {
@@ -47,12 +47,13 @@ export class RdDRollDialog extends Dialog {
this.mode = mode
this.rollData = rollData
this.actor = actor
+ this.attacker = attacker
}
/* -------------------------------------------- */
performRollSort(html, isSortReserve = false) {
this.rollData.isSortReserve = isSortReserve;
- this.actor.performRoll(this.rollData);
+ this.actor.performRoll(this.rollData, attacker);
}
/* -------------------------------------------- */
diff --git a/module/rdd-utility.js b/module/rdd-utility.js
index eff98f86..76a8885a 100644
--- a/module/rdd-utility.js
+++ b/module/rdd-utility.js
@@ -809,7 +809,7 @@ export class RdDUtility {
rollData.attackerid = attackerid;
rollData.defenderTokenId = defenderTokenId;
let defenderToken = canvas.tokens.get( defenderTokenId );
- defenderToken.actor.encaisserDommages( rollData );
+ defenderToken.actor.encaisserDommages( rollData, game.actors.get(attackerid));
} else { // Emit message for GM
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_encaisser",
@@ -824,7 +824,7 @@ export class RdDUtility {
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
let armeId = event.currentTarget.attributes['data-armeid'].value;
let rollData = game.system.rdd.rollDataHandler[attackerid];
- defenderToken.actor.parerAttaque( rollData, armeId );
+ defenderToken.actor.parerAttaque( rollData, armeId, game.actors.get(attackerid));
});
html.on("click", '#esquiver-button', event => {
@@ -833,7 +833,7 @@ export class RdDUtility {
let defenderToken = canvas.tokens.get(event.currentTarget.attributes['data-defenderTokenId'].value );
let rollData = game.system.rdd.rollDataHandler[attackerid];
//console.log("Esquive !", rollData, defenderActor);
- defenderToken.actor.esquiverAttaque( rollData );
+ defenderToken.actor.esquiverAttaque( rollData, game.actors.get(attackerid));
});
html.on("click", '#particuliere-attaque', event => {
diff --git a/system.json b/system.json
index c3b80e93..aa52ecb2 100644
--- a/system.json
+++ b/system.json
@@ -5,7 +5,7 @@
"version": "1.1.0",
"minimumCoreVersion": "0.7.5",
"compatibleCoreVersion": "0.7.7",
- "templateVersion": 52,
+ "templateVersion": 53,
"author": "LeRatierBretonnien",
"esmodules": [ "module/rdd-main.js", "module/hook-renderChatLog.js" ],
"styles": ["styles/simple.css"],
diff --git a/template.json b/template.json
index af5bebec..bc4d142c 100644
--- a/template.json
+++ b/template.json
@@ -50,6 +50,9 @@
"value": 10,
"label": "Endurance",
"derivee": false
+ },
+ "resonnance": {
+ "actors" : []
}
},
"compteurs": {