From 41e63cd7e085f1951784592234e21399aef8df59 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Sat, 23 Jan 2021 18:04:49 +0100 Subject: [PATCH 01/34] Gere recul pour creature --- module/rdd-combat.js | 14 +++++++++++--- system.json | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index fff177b3..95827deb 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -794,9 +794,17 @@ export class RdDCombat { if (this._isAttaqueCauseRecul(attackerRoll)) { let impactRecul = this._computeImpactRecul(attackerRoll); - const agilite = this.defender.isEntiteCauchemar() - ? this.defender.data.data.carac.reve.value - : this.defender.data.data.carac.agilite.value; + const agilite = 10; + if ( this.defender.data.data.carac.agilite ) { + agilite = this.defender.data.data.carac.agilite.value; + } else if ( this.defender.data.data.carac.force) { + agilite = this.defender.data.data.carac.force.value; + } else if ( this.defender.isEntiteCauchemar()) { + agilite = this.defender.data.data.carac.reve.value; + } else + ui.notifications.warn("Recul impossible pour cette créature/entité"); + return; + } let rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impactRecul, showDice: false }); diff --git a/system.json b/system.json index 56881e3e..8c2d166c 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", "description": "Rêve de Dragon RPG for FoundryVTT", - "version": "1.2.36", + "version": "1.2.37", "manifestPlusVersion": "1.0.0", "minimumCoreVersion": "0.7.5", "compatibleCoreVersion": "0.7.8", From 26722d26fda5d98fb6c1e7e40e7c8e2ea510c432 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 23 Jan 2021 18:36:30 +0100 Subject: [PATCH 02/34] Fixes recul/desarmement --- module/actor.js | 70 +++++++++++++++-------- module/rdd-combat.js | 41 ++++++------- module/rdd-resolution-table.js | 2 +- module/rdd-roll.js | 1 - templates/chat-resultat-encaissement.html | 22 ++++--- templates/chat-resultat-esquive.html | 5 -- templates/chat-resultat-parade.html | 39 ++++++------- 7 files changed, 95 insertions(+), 85 deletions(-) diff --git a/module/actor.js b/module/actor.js index 8bd31bbb..1b7f4336 100644 --- a/module/actor.js +++ b/module/actor.js @@ -179,18 +179,34 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ getReveActuel() { - return this.data.data.reve?.reve?.value ?? this.data.data.carac.reve.value; - } - - getChanceActuel() { - return this.data.data.compteurs.chance?.value ?? 10; + return Misc.toInt(this.data.data.reve?.reve?.value ?? this.data.data.carac.reve.value); } /* -------------------------------------------- */ - getForceValue() { - return this.data.data.carac.force?.force ?? this.data.data.carac.reve.value; + getChanceActuel() { + return Misc.toInt(this.data.data.compteurs.chance?.value ?? 10); + } + /* -------------------------------------------- */ + getTaille() { + return Misc.toInt(this.data.data.carac.taille?.value); + } + /* -------------------------------------------- */ + getForce() { + if (this.isEntiteCauchemar()) { + return Misc.toInt(this.data.data.carac.reve?.value); + } + return Misc.toInt(this.data.data.carac.force?.value); + } + /* -------------------------------------------- */ + getAgilite() { + switch(this.data.type) { + case 'personnage': return Misc.toInt(this.data.data.carac.agilite?.value); + case 'creature': return Misc.toInt(this.data.data.carac.force?.value); + case 'entite': return Misc.toInt(this.data.data.carac.reve?.value); + } + return 10; } getMoralTotal() { - return this.data.data.compteurs.moral?.value ?? 0; + return Misc.toInt(this.data.data.compteurs.moral?.value); } /* -------------------------------------------- */ getBonusDegat() { @@ -203,16 +219,16 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ getEtatGeneral() { - return this.data.data.compteurs.etat?.value ?? 0; + return Misc.toInt(this.data.data.compteurs.etat?.value); } getMalusArmure() { - return this.data.data.attributs?.malusarmure?.value ?? 0; + return Misc.toInt(this.data.data.attributs?.malusarmure?.value); } getEncTotal() { return Math.floor(this.encTotal ?? 0); } getSurenc() { - return this.data.data.compteurs.surenc?.value ?? 0; + return Misc.toInt(this.data.data.compteurs.surenc?.value); } /* -------------------------------------------- */ loadCompendiumNames() { @@ -229,7 +245,6 @@ export class RdDActor extends Actor { getMeditation(id) { return this.data.items.find(item => item.type == 'meditation' && item._id == id); } - /* -------------------------------------------- */ getBestDraconic() { const list = this.getDraconicList().sort((a, b) => b.data.niveau - a.data.niveau); @@ -559,8 +574,7 @@ export class RdDActor extends Actor { async updateCarac(caracName, caracValue) { let caracpath = "data.carac." + caracName + ".value" if (caracName == "force") { - let caracTaille = this.data.data.carac.taille; - if ( Number(caracValue) > Number(caracTaille.value)+4) { + if ( Number(caracValue) > this.getTaille() + 4) { ui.notifications.warn("Votre FORCE doit être au maximum de TAILLE+4"); return; } @@ -580,6 +594,9 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async updateCaracXP(caracName, caracXP) { + if (caracName == 'Taille') { + return; + } let caracpath = "data.carac." + caracName + ".xp"; await this.update({ [caracpath]: caracXP }); this.checkCaracXP(caracName); @@ -1971,7 +1988,9 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async appliquerExperience(rolled, caracName, competence = undefined) { - + if (this.isCreature()) { + return; + } if (rolled.isPart && rolled.finalLevel < 0) { // Cas de désir lancinant, pas d'expérience sur particulière if (this.checkDesirLancinant()) { @@ -2222,7 +2241,7 @@ export class RdDActor extends Actor { } /* -------------------------------------------- */ - async encaisserDommages(rollData, attacker = undefined) { + async encaisserDommages(rollData, attacker = undefined, defenderRoll = undefined) { if (attacker && !await attacker.accorder(this, 'avant-encaissement')) { return; } @@ -2241,15 +2260,16 @@ export class RdDActor extends Actor { this.computeEtatGeneral(); this.sheet.render(false); - let santeActuelle = duplicate(this.data.data.sante); - - encaissement.alias = this.data.name; - encaissement.hasPlayerOwner = this.hasPlayerOwner; - encaissement.resteEndurance = santeActuelle.endurance.value - encaissement.sonne = perteEndurance.sonne; - encaissement.jetEndurance = perteEndurance.jetEndurance; - encaissement.endurance = santeOrig.endurance.value - perteEndurance.newValue; - encaissement.vie = this.isEntiteCauchemar() ? 0 : (santeOrig.vie.value - perteVie.newValue); + mergeObject(encaissement, { + alias: this.data.name, + hasPlayerOwner: this.hasPlayerOwner, + resteEndurance: this.data.data.sante.endurance.value, + sonne: perteEndurance.sonne, + jetEndurance: perteEndurance.jetEndurance, + endurance: santeOrig.endurance.value - perteEndurance.newValue, + vie: this.isEntiteCauchemar() ? 0 : (santeOrig.vie.value - perteVie.newValue), + show: defenderRoll?.show ?? {} + }); ChatUtility.createChatWithRollMode(this.name, { roll: encaissement.roll, diff --git a/module/rdd-combat.js b/module/rdd-combat.js index fff177b3..4191f302 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -270,7 +270,7 @@ export class RdDCombat { /* -------------------------------------------- */ attaqueDestinee(attackerRoll) { ui.notifications.info('Attaque significative grâce à la destinée') - RdDResolutionTable.forceSignificative(attackerRoll.rolled); + RdDResolutionTable.significativeRequise(attackerRoll.rolled); this.removeChatMessageActionsPasseArme(attackerRoll.passeArme); this._onAttaqueNormale(attackerRoll); } @@ -289,7 +289,7 @@ export class RdDCombat { let defenderRoll = RdDCombat._getDefense(attackerRoll.passeArme); if (defenderRoll) { ui.notifications.info('Défense significative grâce à la destinée') - RdDResolutionTable.forceSignificative(defenderRoll.rolled); + RdDResolutionTable.significativeRequise(defenderRoll.rolled); this.removeChatMessageActionsPasseArme(defenderRoll.passeArme); if (defenderRoll.arme) { this._onParadeNormale(defenderRoll); @@ -601,7 +601,6 @@ export class RdDCombat { let rollData = { passeArme: attackerRoll.passeArme, - forceValue: this.defender.getForceValue(), diffLibre: attackerRoll.diffLibre, attackerRoll: attackerRoll, competence: this.defender.getCompetence(compName), @@ -698,7 +697,6 @@ export class RdDCombat { _prepareEsquive(attackerRoll, competence) { let rollData = { passeArme: attackerRoll.passeArme, - forceValue: this.defender.getForceValue(), diffLibre: attackerRoll.diffLibre, attackerRoll: attackerRoll, competence: competence, @@ -774,16 +772,13 @@ export class RdDCombat { } } // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132) - if (resistance > 0 && !RdDItemArme.getCategorieParade(rollData.arme) == 'boucliers') { + if (resistance > 0 && RdDItemArme.getCategorieParade(rollData.arme) != 'boucliers') { let desarme = await RdDResolutionTable.rollData({ - caracValue: this.defender.data.data.carac.force.value, + caracValue: this.defender.getForce(), finalLevel: Misc.toInt(rollData.competence.data.niveau) - dmg, showDice: false }); rollData.show.desarme = desarme.rolled.isEchec; - if (desarme.rolled.isEchec) { - rollData.show.desarme = true; - } } } } @@ -793,23 +788,18 @@ export class RdDCombat { const attackerRoll = defenderRoll.attackerRoll; if (this._isAttaqueCauseRecul(attackerRoll)) { - let impactRecul = this._computeImpactRecul(attackerRoll); - const agilite = this.defender.isEntiteCauchemar() - ? this.defender.data.data.carac.reve.value - : this.defender.data.data.carac.agilite.value; - - let rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impactRecul, showDice: false }); - - if (rollRecul.isSuccess) { + const impact = this._computeImpactRecul(attackerRoll); + const rollRecul = await RdDResolutionTable.rollData({ caracValue: 10, finalLevel: impact }); + + if (rollRecul.rolled.isSuccess) { defenderRoll.show.recul = 'encaisse'; - } else if (rollRecul.isETotal) { + } else if (rollRecul.rolled.isETotal) { defenderRoll.show.recul = 'chute'; } else { - let chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impactRecul, showDice: false }); - defenderRoll.show.recul = (chute.isSuccess) - ? 'recul' - : 'chute'; + const agilite = this.defender.getAgilite(); + const chute = await RdDResolutionTable.rollData({ caracValue: agilite, finalLevel: impact }); + defenderRoll.show.recul = (chute.rolled.isSuccess) ? 'recul' : 'chute'; } } } @@ -819,7 +809,10 @@ export class RdDCombat { } _computeImpactRecul(attaque) { - return Misc.toInt(this.defender.data.data.carac.taille.value) - (attaque.forceValue + attaque.arme.data.dommagesReels); + const taille = this.defender.getTaille(); + const force = this.attacker.getForce(); + const dommages = attaque.arme.data.dommagesReels; + return taille - (force + dommages); } /* -------------------------------------------- */ @@ -841,7 +834,7 @@ export class RdDCombat { attackerRoll.defenderTokenId = defenderTokenId; await this.computeRecul(defenderRoll); - this.defender.encaisserDommages(attackerRoll, this.attacker); + this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll); } else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_encaisser", diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index 395b3659..226230b2 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -138,7 +138,7 @@ export class RdDResolutionTable { mergeObject(chances, this._computeCell(null, newScore), { overwrite: true }); } } - static forceSignificative(chances) { + static significativeRequise(chances) { chances.roll = Math.floor(chances.score / 2); mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true }); } diff --git a/module/rdd-roll.js b/module/rdd-roll.js index 9f45752d..f10e285c 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -44,7 +44,6 @@ export class RdDRoll extends Dialog { diffLibre: rollData.competence?.data.default_diffLibre ?? 0, editLibre: true, editConditions: true, - forceValue: actor.getForceValue(), malusArmureValue: actor.getMalusArmure(), surencMalusFlag: actor.isPersonnage() ? (actor.data.data.compteurs.surenc.value < 0) : false, surencMalusValue: actor.getSurenc(), diff --git a/templates/chat-resultat-encaissement.html b/templates/chat-resultat-encaissement.html index 1c666f13..10a7ab0e 100644 --- a/templates/chat-resultat-encaissement.html +++ b/templates/chat-resultat-encaissement.html @@ -30,15 +30,19 @@ {{/if}} ({{dmg.loc.label}}) {{#if (gt endurance 0)}} - {{#if hasPlayerOwner}}, a perdu {{endurance}} points d'endurance - {{#if (ne vie 0)}}, {{vie}} points de vie{{/if}} - {{/if}} - {{#if (ne dmg.mortalite 'cauchemar')}} - {{#if (gt endurance 1)}}et - {{#if sonne}}est sonnécharge jusqu'à la fin du prochain round{{else}}n'est pas sonné{{/if}} - ({{jetEndurance}} / {{resteEndurance}})! - {{/if}} - {{/if}} + {{#if hasPlayerOwner}}, a perdu {{endurance}} points d'endurance + {{#if (ne vie 0)}}, {{vie}} points de vie{{/if}} + {{/if}} + {{#if (ne dmg.mortalite 'cauchemar')}} + {{#if (gt endurance 1)}}et + {{#if sonne}}est sonnécharge jusqu'à la fin du prochain round{{else}}n'est pas sonné{{/if}} + ({{jetEndurance}} / {{resteEndurance}})! + {{/if}} + {{/if}} + {{/if}} + {{#if (eq show.recul 'encaisse')}}
{{alias}} ne recule pas malgré la violence du coup.
+ {{else if (eq show.recul 'chute')}}
Sous la violence du coup, {{alias}} recule et chute au sol ! Il/elle ne pourra plus attaquer ce round.
+ {{else if (eq show.recul 'recul')}}
La violence du coup fait reculer {{alias}} de quelques mètres ! Il/elle ne pourra plus attaquer ce round.
{{/if}} {{/if}} \ No newline at end of file diff --git a/templates/chat-resultat-esquive.html b/templates/chat-resultat-esquive.html index e802e32f..471d5def 100644 --- a/templates/chat-resultat-esquive.html +++ b/templates/chat-resultat-esquive.html @@ -15,11 +15,6 @@ {{/if}} -{{#if (eq show.recul 'encaisse')}}
Vous ne reculez pas malgré la violence du coup.
-{{else if (eq show.recul 'chute')}}
Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round.
-{{else if (eq show.recul 'recul')}}
La violence du choup vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round.
-{{/if}} - {{#if attackerRoll.tactique}}
{{#if (eq attackerRoll.tactique 'charge')}} diff --git a/templates/chat-resultat-parade.html b/templates/chat-resultat-parade.html index dbff81a1..75c84e78 100644 --- a/templates/chat-resultat-parade.html +++ b/templates/chat-resultat-parade.html @@ -4,43 +4,42 @@ {{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html"}}
- {{#if rolled.isSuccess}} - Attaque parée! - {{#if rolled.isPart}} - - Vous pouvez utiliser votre arme pour une deuxième parade! + + {{#if rolled.isSuccess}} + Attaque parée! + {{#if rolled.isPart}}{{alias}} pourra tenter une deuxième parade!{{/if}} + {{else}} + La parade a échoué! {{/if}} - {{else}} - Votre parade a échoué! - {{/if}} +
-{{#if (eq show.recul 'encaisse')}}
Vous ne reculez pas malgré la violence du coup.
-{{else if (eq show.recul 'brise')}}
Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round.
-{{else if (eq show.recul 'perte')}}
La violence du choup vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round.
+{{#if (eq show.recul 'encaisse')}}
{{alias}} ne recule pas malgré la violence du coup.
+{{else if (eq show.recul 'chute')}}
Sous la violence du coup, {{alias}} recule et chute au sol ! Il/elle ne pourra plus attaquer ce round.
+{{else if (eq show.recul 'recul')}}
La violence du coup fait reculer {{alias}} de quelques mètres ! Il/elle ne pourra plus attaquer ce round.
{{/if}} {{#if (eq show.deteriorationArme 'resiste')}} -
Votre {{arme.name}} résiste au choc de la parade.
-{{else if (eq show.deteriorationArme 'resiste')}} -
Sous la violence de la parade, votre {{arme.name}} s'est brisée!
-{{else if (eq show.deteriorationArme 'resiste')}} -
En parant, vous endommagez votre {{arme.name}} qui perd {{show.perteResistance}} de résistance.
+
L'arme résiste au choc de la parade.
+{{else if (eq show.deteriorationArme 'brise')}} +
Sous la violence de la parade, {{arme.name}} s'est brisée!
+{{else if (eq show.deteriorationArme 'perte')}} +
En parant, l'arme perd {{show.perteResistance}} de résistance.
{{/if}} {{#if show.desarme}} -
Vous ne parvenez pas à garder votre arme en main, elle tombe à vos pieds.
+
Le défenseur {{alias}} lâche son arme qui tombe à ses pieds.
{{/if}} {{#if attackerRoll.tactique}}
{{#if (eq attackerRoll.tactique 'charge')}} charge - C'était une charge, les parades de votre adversaire auront un -4 et il ne pourra pas esquiver! + C'était une charge, les parades de l'adversaire auront un -4 et il ne pourra pas esquiver! {{ else if (eq attackerRoll.tactique 'feinte')}} feinte + width="32" /> C'était une feinte! {{/if}}
-{{/if}} +{{/if}} \ No newline at end of file From 68cd2cef3319cbaf0ee3c43bb0ab8b7cd9fae6d1 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Sat, 23 Jan 2021 20:40:13 +0100 Subject: [PATCH 03/34] FVarious fixes --- system.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system.json b/system.json index 8c2d166c..8b683398 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", "description": "Rêve de Dragon RPG for FoundryVTT", - "version": "1.2.37", + "version": "1.2.38", "manifestPlusVersion": "1.0.0", "minimumCoreVersion": "0.7.5", "compatibleCoreVersion": "0.7.8", From e5738aaca38af79c47bc5e8075e7962f326e1e16 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Sun, 21 Feb 2021 22:24:39 +0100 Subject: [PATCH 04/34] #161 Amenagement sur beaute --- module/actor-sheet.js | 1 + system.json | 2 +- templates/actor-sheet.html | 8 +++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 13d5c932..b9d67299 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -66,6 +66,7 @@ export class RdDActorSheet extends ActorSheet { currentCarac.xpNext = RdDUtility.getCaracNextXp(currentCarac.value); currentCarac.isLevelUp = (currentCarac.xp >= currentCarac.xpNext); } + sum += (data.data.beaute >= 0) ? (data.data.beaute - 10) : 0; data.data.caracSum = sum; // Force empty arme, at least for Esquive diff --git a/system.json b/system.json index 594aab04..871d9a2e 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", "description": "Rêve de Dragon RPG for FoundryVTT", - "version": "1.3.22", + "version": "1.3.23", "manifestPlusVersion": "1.0.0", "minimumCoreVersion": "0.7.5", "compatibleCoreVersion": "0.7.9", diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 2ae3963d..4ce76665 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -155,6 +155,11 @@
    +
  • + Beauté : + + +
  • {{#each data.attributs as |attr key|}}
  • {{attr.label}} : @@ -1038,7 +1043,8 @@
  • From 11479556dc21d499afcf9ed173c214abc6b3dcc6 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 21 Feb 2021 23:45:32 +0100 Subject: [PATCH 05/34] =?UTF-8?q?Tooltips=20par=20dessus=20les=20ic=C3=B4n?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le zIndex des tooltips n'était pas positionné --- module/tmr-utility.js | 1 + module/tmr/pixi-tmr.js | 1 + 2 files changed, 2 insertions(+) diff --git a/module/tmr-utility.js b/module/tmr-utility.js index 3aa49a99..aa0358ef 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -282,6 +282,7 @@ export const tmrTokenZIndex = { rencontre: 50, trounoir: 60, demireve: 70, + tooltip: 100, } /* -------------------------------------------- */ diff --git a/module/tmr/pixi-tmr.js b/module/tmr/pixi-tmr.js index 505f1574..a2a24743 100644 --- a/module/tmr/pixi-tmr.js +++ b/module/tmr/pixi-tmr.js @@ -100,6 +100,7 @@ export class PixiTMR { addTooltip(sprite, text) { if (text) { sprite.tooltip = new PIXI.Text(text, tooltipStyle); + sprite.tooltip.zIndex = tmrTokenZIndex.tooltip; sprite.isOver = false; sprite.interactive = true; sprite.on('pointerdown', event => this.onClickBackground(event)) From 1d96374b31d1cfb1c324f9881f715ea0e09ac249 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Mon, 22 Feb 2021 21:15:10 +0100 Subject: [PATCH 06/34] #160 Afficher les totaux d'archetypes --- module/actor-sheet.js | 3 +++ module/rdd-utility.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index b9d67299..22abd450 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -41,11 +41,14 @@ export class RdDActorSheet extends ActorSheet { data.itemsByType = Misc.classify(data.items); // Competence per category + data.data.comptageArchetype = RdDUtility.getLimitesArchetypes(); data.data.competenceXPTotal = 0; data.competenceByCategory = Misc.classify( data.itemsByType.competence, item => item.data.categorie, item => { + let archetypeKey = (item.data.niveau_archetype < 0) ? 0 : item.data.niveau_archetype; + data.data.comptageArchetype[archetypeKey].nombre = data.data.comptageArchetype[archetypeKey].nombre + 1; //Comptage archetype item.data.xpNext = RdDItemCompetence.getCompetenceNextXp(item.data.niveau); item.data.isLevelUp = item.data.xp >= item.data.xpNext; // Flag de niveau à MAJ //this.actor.checkCompetenceXP(item.name); // Petite vérification experience diff --git a/module/rdd-utility.js b/module/rdd-utility.js index de605b65..9f8340c6 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -22,6 +22,22 @@ const categorieCompetences = { "lancer": { level: "-8", label: "Lancer" } } +/* -------------------------------------------- */ +const limitesArchetypes = [ + { "niveau": 0, "nombreMax": 100, "nombre":0}, + { "niveau": 1, "nombreMax": 10, "nombre":0}, + { "niveau": 2, "nombreMax": 9, "nombre":0}, + { "niveau": 3, "nombreMax": 8, "nombre":0}, + { "niveau": 4, "nombreMax": 7, "nombre":0}, + { "niveau": 5, "nombreMax": 6, "nombre":0}, + { "niveau": 6, "nombreMax": 5, "nombre":0}, + { "niveau": 7, "nombreMax": 4, "nombre":0}, + { "niveau": 8, "nombreMax": 3, "nombre":0}, + { "niveau": 9, "nombreMax": 2, "nombre":0}, + { "niveau": 10, "nombreMax": 1, "nombre":0}, + { "niveau": 11, "nombreMax": 1, "nombre":0} +]; + /* -------------------------------------------- */ // This table starts at 0 -> niveau -10 const carac_array = ["taille", "apparence", "constitution", "force", "agilite", "dexterite", "vue", "ouie", "odoratgout", "volonte", "intellect", "empathie", "reve", "chance", "melee", "tir", "lancer", "derobee"]; @@ -262,6 +278,11 @@ export class RdDUtility { return loadTemplates(templatePaths); } + /* -------------------------------------------- */ + static getLimitesArchetypes( ) { + return duplicate(limitesArchetypes); + } + /* -------------------------------------------- */ static checkNull(items) { if (items && items.length) { From 4607a331cc493a278781cdc593dcbdedddd367a7 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Mon, 22 Feb 2021 21:18:46 +0100 Subject: [PATCH 07/34] #160 Afficher les totaux d'archetypes --- templates/actor-sheet.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/templates/actor-sheet.html b/templates/actor-sheet.html index 4ce76665..80f64dea 100644 --- a/templates/actor-sheet.html +++ b/templates/actor-sheet.html @@ -516,6 +516,13 @@ Total XP compétences {{data.competenceXPTotal}}
  • + {{#if data.montrerArchetype}} + {{#each data.comptageArchetype as |archetype key|}} +
  • + +
  • + {{/each}} + {{/if}}
From 448a7b806ecc643ee9777e59e54fc691704b9400 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Tue, 23 Feb 2021 19:46:53 +0100 Subject: [PATCH 08/34] =?UTF-8?q?Ajout=20de=20v=C3=A9hicule=20"pos=C3=A9?= =?UTF-8?q?=20par=20terre"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packs/vehicules.db | 1 + 1 file changed, 1 insertion(+) diff --git a/packs/vehicules.db b/packs/vehicules.db index 9ced9deb..f458efb6 100644 --- a/packs/vehicules.db +++ b/packs/vehicules.db @@ -5,4 +5,5 @@ {"_id":"RFOYL8HBUxd32DXS","name":"Galère","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"vehicule","data":{"categorie":"Bateau","resistance":36,"structure":14,"vitesse":"2/2/1","bonus":"(12)/+12/+16","manoeuvrabilite":"0/-4/-6","equipage":10,"capacite_encombrement":300,"description":"Description ...","notesmj":"Notes du MJ"},"sort":100001,"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/galere.webp","token":{"flags":{},"name":"Galère","displayName":0,"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/galere_token.webp","tint":"","width":14,"height":14,"scale":1,"mirrorX":false,"mirrorY":false,"lockRotation":false,"rotation":0,"vision":false,"dimSight":0,"brightSight":0,"dimLight":0,"brightLight":0,"sightAngle":360,"lightAngle":360,"lightColor":"","lightAlpha":1,"lightAnimation":{"type":"","speed":5,"intensity":5},"actorId":"RFOYL8HBUxd32DXS","actorLink":false,"disposition":0,"displayBars":0,"bar1":{"attribute":""},"bar2":{"attribute":""},"randomImg":false},"items":[],"effects":[]} {"_id":"TDpSn7GawJ1LCHp7","name":"Charette","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"vehicule","data":{"categorie":"Chariot","resistance":16,"structure":8,"vitesse":"","bonus":"","manoeuvrabilite":"","equipage":1,"capacite_encombrement":100,"description":"Description ...","notesmj":"Notes du MJ"},"sort":100001,"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/charette.webp","token":{"flags":{},"name":"Charette","displayName":0,"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/charette_token.webp","tint":"","width":3,"height":3,"scale":1.1,"mirrorX":false,"mirrorY":false,"lockRotation":false,"rotation":0,"vision":false,"dimSight":0,"brightSight":0,"dimLight":0,"brightLight":0,"sightAngle":360,"lightAngle":360,"lightColor":"","lightAlpha":1,"lightAnimation":{"type":"","speed":5,"intensity":5},"actorId":"TDpSn7GawJ1LCHp7","actorLink":false,"disposition":0,"displayBars":0,"bar1":{"attribute":""},"bar2":{"attribute":""},"randomImg":false},"items":[],"effects":[]} {"_id":"ZiyRDzz3gGzlpLIc","name":"Barque","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"vehicule","data":{"categorie":"Barque","resistance":20,"structure":10,"vitesse":"3/2/1","bonus":"(4)/+4/+6","manoeuvrabilite":"0/0/-4","equipage":4,"capacite_encombrement":100,"description":"Description ...","notesmj":"Notes du MJ"},"sort":100001,"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/barque.webp","token":{"flags":{},"name":"Barque","displayName":0,"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/barque_token.webp","tint":"","width":6,"height":6,"scale":1,"mirrorX":false,"mirrorY":false,"lockRotation":false,"rotation":0,"vision":false,"dimSight":0,"brightSight":0,"dimLight":0,"brightLight":0,"sightAngle":360,"lightAngle":360,"lightColor":"","lightAlpha":1,"lightAnimation":{"type":"","speed":5,"intensity":5},"actorId":"ZiyRDzz3gGzlpLIc","actorLink":false,"disposition":0,"displayBars":0,"bar1":{"attribute":""},"bar2":{"attribute":""},"randomImg":false},"items":[],"effects":[]} +{"_id":"gM77co80kmpVsYg6","name":"Posé par terre","permission":{"default":0,"Q2G6GTdrotKzYGUC":3},"type":"vehicule","data":{"categorie":"Autre","resistance":0,"structure":0,"vitesse":"","bonus":"","manoeuvrabilite":"","equipage":0,"capacite_encombrement":100,"description":"

Déposer ici les objets que vous voulez échanger avec d'autres joueurs

","notesmj":""},"sort":100001,"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.png","token":{"flags":{},"name":"Posé par terre","displayName":0,"img":"systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.png","tint":"","width":1,"height":1,"scale":1,"mirrorX":false,"mirrorY":false,"lockRotation":false,"rotation":0,"vision":false,"dimSight":0,"brightSight":0,"dimLight":0,"brightLight":0,"sightAngle":360,"lightAngle":360,"lightColor":"","lightAlpha":1,"lightAnimation":{"type":"","speed":5,"intensity":5},"actorId":"gM77co80kmpVsYg6","actorLink":false,"disposition":0,"displayBars":0,"bar1":{"attribute":""},"bar2":{"attribute":""},"randomImg":false},"items":[],"effects":[]} {"_id":"idyDmDWYpQ4Eppen","name":"Chariot","permission":{"default":0,"rYShh2P1DNavdoBD":3},"type":"vehicule","data":{"categorie":"Chariot","resistance":20,"structure":10,"vitesse":"","bonus":"","manoeuvrabilite":"","equipage":1,"capacite_encombrement":150,"description":"Description ...","notesmj":"Notes du MJ"},"sort":100001,"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/chariot.webp","token":{"flags":{},"name":"Chariot","displayName":0,"img":"systems/foundryvtt-reve-de-dragon/icons/vehicules/chariot_token.webp","tint":"","width":4,"height":4,"scale":1.4,"mirrorX":false,"mirrorY":false,"lockRotation":false,"rotation":0,"vision":false,"dimSight":0,"brightSight":0,"dimLight":0,"brightLight":0,"sightAngle":360,"lightAngle":360,"lightColor":"","lightAlpha":1,"lightAnimation":{"type":"","speed":5,"intensity":5},"actorId":"idyDmDWYpQ4Eppen","actorLink":false,"disposition":0,"displayBars":0,"bar1":{"attribute":""},"bar2":{"attribute":""},"randomImg":false},"items":[],"effects":[]} From eaeb164627eac640faf45907de62336aedde45c2 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 01:58:55 +0100 Subject: [PATCH 09/34] =?UTF-8?q?Niveau=20d'arch=C3=A9type=20>=20+11?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le comptage des niveaux d'archétype n'empêche plus d'ouvrir la feuille d'un personnage avec un niveau d'archétype au dessus de +11 --- module/actor-sheet.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index 22abd450..b83b7492 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -48,7 +48,10 @@ export class RdDActorSheet extends ActorSheet { item => item.data.categorie, item => { let archetypeKey = (item.data.niveau_archetype < 0) ? 0 : item.data.niveau_archetype; - data.data.comptageArchetype[archetypeKey].nombre = data.data.comptageArchetype[archetypeKey].nombre + 1; //Comptage archetype + if (data.data.comptageArchetype[archetypeKey] == undefined) { + data.data.comptageArchetype[archetypeKey] = { "niveau": archetypeKey, "nombreMax": 0, "nombre": 0}; + } + data.data.comptageArchetype[archetypeKey].nombre = (data.data.comptageArchetype[archetypeKey]?.nombre??0) + 1; //Comptage archetype item.data.xpNext = RdDItemCompetence.getCompetenceNextXp(item.data.niveau); item.data.isLevelUp = item.data.xp >= item.data.xpNext; // Flag de niveau à MAJ //this.actor.checkCompetenceXP(item.name); // Petite vérification experience From 382ea2c4852564d7fbb2972dd897d480cf33d9bf Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:00:27 +0100 Subject: [PATCH 10/34] Ajout de helper "accord" pour accorder selon le genre --- module/grammar.js | 45 ++++++++++++++++++++++++++++++++++++------- module/rdd-utility.js | 1 + 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/module/grammar.js b/module/grammar.js index df4162a2..e75bdc77 100644 --- a/module/grammar.js +++ b/module/grammar.js @@ -1,11 +1,12 @@ const articlesApostrophes = { - 'de' : 'd\'', - 'le' : 'l\'', - 'la' : 'l\'' + 'de': 'd\'', + 'le': 'l\'', + 'la': 'l\'' } export class Grammar { + /* -------------------------------------------- */ static apostrophe(article, word) { if (articlesApostrophes[article] && Grammar.startsWithVoyel(word)) { return articlesApostrophes[article] + word @@ -13,28 +14,58 @@ export class Grammar { return article + ' ' + word; } + /* -------------------------------------------- */ static startsWithVoyel(word) { return word.match(/^[aeiouy]/i) } + /* -------------------------------------------- */ static toLowerCaseNoAccent(words) { return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words; } + + /* -------------------------------------------- */ static articleDetermine(genre) { - switch (genre?.toLowerCase()) { + switch (toLowerCaseNoAccent(genre)) { case 'f': case 'feminin': return 'la'; - case 'p': case 'pluriel': return 'les'; + case 'p': case 'mp': case 'fp': case 'pluriel': return 'les'; default: case 'm': case 'masculin': return 'le'; } } + + /* -------------------------------------------- */ static articleIndétermine(genre) { - switch (genre?.toLowerCase()) { + switch (toLowerCaseNoAccent(genre)) { case 'f': case 'feminin': return 'une'; - case 'p': case 'pluriel': return 'des'; + case 'p': case 'fp': case 'mp': case 'pluriel': return 'des'; case 'n': case 'neutre': return 'du' default: case 'm': case 'masculin': return 'un'; } } + + /* -------------------------------------------- */ + /** + * renvoie un des mots en fonction du genre: + * + * - masculin/neutre/m/n : mots[0] + * - feminin/f : mots[1] + * - pluriel/mp/p : mots[2] + * - fp : mots[3] + * + * @param {*} genre + * @param {...any} mots + */ + static accord(genre, ...mots) { + switch (toLowerCaseNoAccent(genre)) { + default: + case 'n': case 'neutre': + case 'm': case 'masculin': return mots[0]; + case 'f': case 'feminin': return mots[1]; + case 'p': case 'mp': case 'pluriel': return mots[2] + case 'fp': return mots[3]; + } + } + } \ No newline at end of file diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 9f8340c6..cba004fc 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -274,6 +274,7 @@ export class RdDUtility { Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL'); Handlebars.registerHelper('le', str => Grammar.articleDetermine(str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); + Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); return loadTemplates(templatePaths); } From 15144697e18e7715da0bc9777c4aca7856a28674 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:01:27 +0100 Subject: [PATCH 11/34] Fix: passage round suivant --- module/rdd-combat.js | 1 + 1 file changed, 1 insertion(+) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index f78bfc02..c9653f90 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -31,6 +31,7 @@ export class RdDCombatManager extends Combat { //console.log('New round !');s this.cleanItemUse(); this.cleanSonne(); + return super.nextRound(); } } From 9b362aa265b9918486dc8b00dbd88c3747605785 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:01:59 +0100 Subject: [PATCH 12/34] =?UTF-8?q?Fix:=20typo=20pi=C3=A8re=20->=20pi=C3=A8t?= =?UTF-8?q?re?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- templates/chat-resultat-recettecuisine.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/chat-resultat-recettecuisine.html b/templates/chat-resultat-recettecuisine.html index fa75d72d..086b6e81 100644 --- a/templates/chat-resultat-recettecuisine.html +++ b/templates/chat-resultat-recettecuisine.html @@ -8,7 +8,7 @@ {{#if rolled.isSuccess}} {{alias}} réussit sa recette, avec un plat de {{qualiteFinale}} pour {{oeuvre.data.sust}} Points de Sustentation. {{else}} - {{alias}} fait un pière cuisinier(e), et obtient {{#if (lt qualiteFinale 0)}}un plat à l'exotisme certain{{else}}un plat de qualité {{qualiteFinale}}{{/if}}. + {{alias}} fait un piètre cuisinier(e), et obtient {{#if (lt qualiteFinale 0)}}un plat à l'exotisme certain{{else}}un plat de qualité {{qualiteFinale}}{{/if}}. Selon la décision du MJ, le plat peut fournir {{oeuvre.data.sust}} Points de Sustentation {{/if}} From 55d11695f7fb23a18648cd1869155cb7daed6379 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:03:45 +0100 Subject: [PATCH 13/34] Fix: significative sur diff -11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les significatives sur difficulté -16 à -11 faisaient l'échec total spécifique à ces difficultés --- module/rdd-resolution-table.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/rdd-resolution-table.js b/module/rdd-resolution-table.js index e020deaf..ca5376a9 100644 --- a/module/rdd-resolution-table.js +++ b/module/rdd-resolution-table.js @@ -125,7 +125,7 @@ export class RdDResolutionTable { /* -------------------------------------------- */ static _updateChancesFactor(chances, diviseur) { - if (diviseur && diviseur > 1) { + if (chances.level > -11 && diviseur && diviseur > 1) { let newScore = Math.floor(chances.score / diviseur); mergeObject(chances, this._computeCell(null, newScore), { overwrite: true }); } From da56316e429a54ffde07e69d6d5da8a3fa4f5b26 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:06:21 +0100 Subject: [PATCH 14/34] =?UTF-8?q?Typo:=20maladresse=20au=20lieu=20d'=C3=A9?= =?UTF-8?q?chec=20total?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lors d'un échec total, on tire une maladresse, pas un échec total --- module/rdd-combat.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index c9653f90..dcf6e3ea 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -592,7 +592,7 @@ export class RdDCombat { const avecArme = arme?.data.categorie_parade != 'sans-armes'; const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque"); ChatUtility.createChatWithRollMode(this.defender.name, { - content: `Echec total à ${action}! ` + await RdDRollTables.getMaladresse({ arme: avecArme }) + content: `Maladresse à ${action}! ` + await RdDRollTables.getMaladresse({ arme: avecArme }) }); } From 7f0e58b216eb742f9762f99f2c56702f8edf6b18 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:08:21 +0100 Subject: [PATCH 15/34] =?UTF-8?q?d=C3=A9placement=20du=20helper=20Handleba?= =?UTF-8?q?rs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tous les helpers sont déclarés dans RdDUtility --- module/rdd-main.js | 3 --- module/rdd-utility.js | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/module/rdd-main.js b/module/rdd-main.js index 72dabf6d..328e9b1a 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -222,9 +222,6 @@ Hooks.once("init", async function () { Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true }); CONFIG.Combat.entityClass = RdDCombatManager; - // Handlebar function pour container - Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); }); - // Patch the initiative formula _patch_initiative(); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index cba004fc..b649373a 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -275,6 +275,7 @@ export class RdDUtility { Handlebars.registerHelper('le', str => Grammar.articleDetermine(str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); + Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); }); return loadTemplates(templatePaths); } From 0aaa4491648938cb4741205377cbbd8e27634772 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:13:39 +0100 Subject: [PATCH 16/34] Initiative dans RdDCombatManager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fonction _patch_initiative remplacée par surcharge de la méthode Combat.rollInitiative --- module/actor-sheet.js | 7 +- module/rdd-combat.js | 308 +++++++++++++++++++++++++++++++++++++--- module/rdd-main.js | 78 +--------- module/rdd-token-hud.js | 9 +- module/rdd-utility.js | 237 ++----------------------------- 5 files changed, 311 insertions(+), 328 deletions(-) diff --git a/module/actor-sheet.js b/module/actor-sheet.js index b83b7492..19837d4e 100644 --- a/module/actor-sheet.js +++ b/module/actor-sheet.js @@ -9,6 +9,7 @@ import { RdDItemArme } from "./item-arme.js"; import { RdDItemCompetence } from "./item-competence.js"; import { RdDBonus } from "./rdd-bonus.js"; import { Misc } from "./misc.js"; +import { RdDCombatManager } from "./rdd-combat.js"; /* -------------------------------------------- */ export class RdDActorSheet extends ActorSheet { @@ -95,12 +96,12 @@ export class RdDActorSheet extends ActorSheet { // To avoid armour and so on... data.data.combat = duplicate(RdDUtility.checkNull(data.itemsByType['arme'])); - data.data.combat = RdDUtility._finalizeArmeList(data.data.combat, data.itemsByType.competence, data.data.carac); + data.data.combat = RdDCombatManager.finalizeArmeList(data.data.combat, data.itemsByType.competence, data.data.carac); data.esquive = { name: "Esquive", niveau: data.competenceByCategory?.melee.find(it => it.name == 'Esquive')?.data.niveau ?? -6}; let corpsACorps = data.competenceByCategory?.melee.find(it => it.name == 'Corps à corps'); if (corpsACorps) { - let cc_init = RdDUtility.calculInitiative(corpsACorps.data.niveau, data.data.carac['melee'].value); + let cc_init = RdDCombatManager.calculInitiative(corpsACorps.data.niveau, data.data.carac['melee'].value); data.data.combat.push(RdDItemArme.mainsNues({ niveau: corpsACorps.data.niveau, initiative: cc_init })); } this.armesList = duplicate(data.data.combat); @@ -357,7 +358,7 @@ export class RdDActorSheet extends ActorSheet { if (combatant) { let armeName = event.currentTarget.attributes['data-arme-name'].value; let arme = this.armesList.find(a => a.name == armeName); - RdDUtility.rollInitiativeCompetence(combatant._id, arme); + RdDCombatManager.rollInitiativeCompetence(combatant._id, arme); } else { ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat."); } diff --git a/module/rdd-combat.js b/module/rdd-combat.js index dcf6e3ea..9cff8723 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -10,19 +10,26 @@ import { RdDRollTables } from "./rdd-rolltables.js"; import { ReglesOptionelles } from "./regles-optionelles.js"; /* -------------------------------------------- */ -export class RdDCombatManager extends Combat { +export class RdDCombatManager extends Combat { + + static init() { + /* -------------------------------------------- */ + Hooks.on("getCombatTrackerEntryContext", (html, options) => { + RdDCombatManager.pushInitiativeOptions(html, options); + }); + } /* -------------------------------------------- */ cleanItemUse() { - for(let turn of this.turns) { + for (let turn of this.turns) { turn.actor.resetItemUse() } } - + /* -------------------------------------------- */ - cleanSonne( ) { + cleanSonne() { for (let combatant of this.data.combatants) { - combatant.actor.verifierSonneRound( this.current.round ); + combatant.actor.verifierSonneRound(this.current.round); } } @@ -33,6 +40,266 @@ export class RdDCombatManager extends Combat { this.cleanSonne(); return super.nextRound(); } + + /************************************************************************************/ + async rollInitiative(ids, formula = undefined, messageOptions = {}) { + console.log(`${game.data.system.data.title} | Combat.rollInitiative()`, ids, formula, messageOptions); + // Structure input data + ids = typeof ids === "string" ? [ids] : ids; + const currentId = this.combatant._id; + // calculate initiative + for (let cId = 0; cId < ids.length; cId++) { + const c = this.getCombatant(ids[cId]); + //if (!c) return results; + + let rollFormula = formula; // Init per default + if (!rollFormula) { + let armeCombat, competence; + if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') { + for (const competenceItem of c.actor.data.items) { + if (competenceItem.data.iscombat) { + competence = duplicate(competenceItem); + } + } + rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)"; + } else { + for (const item of c.actor.data.items) { + if (item.type == "arme" && item.data.equipe) { + armeCombat = duplicate(item); + } + } + let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence; + competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName); + let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0; + rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, c.actor.data.data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)"; + } + } + //console.log("Combatat", c); + const roll = super._getInitiativeRoll(c, rollFormula); + if (roll.total <= 0) roll.total = 0.00; + console.log("Compute init for", rollFormula, roll.total); + await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total }); + + // Send a chat message + let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode"); + let messageData = mergeObject( + { + speaker: { + scene: canvas.scene._id, + actor: c.actor ? c.actor._id : null, + token: c.token._id, + alias: c.token.name, + sound: CONFIG.sounds.dice, + }, + flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo}) +
+ `, + }, + messageOptions + ); + roll.toMessage(messageData, { rollMode, create: true }); + + RdDCombatManager.processPremierRoundInit(); + } + return this; + }; + + /* -------------------------------------------- */ + static calculInitiative(niveau, caracValue, bonusEcaille = 0) { + let base = niveau + Math.floor(caracValue / 2); + base += bonusEcaille; + return "1d6" + (base >= 0 ? "+" : "") + base; + } + + /* -------------------------------------------- */ + /** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */ + static finalizeArmeList(armes, competences, carac) { + // Gestion des armes 1/2 mains + let armesEquipe = []; + for (const arme of armes) { + if (arme.data.equipe) { + armesEquipe.push(arme); + let comp = competences.find(c => c.name == arme.data.competence); + arme.data.initiative = RdDCombatManager.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value); + // Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence + if (arme.data.unemain && !arme.data.deuxmains) { + arme.data.mainInfo = "(1m)"; + } else if (!arme.data.unemain && arme.data.deuxmains) { + arme.data.mainInfo = "(2m)"; + } else if (arme.data.unemain && arme.data.deuxmains) { + arme.data.mainInfo = "(1m)"; + let arme2main = duplicate(arme); + arme2main.data.mainInfo = "(2m)"; + arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK + arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace ! + let comp = competences.find(c => c.name == arme2main.data.competence); + arme2main.data.niveau = comp.data.niveau; + arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value); + armesEquipe.push(arme2main); + } + } + } + return armesEquipe.sort((a, b) => { + const nameA = a.name + (a.data.mainInfo ?? ''); + const nameB = b.name + (b.data.mainInfo ?? ''); + if (nameA > nameB) return 1; + if (nameA < nameB) return -1; + return 0; + }); + } + + /* -------------------------------------------- */ + static buildListeActionsCombat(combatant) { + const actor = combatant.actor; // Easy access + let items = actor.data.items; + let actions = [] + if (actor.isCreature()) { + actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) + .map(competence => RdDItemCompetenceCreature.toArme(competence))); + } else { + // Recupération des items 'arme' + let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) + .map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */ + .concat(RdDItemArme.mainsNues()); + + let competences = items.filter(it => it.type == 'competence'); + actions = actions.concat(RdDCombatManager.finalizeArmeList(armes, competences, actor.data.data.carac)); + + actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } }); + } + + actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } }); + for (let index = 0; index < actions.length; index++) { + actions[index].index = index; + } + return actions; + } + + /* -------------------------------------------- */ + static processPremierRoundInit() { + // Check if we have the whole init ! + if (game.user.isGM && game.combat.current.round == 1) { + let initMissing = game.combat.data.combatants.find(it => !it.initiative); + if (!initMissing) { // Premier round ! + for (let combatant of game.combat.data.combatants) { + let arme = combatant.initiativeData?.arme; + //console.log("Parsed !!!", combatant, initDone, game.combat.current, arme); + if (arme && arme.type == "arme") { + for (let initData of premierRoundInit) { + if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) { + let msg = `

L'initiative de ${combatant.actor.name} a été modifiée !

+
+
+ Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}. +
` + ChatMessage.create({ content: msg }); + game.combat.setInitiative(combatant._id, initData.init); + } + } + } + } + } + } + } + + /* -------------------------------------------- */ + static incDecInit(combatantId, incDecValue) { + const combatant = game.combat.getCombatant(combatantId); + let initValue = combatant.initiative + incDecValue; + game.combat.setInitiative(combatantId, initValue); + } + + /* -------------------------------------------- */ + static pushInitiativeOptions(html, options) { + for (let i = 0; i < options.length; i++) { + let option = options[i]; + if (option.name == 'COMBAT.CombatantReroll') { // Replace ! + option.name = "Sélectionner l'initiative..."; + option.condition = true; + option.icon = ''; + option.callback = target => { + RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id')); + } + } + } + options = [ + { name: "Incrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } }, + { name: "Décrémenter initiative", condition: true, icon: '', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } } + ].concat(options); + } + /* -------------------------------------------- */ + static rollInitiativeCompetence(combatantId, arme) { + const combatant = game.combat.getCombatant(combatantId); + const actor = combatant.actor; + + let initInfo = ""; + let initOffset = 0; + let caracForInit = 0; + let compNiveau = 0; + let competence = { name: "Aucune" }; + if (actor.getSurprise() == "totale") { + initOffset = -1; // To force 0 + initInfo = "Surprise Totale" + } else if (actor.getSurprise() == "demi") { + initOffset = 0; + initInfo = "Demi Surprise" + } else if (arme.name == "Autre action") { + initOffset = 2; + initInfo = "Autre Action" + } else if (arme.name == "Draconic") { + initOffset = 7; + initInfo = "Draconic" + } else { + initOffset = 3; // Melée = 3.XX + competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence); + compNiveau = competence.data.niveau; + initInfo = arme.name + " / " + arme.data.competence; + + if (actor.data.type == 'creature' || actor.data.type == 'entite') { + caracForInit = competence.data.carac_value; + if (competence.data.categorie == "lancer") { + initOffset = 5; + } + } else { + caracForInit = actor.data.data.carac[competence.data.defaut_carac].value; + if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet + initOffset = 4; + } + if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet + initOffset = 5; + } + if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet + initOffset = 3; + } + } + } + let malus = actor.getEtatGeneral(); // Prise en compte état général + // Cas des créatures et entités vs personnages + let rollFormula = initOffset + "+ ( (" + RdDCombatManager.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)"; + // Garder la trace de l'arme/compétence utilisée pour l'iniative + combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0 + game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo }); + } + + /* -------------------------------------------- */ + static displayInitiativeMenu(html, combatantId) { + const combatant = game.combat.getCombatant(combatantId); + let armesList = RdDCombatManager.buildListeActionsCombat(combatant); + + // Build the relevant submenu + if (armesList) { + let menuItems = []; + for (let arme of armesList) { + menuItems.push({ + name: arme.data.competence, + icon: "", + callback: target => { RdDCombatManager.rollInitiativeCompetence(combatantId, arme) } + }); + } + new ContextMenu(html, ".directory-list", menuItems).render(); + } + } + } /* -------------------------------------------- */ @@ -385,8 +652,8 @@ export class RdDCombat { let rollData = this._prepareAttaque(competence, arme); console.log("RdDCombat.attaque >>>", rollData); - this.attacker.incItemUse( arme._id ); // Usage - this.attacker.verifierForceMin( arme ); + this.attacker.incItemUse(arme._id); // Usage + this.attacker.verifierForceMin(arme); const dialog = await RdDRoll.create(this.attacker, rollData, { @@ -491,7 +758,7 @@ export class RdDCombat { let esquiveUsage = 0; let esquive = this.defender.getCompetence("esquive"); if (esquive) { - esquiveUsage = this.defender.getItemUse( esquive._id); + esquiveUsage = this.defender.getItemUse(esquive._id); } const paramChatDefense = { @@ -551,8 +818,8 @@ export class RdDCombat { _filterArmesParade(defender, competence) { let items = defender.data.items; items = items.filter(item => RdDItemArme.isArmeUtilisable(item) || RdDItemCompetenceCreature.isCompetenceParade(item)); - for( let item of items) { - item.data.nbUsage = defender.getItemUse( item._id); // Ajout du # d'utilisation ce round + for (let item of items) { + item.data.nbUsage = defender.getItemUse(item._id); // Ajout du # d'utilisation ce round } switch (competence.data.categorie) { case 'tir': @@ -572,9 +839,8 @@ export class RdDCombat { RdDCombat._storeAttaque(this.attackerId, attackerRoll); - // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum ChatMessage.create({ - whisper: ChatMessage.getWhisperRecipients(this.attacker.name), + whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { attackerId: this.attackerId, attacker: this.attacker, @@ -617,7 +883,7 @@ export class RdDCombat { let arme = this.defender.getArmeParade(armeParadeId); console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme); - this.defender.incItemUse( armeParadeId ); // Usage + this.defender.incItemUse(armeParadeId); // Usage let rollData = this._prepareParade(attackerRoll, arme); @@ -725,7 +991,7 @@ export class RdDCombat { } console.log("RdDCombat.esquive >>>", attackerRoll, esquive); let rollData = this._prepareEsquive(attackerRoll, esquive); - this.defender.incItemUse( esquive._id ); // Usage + this.defender.incItemUse(esquive._id); // Usage const dialog = await RdDRoll.create(this.defender, rollData, { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' }, { @@ -804,10 +1070,10 @@ export class RdDCombat { const dmg = attackerRoll.dmg.dmgArme + attackerRoll.dmg.dmgActor; let arme = defenderRoll.arme; let msg = ""; - if ( arme.data.magique ) { + if (arme.data.magique) { defenderRoll.show.deteriorationArme = 'resiste'; // Par défaut if (arme.data.resistance_magique == undefined) arme.data.resistance_magique = 0; // Quick fix - if ( dmg > arme.data.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274) + if (dmg > arme.data.resistance_magique) { // Jet uniquement si dommages supérieur à résistance magique (cf. 274) let resistance = Misc.toInt(arme.data.resistance); // Jet de résistance de l'arme de parade (p.132) let resistRoll = await RdDResolutionTable.rollData({ @@ -815,14 +1081,14 @@ export class RdDCombat { finalLevel: - dmg, showDice: false }); - if ( !resistRoll.rolled.isSuccess) { - let perteResistance = ( dmg - arme.data.resistance_magique) + if (!resistRoll.rolled.isSuccess) { + let perteResistance = (dmg - arme.data.resistance_magique) resistance -= perteResistance; - defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise': 'perte'; + defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte'; defenderRoll.show.perteResistance = perteResistance; this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance }); } - } + } } else { let resistance = Misc.toInt(arme.data.resistance); // Jet de résistance de l'arme de parade (p.132) @@ -835,7 +1101,7 @@ export class RdDCombat { defenderRoll.show.deteriorationArme = 'resiste'; } else { resistance -= dmg; - defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise': 'perte'; + defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte'; defenderRoll.show.perteResistance = dmg; this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance }); } diff --git a/module/rdd-main.js b/module/rdd-main.js index 328e9b1a..2b7d2e43 100644 --- a/module/rdd-main.js +++ b/module/rdd-main.js @@ -34,77 +34,7 @@ import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; /* Foundry VTT Initialization */ /* -------------------------------------------- */ -/************************************************************************************/ -const _patch_initiative = () => { - Combat.prototype.rollInitiative = async function ( - ids, - formula = undefined, - messageOptions = {} - ) { - console.log( - `${game.data.system.data.title} | Combat.rollInitiative()`, - ids, - formula, - messageOptions - ); - // Structure input data - ids = typeof ids === "string" ? [ids] : ids; - const currentId = this.combatant._id; - // calculate initiative - for (let cId = 0; cId < ids.length; cId++) { - const c = this.getCombatant(ids[cId]); - //if (!c) return results; - let rollFormula = formula; // Init per default - if (!rollFormula) { - let armeCombat, competence; - if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') { - for (const competenceItem of c.actor.data.items) { - if (competenceItem.data.iscombat) { - competence = duplicate(competenceItem); - } - } - rollFormula = "2+( ("+RdDUtility.calculInitiative(competence.data.niveau, competence.data.carac_value)+")/100)"; - } else { - for (const item of c.actor.data.items) { - if (item.type == "arme" && item.data.equipe) { - armeCombat = duplicate(item); - } - } - let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence; - competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName); - let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0; - rollFormula = "2+( ("+RdDUtility.calculInitiative(competence.data.niveau, c.actor.data.data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)"; - } - } - //console.log("Combatat", c); - const roll = this._getInitiativeRoll(c, rollFormula); - if (roll.total <= 0) roll.total = 0.00; - console.log("Compute init for", rollFormula, roll.total); - await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total }); - - // Send a chat message - let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode"); - let messageData = mergeObject( - { - speaker: { - scene: canvas.scene._id, - actor: c.actor ? c.actor._id : null, - token: c.token._id, - alias: c.token.name, - sound: CONFIG.sounds.dice, - }, - flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})`, - }, - messageOptions - ); - roll.toMessage(messageData, { rollMode, create: true }); - - RdDUtility.processPremierRoundInit( ); - } - return this; - }; -} /************************************************************************************/ Hooks.once("init", async function () { @@ -222,12 +152,10 @@ Hooks.once("init", async function () { Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true }); CONFIG.Combat.entityClass = RdDCombatManager; - // Patch the initiative formula - _patch_initiative(); - // préparation des différents modules RdDCommands.init(); RdDCombat.init(); + RdDCombatManager.init(), RdDTokenHud.init(); RdDActor.init(); RddCompendiumOrganiser.init(); @@ -296,10 +224,6 @@ Hooks.on("chatMessage", (html, content, msg) => { return true; }); -/* -------------------------------------------- */ -Hooks.on("getCombatTrackerEntryContext", (html, options) => { - RdDUtility.pushInitiativeOptions(html, options); -}); /* -------------------------------------------- */ Hooks.on("renderChatMessage", async (app, html, msg) => { diff --git a/module/rdd-token-hud.js b/module/rdd-token-hud.js index 0f9abcb0..27c96c46 100644 --- a/module/rdd-token-hud.js +++ b/module/rdd-token-hud.js @@ -1,5 +1,6 @@ /* -------------------------------------------- */ import { HtmlUtility } from "./html-utility.js"; +import { RdDCombatManager } from "./rdd-combat.js"; import { RdDUtility } from "./rdd-utility.js"; /* -------------------------------------------- */ @@ -26,7 +27,7 @@ export class RdDTokenHud { let combatant = game.combat.data.combatants.find(c => c.tokenId == token.data._id); app.hasExtension = true; - let armesList = RdDUtility.buildListeActionsCombat(combatant) ; + let armesList = RdDCombatManager.buildListeActionsCombat(combatant) ; const hudData = { combatant: combatant, armes: armesList, commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01}, { name: 'Initiative -1',command: 'dec', value: -0.01}] }; @@ -38,11 +39,11 @@ export class RdDTokenHud { if ( !initCommand ) { let armeIndex = event.currentTarget.attributes['data-arme-id'].value; let arme = armesList[armeIndex]; - RdDUtility.rollInitiativeCompetence(combatantId, arme); + RdDCombatManager.rollInitiativeCompetence(combatantId, arme); } else if (initCommand == 'inc') { - RdDUtility.incDecInit( combatantId, 0.01 ); + RdDCombatManager.incDecInit( combatantId, 0.01 ); } else if ( initCommand == 'dec') { - RdDUtility.incDecInit( combatantId, -0.01 ); + RdDCombatManager.incDecInit( combatantId, -0.01 ); } }); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index b649373a..0c579375 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -2,7 +2,7 @@ import { RdDRollTables } from "./rdd-rolltables.js"; import { ChatUtility } from "./chat-utility.js"; -import { RdDCombat } from "./rdd-combat.js"; +import { RdDCombat, RdDCombatManager } from "./rdd-combat.js"; import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItemArme } from "./item-arme.js"; @@ -24,18 +24,18 @@ const categorieCompetences = { /* -------------------------------------------- */ const limitesArchetypes = [ - { "niveau": 0, "nombreMax": 100, "nombre":0}, - { "niveau": 1, "nombreMax": 10, "nombre":0}, - { "niveau": 2, "nombreMax": 9, "nombre":0}, - { "niveau": 3, "nombreMax": 8, "nombre":0}, - { "niveau": 4, "nombreMax": 7, "nombre":0}, - { "niveau": 5, "nombreMax": 6, "nombre":0}, - { "niveau": 6, "nombreMax": 5, "nombre":0}, - { "niveau": 7, "nombreMax": 4, "nombre":0}, - { "niveau": 8, "nombreMax": 3, "nombre":0}, - { "niveau": 9, "nombreMax": 2, "nombre":0}, - { "niveau": 10, "nombreMax": 1, "nombre":0}, - { "niveau": 11, "nombreMax": 1, "nombre":0} + { "niveau": 0, "nombreMax": 100, "nombre": 0 }, + { "niveau": 1, "nombreMax": 10, "nombre": 0 }, + { "niveau": 2, "nombreMax": 9, "nombre": 0 }, + { "niveau": 3, "nombreMax": 8, "nombre": 0 }, + { "niveau": 4, "nombreMax": 7, "nombre": 0 }, + { "niveau": 5, "nombreMax": 6, "nombre": 0 }, + { "niveau": 6, "nombreMax": 5, "nombre": 0 }, + { "niveau": 7, "nombreMax": 4, "nombre": 0 }, + { "niveau": 8, "nombreMax": 3, "nombre": 0 }, + { "niveau": 9, "nombreMax": 2, "nombre": 0 }, + { "niveau": 10, "nombreMax": 1, "nombre": 0 }, + { "niveau": 11, "nombreMax": 1, "nombre": 0 } ]; /* -------------------------------------------- */ @@ -281,7 +281,7 @@ export class RdDUtility { } /* -------------------------------------------- */ - static getLimitesArchetypes( ) { + static getLimitesArchetypes() { return duplicate(limitesArchetypes); } @@ -460,50 +460,6 @@ export class RdDUtility { return tableCaracDerivee[targetValue]?.xp ?? 200; } - /* -------------------------------------------- */ - /** Retourne une liste triée d'armes avec le split arme1 main / arme 2 main */ - static _finalizeArmeList(armes, competences, carac) { - // Gestion des armes 1/2 mains - let armesEquipe = []; - for (const arme of armes) { - if (arme.data.equipe) { - armesEquipe.push(arme); - let comp = competences.find(c => c.name == arme.data.competence); - arme.data.initiative = RdDUtility.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value); - // Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence - if (arme.data.unemain && !arme.data.deuxmains) { - arme.data.mainInfo = "(1m)"; - } else if (!arme.data.unemain && arme.data.deuxmains) { - arme.data.mainInfo = "(2m)"; - } else if (arme.data.unemain && arme.data.deuxmains) { - arme.data.mainInfo = "(1m)"; - let arme2main = duplicate(arme); - arme2main.data.mainInfo = "(2m)"; - arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK - arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace ! - let comp = competences.find(c => c.name == arme2main.data.competence); - arme2main.data.niveau = comp.data.niveau; - arme2main.data.initiative = RdDUtility.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value); - armesEquipe.push(arme2main); - } - } - } - return armesEquipe.sort((a, b) => { - const nameA = a.name + (a.data.mainInfo ?? ''); - const nameB = b.name + (b.data.mainInfo ?? ''); - if (nameA > nameB) return 1; - if (nameA < nameB) return -1; - return 0; - }); - } - - /* -------------------------------------------- */ - static calculInitiative(niveau, caracValue, bonusEcaille = 0) { - let base = niveau + Math.floor(caracValue / 2); - base += bonusEcaille; - return "1d6" + (base >= 0 ? "+" : "") + base; - } - /* -------------------------------------------- */ static computeCarac(data) { data.carac.force.value = Math.min(data.carac.force.value, parseInt(data.carac.taille.value) + 4); @@ -711,173 +667,8 @@ export class RdDUtility { } } - /* -------------------------------------------- */ - static processPremierRoundInit() { - // Check if we have the whole init ! - if (game.user.isGM) { - let initDone = true; - for (let combatant of game.combat.data.combatants) { - if (!combatant.initiative) initDone = false; - } - if (initDone && game.combat.current.round == 1) { // Premier round ! - for (let combatant of game.combat.data.combatants) { - let arme = combatant.initiativeData.arme; - //console.log("Parsed !!!", combatant, initDone, game.combat.current, arme); - if (arme && arme.type == "arme") { - for (let initData of premierRoundInit) { - if (arme.data.initpremierround.toLowerCase().includes(initData.pattern)) { - let msg = `

L'initiative de ${combatant.actor.name} a été modifiée !

-
-
- Etant donné son ${arme.name}, son initative pour ce premier round est désormais de ${initData.init}. -
` - ChatMessage.create({ content: msg }); - game.combat.setInitiative(combatant._id, initData.init); - } - } - } - } - } - } - } - /* -------------------------------------------- */ - static rollInitiativeCompetence(combatantId, arme) { - const combatant = game.combat.getCombatant(combatantId); - const actor = combatant.actor; - let initInfo = ""; - let initOffset = 0; - let caracForInit = 0; - let compNiveau = 0; - let competence = { name: "Aucune"}; - if (actor.getSurprise() == "totale") { - initOffset = -1; // To force 0 - initInfo = "Surprise Totale" - } else if (actor.getSurprise() == "demi") { - initOffset = 0; - initInfo = "Demi Surprise" - } else if (arme.name == "Autre action") { - initOffset = 2; - initInfo = "Autre Action" - } else if (arme.name == "Draconic") { - initOffset = 7; - initInfo = "Draconic" - } else { - initOffset = 3; // Melée = 3.XX - competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence); - compNiveau = competence.data.niveau; - initInfo = arme.name + " / " + arme.data.competence; - - if (actor.data.type == 'creature' || actor.data.type == 'entite') { - caracForInit = competence.data.carac_value; - if (competence.data.categorie == "lancer") { - initOffset = 5; - } - } else { - caracForInit = actor.data.data.carac[competence.data.defaut_carac].value; - if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet - initOffset = 4; - } - if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet - initOffset = 5; - } - if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet - initOffset = 3; - } - } - } - let malus = actor.getEtatGeneral(); // Prise en compte état général - // Cas des créatures et entités vs personnages - let rollFormula = initOffset + "+ ( (" + RdDUtility.calculInitiative(compNiveau, caracForInit) + " + " + malus + ") /100)"; - // Garder la trace de l'arme/compétence utilisée pour l'iniative - combatant.initiativeData = { arme: arme } // pour reclasser l'init au round 0 - game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo}); - } - - /* -------------------------------------------- */ - static buildListeActionsCombat(combatant) { - const actor = combatant.actor; // Easy access - let items = actor.data.items; - let actions = [] - if (actor.isCreature()) { - actions = actions.concat(items.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) - .map(competence => RdDItemCompetenceCreature.toArme(competence))); - } else { - // Recupération des items 'arme' - let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it)) - .map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */ - .concat(RdDItemArme.mainsNues()); - - let competences = items.filter(it => it.type == 'competence'); - actions = actions.concat(this._finalizeArmeList(armes, competences, actor.data.data.carac)); - - actions.push({ name: "Draconic", data: { initOnly: true, competence: "Draconic" } }); - } - - actions.push({ name: "Autre action", data: { initOnly: true, competence: "Autre action" } }); - for (let index = 0; index < actions.length; index++) { - actions[index].index = index; - } - return actions; - } - - /* -------------------------------------------- */ - static displayInitiativeMenu(html, combatantId) { - const combatant = game.combat.getCombatant(combatantId); - let armesList = this.buildListeActionsCombat(combatant); - - // Build the relevant submenu - if (armesList) { - let menuItems = []; - for (let arme of armesList) { - menuItems.push({ - name: arme.data.competence, - icon: "", - callback: target => { RdDUtility.rollInitiativeCompetence(combatantId, arme) } - }); - } - new ContextMenu(html, ".directory-list", menuItems).render(); - } - } - - /* -------------------------------------------- */ - static incDecInit(combatantId, incDecValue) { - const combatant = game.combat.getCombatant(combatantId); - let initValue = combatant.initiative + incDecValue; - game.combat.setInitiative(combatantId, initValue); - } - - /* -------------------------------------------- */ - static pushInitiativeOptions(html, options) { - for (let i = 0; i < options.length; i++) { - let option = options[i]; - if (option.name == 'COMBAT.CombatantReroll') { // Replace ! - option.name = "Sélectionner l'initiative..."; - option.condition = true; - option.icon = ''; - option.callback = target => { - RdDUtility.displayInitiativeMenu(html, target.data('combatant-id')); - } - } - } - options.push({ - name: "Incrémenter initiative", - condition: true, - icon: '', - callback: target => { - RdDUtility.incDecInit(target.data('combatant-id'), +0.01); - } - }); - options.push({ - name: "Décrémenter initiative", - condition: true, - icon: '', - callback: target => { - RdDUtility.incDecInit(target.data('combatant-id'), -0.01); - } - }); - } /* -------------------------------------------- */ static async chatListeners(html) { From c5f4a0a14d214cce61f08b8467f08072ac978139 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Thu, 25 Feb 2021 02:14:47 +0100 Subject: [PATCH 17/34] =?UTF-8?q?Init=20des=20armes=20=C3=A0=20distance=20?= =?UTF-8?q?sans=20r=C3=A9sistance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workaround: si une arme a une portée, elle peut être utilisée. --- module/item-arme.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/item-arme.js b/module/item-arme.js index 048543f0..68e3cafb 100644 --- a/module/item-arme.js +++ b/module/item-arme.js @@ -145,7 +145,7 @@ export class RdDItemArme extends Item { } static isArmeUtilisable(item) { - return item.type == 'arme' && item.data.resistance > 0; + return item.type == 'arme' && (item.data.resistance > 0 || item.data.portee_courte>0); } static mainsNues(actorData={}) { From 741d724d93ce73c92f81cbcfbd8eaa12576ad1e8 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Thu, 25 Feb 2021 08:48:31 +0100 Subject: [PATCH 18/34] Fix increment d'utilisation --- module/actor.js | 8 ++++++++ module/rdd-combat.js | 1 + 2 files changed, 9 insertions(+) diff --git a/module/actor.js b/module/actor.js index 0abf2717..e318a0db 100644 --- a/module/actor.js +++ b/module/actor.js @@ -2779,6 +2779,14 @@ export class RdDActor extends Actor { await this.setFlag('foundryvtt-reve-de-dragon', 'itemUse', {} ); } + /* -------------------------------------------- */ + async decItemUse( itemId ) { + let itemUse = duplicate(this.getFlag('foundryvtt-reve-de-dragon', 'itemUse') ?? {}); + itemUse[itemId] = (itemUse[itemId] ?? 0) - 1; + await this.setFlag( 'foundryvtt-reve-de-dragon', 'itemUse', itemUse); + console.log("ITEM USE DEC", itemUse); + } + /* -------------------------------------------- */ async incItemUse( itemId ) { let itemUse = duplicate(this.getFlag('foundryvtt-reve-de-dragon', 'itemUse') ?? {}); diff --git a/module/rdd-combat.js b/module/rdd-combat.js index f78bfc02..bc641c0a 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -435,6 +435,7 @@ export class RdDCombat { /* -------------------------------------------- */ async _onAttaqueParticuliere(rollData) { RdDCombat._storeAttaque(this.attackerId, rollData); + this.attacker.decItemUse( rollData.arme._id ); // Usage décrémenté sur particulière // Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum const isMeleeDiffNegative = rollData.selectedCarac.label == "Mêlée" && rollData.diffLibre < 0; From 28fde31a54ffb0d9088fb915f8b9c81ce211c6b7 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 26 Feb 2021 00:59:12 +0100 Subject: [PATCH 19/34] Fix typos --- module/actor.js | 2 +- templates/chat-resultat-recettecuisine.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/module/actor.js b/module/actor.js index e318a0db..2ecae44a 100644 --- a/module/actor.js +++ b/module/actor.js @@ -481,7 +481,7 @@ export class RdDActor extends Actor { async dormir(heures = 1) { let message = { whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), - content: this.name + ": Vous dormez " + heures + (heures > 1 ? " heures. " : "heure. ") + content: `${this.name}: Vous dormez ${heures == 1 ? 'une': heures} heure${heures == 1 ? '': 's'}.` }; await this.recupereEndurance(message); for (let i = 0; i < heures; i++) { diff --git a/templates/chat-resultat-recettecuisine.html b/templates/chat-resultat-recettecuisine.html index 086b6e81..c1bc57df 100644 --- a/templates/chat-resultat-recettecuisine.html +++ b/templates/chat-resultat-recettecuisine.html @@ -6,7 +6,7 @@
{{#if rolled.isSuccess}} - {{alias}} réussit sa recette, avec un plat de {{qualiteFinale}} pour {{oeuvre.data.sust}} Points de Sustentation. + {{alias}} réussit sa recette, avec un plat de qualité {{qualiteFinale}} pour {{oeuvre.data.sust}} Points de Sustentation. {{else}} {{alias}} fait un piètre cuisinier(e), et obtient {{#if (lt qualiteFinale 0)}}un plat à l'exotisme certain{{else}}un plat de qualité {{qualiteFinale}}{{/if}}. Selon la décision du MJ, le plat peut fournir {{oeuvre.data.sust}} Points de Sustentation From 622aeda279f01a4736e0a0977a0341b8f1602575 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 26 Feb 2021 01:15:08 +0100 Subject: [PATCH 20/34] =?UTF-8?q?Fix=20t=C3=AAte=20pr=C3=A9sent=20des=20ci?= =?UTF-8?q?t=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit doublon + typo empêchait d'automatiser la création des présents fix tables des têtes inversée et icône dans les tables --- module/rdd-rolltables.js | 4 ++-- packs/tables-diverses.db | 2 +- packs/tetes-de-dragon-pour-haut-revants.db | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js index 61b1fb19..957c130a 100644 --- a/module/rdd-rolltables.js +++ b/module/rdd-rolltables.js @@ -57,12 +57,12 @@ export class RdDRollTables { } /* -------------------------------------------- */ - static async getTete(toChat = false) { + static async getTeteHR(toChat = false) { return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat); } /* -------------------------------------------- */ - static async getTeteHR(toChat = false) { + static async getTete(toChat = false) { return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour tous personnages", toChat); } diff --git a/packs/tables-diverses.db b/packs/tables-diverses.db index 306a2b6a..b16a39d0 100644 --- a/packs/tables-diverses.db +++ b/packs/tables-diverses.db @@ -7,6 +7,6 @@ {"_id":"nbH4v630P7ARaAHk","name":"Idées fixes","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"img":"icons/svg/d20-grey.svg","description":"Les idées fixes prennent effet immédiatement et durent jusqu’à l’extrême fin de l’heure du Château Dormant du lendemain. Si passé ce délai, l’occasion de les manifester ne s’est pas présentée, la queue prend fin néanmoins. Si elles entrent en contradiction avec une autre queue de Dragon, retirer. Les idées fixes peuvent être refoulées à tout moment au prix de 1 point de refoulement.","results":[{"_id":"xX6XGI6ujPDSbbob","flags":{},"type":2,"text":"Idée fixe : Ne s’exprimer que par des cris d’animaux (meuh ! coin-coin ! etc.)","img":"exprimer_cris.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"YCHBbRLiMzTH7IBj","weight":1,"range":[1,1],"drawn":false},{"_id":"gYN6fcQISs2H7kAn","flags":{},"type":2,"text":"Idée fixe : Garder les yeux bandés","img":"garder_yeux.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"E902EEYZHg3zFKq6","weight":1,"range":[2,2],"drawn":false},{"_id":"QIHOFfluPnEJFKHD","flags":{},"type":2,"text":"Idée fixe : Ne dire que «non» ou négation analogue","img":"dire_non.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"gMmqdJ9I7Mt8Tg3f","weight":1,"range":[3,3],"drawn":false},{"_id":"P0eaJjtQQfpNIL9I","flags":{},"type":2,"text":"Idée fixe : Garder sur soi 3d6 kilos de cailloux","img":"garder_cailloux.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"F8G3rdU1nfJzYwYR","weight":1,"range":[4,4],"drawn":false},{"_id":"PENvfmIpKFWee8rF","flags":{},"type":2,"text":"Idée fixe : Traîner son épée en laisse (ou sa meilleure arme)","img":"trainer_laisse.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"2j1q9e07ZLlIQDYl","weight":1,"range":[5,5],"drawn":false},{"_id":"6xT8v1ScJSZEente","flags":{},"type":2,"text":"Idée fixe : Garder une main sur la tête","img":"garder_main.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"iPYPgxL2uUnphStc","weight":1,"range":[6,6],"drawn":false},{"_id":"0CO9RJPygGdJT9nB","flags":{},"type":2,"text":"Idée fixe : Avoir le visage noirci à la cendre","img":"avoir_visage.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"6G0lF06jSryTduAt","weight":1,"range":[7,7],"drawn":false},{"_id":"XeCtzSCuEEm9q8TI","flags":{},"type":2,"text":"Idée fixe : Cracher dans toute nourriture ou boisson aperçue","img":"cracher_nourriture.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"22EQLBJfHVYs96iC","weight":1,"range":[8,8],"drawn":false},{"_id":"Sh5KRDvM7iXad6rK","flags":{},"type":2,"text":"Idée fixe : Anorexie. Ne rien avaler, ni solide, ni liquide, pas même une potion","img":"anorexie.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"0uc2pMIGL03Hq2Hn","weight":1,"range":[9,9],"drawn":false},{"_id":"6Q3XKURzip61EXK2","flags":{},"type":2,"text":"Idée fixe : Aller tout nu, sans porter le moindre paquet ni objet","img":"aller_nu.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"I0CtQ05xFW6ghcdP","weight":1,"range":[10,10],"drawn":false},{"_id":"7B8joMjIuhNxip6N","flags":{},"type":2,"text":"Idée fixe : Vider sur sa tête toute fiole ou flacon aperçu","img":"verser_flacon.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"afGp9CewfyJKecEE","weight":1,"range":[11,11],"drawn":false},{"_id":"Febiy30xqiNo7OqV","flags":{},"type":2,"text":"Idée fixe : Appeler les hommes «madame» et les femmes «messire»","img":"appeler_hommes_femmes.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"j2xIrFWYqhDM4TcN","weight":1,"range":[12,12],"drawn":false},{"_id":"Aa72g0fFdq2qBmCn","flags":{},"type":2,"text":"Idée fixe : Ne marcher qu’à quatre pattes","img":"marcher_quatre_pattes.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"7TKsit2Mv9mWGq3C","weight":1,"range":[13,13],"drawn":false},{"_id":"UYhT76xYv8OGXcMZ","flags":{},"type":2,"text":"Idée fixe : Boulimie. Manger au moins un point de sust. par heure","img":"boulimie.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"JcTX8qMS0z8bmdVt","weight":1,"range":[14,14],"drawn":false},{"_id":"fOnQmiXMPXrK3K6P","flags":{},"type":2,"text":"Idée fixe : Refuser de se déplacer autrement que porté","img":"refuser_deplacer.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"hghw6Cldrad1CIiJ","weight":1,"range":[15,15],"drawn":false},{"_id":"KKGlZXouFfIMKQma","flags":{},"type":2,"text":"Idée fixe : Ne pas franchir de porte. (On peut franchir une fenêtre)","img":"pas-franchir.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"UUTbsktTcxsIe5L5","weight":1,"range":[16,16],"drawn":false},{"_id":"JjWHUsMLhLuTYB2q","flags":{},"type":2,"text":"Idée fixe : Faire le mort","img":"faire_mort.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"xa4t9Lbt6uLEjap6","weight":1,"range":[17,17],"drawn":false},{"_id":"r7Dw8GD1ceypY0iV","flags":{},"type":2,"text":"Idée fixe : Éteindre tout feu rencontré (feu de camp, torche, lanterne, etc.)","img":"eteindre_feu.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"2Rtm78bMKPy8eG4q","weight":1,"range":[18,18],"drawn":false},{"_id":"i0AW1Ir1V7y2ZmEh","flags":{},"type":2,"text":"Idée fixe : Refuser de se délester du moindre objet, ni donner ni prêter","img":"refuser_delester.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"VChJbtGFtWoiFNky","weight":1,"range":[19,19],"drawn":false},{"_id":"DQBzVXbJKn9zsXUI","flags":{},"type":2,"text":"Idée fixe : Refuser de monter dans les TMR","img":"refuser_tmr.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"NpTDqICR7ZuToQrg","weight":1,"range":[20,20],"drawn":false}],"formula":"1d20","replacement":false,"displayRoll":true} {"name":"Maladresse armé","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"description":"","results":[{"_id":"R18ITzDLLuGiaqXM","flags":{},"type":0,"text":"Assomé net : Endurance tombe à 0 et -1 pt de vie.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[2,2],"drawn":false},{"_id":"sfWXLz4QIkPLNJmg","flags":{},"type":0,"text":"Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à -1d6 ou être en demi-surprise jusqu’à la fin du round suivant.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[3,3],"drawn":false},{"_id":"APqyDePFzBaROB6i","flags":{},"type":0,"text":"Chute : Encaissement à -1d6 sur la table des Coups non mortels.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[4,4],"drawn":false},{"_id":"8yErM3dW4F2MBFqe","flags":{},"type":0,"text":"Désarmé","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[5,5],"drawn":false},{"_id":"8dh7zUXAq8ehNag7","flags":{},"type":0,"text":"Arme choquée : L’arme utilisée joue un jet de Résistance à -2d6 et perd ce nombre de points de résistance en cas d’échec.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[6,7],"drawn":false},{"_id":"OskepgYnU7pok5jv","flags":{},"type":0,"text":"Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise jusqu’à la fin du round suivant.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[8,9],"drawn":false},{"_id":"GOYmqZj1Lnc0cKO9","flags":{},"type":0,"text":"Faux mouvement : Perte de 2d6 points d’endurance.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[10,12],"drawn":false},{"_id":"NOrmphYuLWRKZxai","flags":{},"type":0,"text":"Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise jusqu’à la fin du round suivant.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[13,14],"drawn":false},{"_id":"ef8tfK8JzdX1OKzf","flags":{},"type":0,"text":"Arme choquée : L’arme utilisée joue un jet de Résistance à -2d6 et perd ce nombre de points de résistance en cas d’échec.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[15,16],"drawn":false},{"_id":"9V3Gj9PEYrEY7OCc","flags":{},"type":0,"text":"Désarmé","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[17,17],"drawn":false},{"_id":"c61AFRaP9poCmr9B","flags":{},"type":0,"text":"Chute : Encaissement à -1d6 sur la table des Coups non mortels.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[18,18],"drawn":false},{"_id":"8tS1rSwYvd0cS9o4","flags":{},"type":0,"text":"Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à -1d6 ou être en demi-surprise jusqu’à la fin du round suivant.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[19,19],"drawn":false},{"_id":"ma6DRHIjkgpOVc55","flags":{},"type":0,"text":"Assommé net : Endurance tombe à 0 et -1 pt de vie.","img":"icons/svg/d20-black.svg","resultId":"","weight":1,"range":[20,20],"drawn":false}],"formula":"2d10","replacement":false,"displayRoll":true,"_id":"pXYVWRlCftWdwsBP"} {"_id":"sVWhyr4wPnieuPP8","name":"Désirs lancinants","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"img":"icons/svg/d20-grey.svg","description":"Les désirs lancinants durent jusqu’à ce qu’ils soient satisfaits ou refoulés. Tant que satisfaction n’est pas obtenue, aucun point d’expérience ne peut plus être gagné par l’exercice en cas de particulière et d’ajustement final négatif. Les points d’expérience dus au stress ne sont pas affectés. Les désirs lancinants peuvent être refoulés à tout moment au prix de 1 point de refoulement.","results":[{"_id":"m9BMFVAByyICiMkp","flags":{},"type":2,"text":"Désir lancinant : Danser nu sous la pluie","img":"danser_pluie.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"F6qL4d4g3qjh045R","weight":1,"range":[1,1],"drawn":false},{"_id":"EJYCgPl9BCW92LSM","flags":{},"type":2,"text":"Désir lancinant : Traire une vache","img":"traire_vache.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"QHUOwjMR6AvepGPm","weight":1,"range":[2,2],"drawn":false},{"_id":"fRgwd7VconbmXrWQ","flags":{},"type":2,"text":"Désir lancinant : Manger du poisson","img":"manger_poisson.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"SY0SsWtZdxSodMcl","weight":1,"range":[3,3],"drawn":false},{"_id":"NEWpP5vwM5KQviDD","flags":{},"type":2,"text":"Désir lancinant : Manger des champignons","img":"manger_champignons.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"gadh6aI5iCM82qpP","weight":1,"range":[4,4],"drawn":false},{"_id":"8pMq7q3evaj9fIst","flags":{},"type":2,"text":"Désir lancinant : Se soûler (minimum pas frais)","img":"se_souler.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"jShpKV8mVcqWmYvp","weight":1,"range":[5,5],"drawn":false},{"_id":"qFOyIPVjQkVjrHFI","flags":{},"type":2,"text":"Désir lancinant : Gagner de l’argent (minimum 10 deniers)","img":"gagner_argent.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"3BcC8lSsP5WIyva7","weight":1,"range":[6,6],"drawn":false},{"_id":"RrOMys2WRxUrRYev","flags":{},"type":2,"text":"Désir lancinant : Faire des bulles de savon","img":"bulles_savon.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"df5oN8Ub3dWTVxNj","weight":1,"range":[7,7],"drawn":false},{"_id":"kwOTcCx7NDRxqv8B","flags":{},"type":2,"text":"Désir lancinant : Entendre braire un âne","img":"entendre_ane.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"diCCimukdNM6bPub","weight":1,"range":[8,8],"drawn":false},{"_id":"KoGHRGGze7WXnO9R","flags":{},"type":2,"text":"Désir lancinant : Danser avec un(e) partenaire inconnu(e) (Beauté 13 minimum)","img":"danser_inconnu.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"2i3PndTKG1n3hEUU","weight":1,"range":[9,9],"drawn":false},{"_id":"JFiIv5R4gAYV1IMs","flags":{},"type":2,"text":"Désir lancinant : Construire une cabane","img":"construire_cabane.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"mN0yghXkFfj2YctJ","weight":1,"range":[10,10],"drawn":false},{"_id":"vKXdKjA4Vt7OWhOW","flags":{},"type":2,"text":"Désir lancinant : Acquérir une chèvre","img":"acqu%C3%A9rir_chevre.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"8sLXQBqo8XwjAFG0","weight":1,"range":[11,11],"drawn":false},{"_id":"wRk4nXin4UUB5c4o","flags":{},"type":2,"text":"Désir lancinant : Se rouler dans la boue","img":"se_rouler_boue.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"el4lofhhSucMv5xv","weight":1,"range":[12,12],"drawn":false},{"_id":"XUcNhyHEDjSvg8ki","flags":{},"type":2,"text":"Désir lancinant : Embrasser un cochon sur le groin","img":"embrasser_cochon.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"sjXBBr85OBk4Yg4t","weight":1,"range":[13,13],"drawn":false},{"_id":"oN3eP4peneyXENds","flags":{},"type":2,"text":"Désir lancinant : Briser un objet de verre","img":"briser_verre.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"1l59lWbtvYp74OTb","weight":1,"range":[14,14],"drawn":false},{"_id":"5AHjNXDrQL5TqLjv","flags":{},"type":2,"text":"Désir lancinant : Casser 3d6 oeufs en les jetant à terre","img":"casser_oeufs.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"OjG8XRbeYtq2jcgB","weight":1,"range":[15,15],"drawn":false},{"_id":"crQSShE6rcAnBj1k","flags":{},"type":2,"text":"Désir lancinant : Passer une nuit sur une échelle","img":"nuit_echelle.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"LlELEB0FhymLx6VM","weight":1,"range":[16,16],"drawn":false},{"_id":"dDYpP2np5BKlEMSK","flags":{},"type":2,"text":"Désir lancinant : Se faire raser la tête","img":"raser_tete.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"HSNOvBR890dsEDw2","weight":1,"range":[17,17],"drawn":false},{"_id":"CvynUiSfzZ0UnFzk","flags":{},"type":2,"text":"Désir lancinant : Masochisme. Perdre 3 points d’endurance minimum en 1 round","img":"masochisme.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"NzJJNK0YMAbobu0p","weight":1,"range":[18,18],"drawn":false},{"_id":"3pM6YTcKglgt5naZ","flags":{},"type":2,"text":"Désir lancinant : Mégalomanie. Être acclamé par un minimum de 10 personnes","img":"megalomanie.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"3ZjwYyQRatCMnBCi","weight":1,"range":[19,19],"drawn":false},{"_id":"EJYLKIrPHPPbgrlW","flags":{},"type":2,"text":"Désir lancinant : Pisser dans un violon (luth, mandoline, etc.)","img":"pisser_violon.png","collection":"foundryvtt-reve-de-dragon.queues-de-dragon","resultId":"S8PVNgxb7TcFXq9g","weight":1,"range":[20,20],"drawn":false}],"formula":"1d20","replacement":false,"displayRoll":true} -{"name":"Têtes de Dragon pour haut-rêvants","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"description":"Quand une tête est dite unique, retirer si le personnage la possède déjà. Quand elle est dite cumulable, le jet de dés indiqué bénéficie d’un nouveau bonus de +1 chaque fois qu’elle est ré-obtenue. Par exemple un jet de Vue à zéro devient un jet de Vue à +1.","results":[{"_id":"SrGcS3nquZptN3Lx","flags":{},"type":2,"text":"Don de double-rêve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"VWOXA0q6GB7o8oxz","weight":1,"range":[1,10],"drawn":false},{"_id":"fGwttrng7KMYrll1","flags":{},"type":2,"text":"Don de déplacement accéléré","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"ZVh8PLlAzAJulr37","weight":1,"range":[11,20],"drawn":false},{"_id":"BASdOFjj0HJsrDI6","flags":{},"type":2,"text":"Augmentation du seuil de rêve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"Zlt01O2sFrVR9pus","weight":1,"range":[21,30],"drawn":false},{"_id":"HWgayaNNiVLlb5Lj","flags":{},"type":2,"text":"Connaissance intuitive d'un nouveau sort","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"SFxPAvWpEGYHI8mO","weight":1,"range":[31,40],"drawn":false},{"_id":"QMegfeFyxIxNNai7","flags":{},"type":2,"text":"Terre d'attache","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"YDo0a0ApM8iW9g82","weight":1,"range":[41,50],"drawn":false},{"_id":"0FYecx0AOjHJGInw","flags":{},"type":2,"text":"Présents de cités","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"ZuTV36GyOhFgTlE7","weight":1,"range":[51,60],"drawn":false},{"_id":"CtjqmAwweZVDbAjY","flags":{},"type":2,"text":"Réserve en sécurité","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"BT18LAdIqEgSG2Hh","weight":1,"range":[61,70],"drawn":false},{"_id":"WNELkA5FkYTj68Ln","flags":{},"type":2,"text":"Réserve extensible","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"bFdU6ddgj4BAlJZX","weight":1,"range":[71,80],"drawn":false},{"_id":"fn1I3FolBzOmeh0W","flags":{},"type":2,"text":"Quête des eaux","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"a3Y5W0AX5EKxZRSL","weight":1,"range":[81,90],"drawn":false},{"_id":"jr90oOnnrEH31eZj","flags":{},"type":2,"text":"Connaissance du fleuve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"5JccZSafqCXYqrwU","weight":1,"range":[91,100],"drawn":false}],"formula":"1d100","replacement":false,"displayRoll":true,"_id":"sXPDAHwb6ND5tNJG"} +{"_id":"sXPDAHwb6ND5tNJG","name":"Têtes de Dragon pour haut-rêvants","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"img":"icons/svg/d20-grey.svg","description":"Quand une tête est dite unique, retirer si le personnage la possède déjà. Quand elle est dite cumulable, le jet de dés indiqué bénéficie d’un nouveau bonus de +1 chaque fois qu’elle est ré-obtenue. Par exemple un jet de Vue à zéro devient un jet de Vue à +1.","results":[{"_id":"SrGcS3nquZptN3Lx","flags":{},"type":2,"text":"Don de double-rêve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"VWOXA0q6GB7o8oxz","weight":1,"range":[1,10],"drawn":false},{"_id":"fGwttrng7KMYrll1","flags":{},"type":2,"text":"Don de déplacement accéléré","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"ZVh8PLlAzAJulr37","weight":1,"range":[11,20],"drawn":false},{"_id":"BASdOFjj0HJsrDI6","flags":{},"type":2,"text":"Augmentation du seuil de rêve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"Zlt01O2sFrVR9pus","weight":1,"range":[21,30],"drawn":false},{"_id":"HWgayaNNiVLlb5Lj","flags":{},"type":2,"text":"Connaissance intuitive d'un nouveau sort","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"SFxPAvWpEGYHI8mO","weight":1,"range":[31,40],"drawn":false},{"_id":"QMegfeFyxIxNNai7","flags":{},"type":2,"text":"Terre d'attache","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"YDo0a0ApM8iW9g82","weight":1,"range":[41,50],"drawn":false},{"_id":"0FYecx0AOjHJGInw","flags":{},"type":2,"text":"Présent des cités","img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"E4a4O1IdrgbNGpVy","weight":1,"range":[51,60],"drawn":false},{"_id":"CtjqmAwweZVDbAjY","flags":{},"type":2,"text":"Réserve en sécurité","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"BT18LAdIqEgSG2Hh","weight":1,"range":[61,70],"drawn":false},{"_id":"WNELkA5FkYTj68Ln","flags":{},"type":2,"text":"Réserve extensible","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"bFdU6ddgj4BAlJZX","weight":1,"range":[71,80],"drawn":false},{"_id":"fn1I3FolBzOmeh0W","flags":{},"type":2,"text":"Quête des eaux","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"a3Y5W0AX5EKxZRSL","weight":1,"range":[81,90],"drawn":false},{"_id":"jr90oOnnrEH31eZj","flags":{},"type":2,"text":"Connaissance du fleuve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.tetes-de-dragon-pour-haut-revants","resultId":"5JccZSafqCXYqrwU","weight":1,"range":[91,100],"drawn":false}],"formula":"1d100","replacement":true,"displayRoll":true} {"name":"Souffles de Dragon","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"flags":{},"description":"Quand un souffle dure ddr jours, déterminer ce nombre de la même façon que la force d’un Rêve de Dragon, sur une base minimum de 7. Le souffle prend effet à l’instant même et dure jusqu’à la fin de l’heure du Château Dormant du xème jour. Aucun souffle de Dragon n’est refoulable.","results":[{"_id":"39OpB4Ly6pwHNvq3","flags":{},"type":2,"text":"Périple","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"yczTFUNwqyg0WhsQ","weight":1,"range":[1,5],"drawn":false},{"_id":"8JkuRose0umr9I9J","flags":{},"type":2,"text":"Fermeture des cités","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"aBiHdEMLWNZurX3v","weight":1,"range":[6,10],"drawn":false},{"_id":"dGKfn21m4nMJkvTj","flags":{},"type":2,"text":"Débordement","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"YiXBU7qBxR0OnkPS","weight":1,"range":[11,15],"drawn":false},{"_id":"3yosmgSu7FZ0nY3l","flags":{},"type":2,"text":"Impraticabilité des ponts","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"8B74cu17PCdqztke","weight":1,"range":[16,20],"drawn":false},{"_id":"5ujcfs6jFvDjWVOK","flags":{},"type":2,"text":"Désorientation","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"Su90PAG4Hea7qoej","weight":1,"range":[21,25],"drawn":false},{"_id":"MEunTLUJI4pVuzwv","flags":{},"type":2,"text":"Impraticabilité des ponts","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"8B74cu17PCdqztke","weight":1,"range":[26,30],"drawn":false},{"_id":"IvuyAhcW9yzbhRLF","flags":{},"type":2,"text":"Désorientation","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"Su90PAG4Hea7qoej","weight":1,"range":[31,35],"drawn":false},{"_id":"JmoyngtksVYFnNWy","flags":{},"type":2,"text":"Trou noir","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"QcfOUgWT15BCLUvl","weight":1,"range":[36,40],"drawn":false},{"_id":"pombreEUTYX2prs6","flags":{},"type":2,"text":"Péage","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"HYsVo3LM53vAm8Y4","weight":1,"range":[41,45],"drawn":false},{"_id":"PWzcBoJSsDdV8m8m","flags":{},"type":2,"text":"Montée laborieuse","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"yFZ6KkvVQVyCJLua","weight":1,"range":[46,50],"drawn":false},{"_id":"KoyO1TrUQYFxu1MM","flags":{},"type":2,"text":"Double résistance du fleuve","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"nI4sA12n6AdLNv5I","weight":1,"range":[51,55],"drawn":false},{"_id":"NGpVZ0worbKmi5bN","flags":{},"type":2,"text":"Confusion draconique","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"cuopXCY54q3nTtBl","weight":1,"range":[56,60],"drawn":false},{"_id":"wjlmxOrF5mKx5Uqt","flags":{},"type":2,"text":"Épuisement","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"GNZW6esJ2nCHjfyu","weight":1,"range":[61,65],"drawn":false},{"_id":"RYySlbmF6KtKJ8C6","flags":{},"type":2,"text":"Perte dans une caractéristique","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"ykxvi2vohrZPidLK","weight":1,"range":[66,70],"drawn":false},{"_id":"Ec0BW2vZ3QTpIZRn","flags":{},"type":2,"text":"Vieillissement instantané","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"dArTQtFwTssAyl90","weight":1,"range":[71,75],"drawn":false},{"_id":"dIBOMmIwvx2kTgTN","flags":{},"type":2,"text":"Non-combativité","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"6xvkOytCrp5yDAOs","weight":1,"range":[76,79],"drawn":false},{"_id":"3tR6RxkGiugHxSHd","flags":{},"type":2,"text":"Je-m'en-foutisme","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"2FDRnIY6Os6JJ27j","weight":1,"range":[80,83],"drawn":false},{"_id":"TZWltQcYm3F81ZqO","flags":{},"type":2,"text":"Paresse intellectuelle","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"IYfK01ZdAkDZbUS9","weight":1,"range":[84,88],"drawn":false},{"_id":"xmUhIdsW8Bgq31lJ","flags":{},"type":2,"text":"Queue de dragon perpétuelle","img":"icons/svg/mystery-man.svg","collection":"foundryvtt-reve-de-dragon.souffles-de-dragon","resultId":"CVXptnnw75fLx4LK","weight":1,"range":[89,100],"drawn":false}],"formula":"1d100","replacement":false,"displayRoll":true,"_id":"vKiKfjFVP36mYnEt"} {"_id":"w2WBqsg1B2fPV8zT","name":"Tarot Draconique","permission":{"default":0,"Q2G6GTdrotKzYGUC":3},"flags":{"core":{"sourceId":"RollTable.wgFwo1JYrkjyy7J7"}},"img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","description":"Tirage d'une carte de tarot","results":[{"_id":"EP4xqaMgXhuFKNWe","flags":{},"type":2,"text":"L'Auberge","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"2AZ4LaHfNjewYIkO","weight":1,"range":[1,1],"drawn":false},{"_id":"hRvvPoX8nv7AonqM","flags":{},"type":2,"text":"L'Epée","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"inWYIYIuHkoZ3S4A","weight":1,"range":[2,2],"drawn":false},{"_id":"gtMrSlTlMKFV6T6i","flags":{},"type":2,"text":"L'Esprit Thanataire","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"jpNASgEPndryQwuX","weight":1,"range":[3,3],"drawn":false},{"_id":"UdJ5OXBfeg83EN8y","flags":{},"type":2,"text":"La Couronne","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"W150EcUq9vU9ryyc","weight":1,"range":[4,4],"drawn":false},{"_id":"GobVbxfElUvE1flV","flags":{},"type":2,"text":"La Déchirure","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"yIIUac5ehspmqDB2","weight":1,"range":[5,5],"drawn":false},{"_id":"JPjrJQ77YbIwTcJX","flags":{},"type":2,"text":"La Licorne","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"0tOoKLhFKqBLGdAc","weight":1,"range":[6,6],"drawn":false},{"_id":"ToLq4NpjqD2GwlZq","flags":{},"type":2,"text":"La Lune","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"J1qgDjOtf7vK4oV6","weight":1,"range":[7,7],"drawn":false},{"_id":"bTwPXktwq5t5jAAy","flags":{},"type":2,"text":"La Sebile","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"rlmOj3pu4EDd2jZi","weight":1,"range":[8,8],"drawn":false},{"_id":"tbTCmOeNaWYaG6jU","flags":{},"type":2,"text":"La Vierge","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"miO25LLlwPyOAGeR","weight":1,"range":[9,9],"drawn":false},{"_id":"ssqd2Idq1akdYakx","flags":{},"type":2,"text":"Le Chateau","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"n9il4UfR6swHQ805","weight":1,"range":[10,10],"drawn":false},{"_id":"ykbg1uUgbbySEfai","flags":{},"type":2,"text":"Le Coffre","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"vreVS8zyLuiV3qom","weight":1,"range":[11,11],"drawn":false},{"_id":"NkEN5qFZ0aGcgjne","flags":{},"type":2,"text":"Le Gibet","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"beF1v9sjQeDgmxZL","weight":1,"range":[12,12],"drawn":false},{"_id":"OjbIhV6dwaqwMLhG","flags":{},"type":2,"text":"Le Grimoire","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"G2zkE5vY7UrgzNV9","weight":1,"range":[13,13],"drawn":false},{"_id":"mzKV31aojE7DFJUz","flags":{},"type":2,"text":"Le Groin","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"yHvIWLb4TuUAbPGa","weight":1,"range":[14,14],"drawn":false},{"_id":"hD9BUGLDILRc4jJm","flags":{},"type":2,"text":"Le Haut-Rêvant","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"2dWBIwjKVCTxwrHE","weight":1,"range":[15,15],"drawn":false},{"_id":"MFjPTrGgPxUrjHeW","flags":{},"type":2,"text":"Le Luth","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"RjwPSt0pOwQ8w9Qy","weight":1,"range":[16,16],"drawn":false},{"_id":"LZ9n4jg7I1ZjB8Lg","flags":{},"type":2,"text":"Le Rabot","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"zP2OF8ZrAYEODxOn","weight":1,"range":[17,17],"drawn":false},{"_id":"nv6TDBdxJNnJyDYa","flags":{},"type":2,"text":"Le Soleil","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"zSqKPNeQTVjRuni6","weight":1,"range":[18,18],"drawn":false},{"_id":"QdM0WqpsxObvETQU","flags":{},"type":2,"text":"Le Vaisseau","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"VAhO41qD8QQLDie5","weight":1,"range":[19,19],"drawn":false},{"_id":"iDCdiYblZYjPYwYJ","flags":{},"type":2,"text":"Le Voyageur","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"BQkcM9P2xdImdNb9","weight":1,"range":[20,20],"drawn":false},{"_id":"yLioN4DMxU45TnBE","flags":{},"type":2,"text":"Les Marais","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.png","collection":"foundryvtt-reve-de-dragon.tarot-draconique","resultId":"3U9OCmUD156gwu9b","weight":1,"range":[21,21],"drawn":false}],"formula":"1d21","replacement":true,"displayRoll":true} diff --git a/packs/tetes-de-dragon-pour-haut-revants.db b/packs/tetes-de-dragon-pour-haut-revants.db index aeaa1281..c3793ac4 100644 --- a/packs/tetes-de-dragon-pour-haut-revants.db +++ b/packs/tetes-de-dragon-pour-haut-revants.db @@ -1,11 +1,10 @@ {"_id":"5JccZSafqCXYqrwU","name":"Connaissance du fleuve","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Cette tête permet de téléporter instantanément son demi-rêve de n’importe quelle case de fleuve à n’importe quelle autre. Il s’agit du fleuve seul, à l’exclusion des cases de lac et marais. La téléportation remplace le mouvement normal et coûte donc un point de fatigue. Comme après un mouvement normal, une rencontre doit être tirée dans la case de fleuve d’arrivée, puis cette dernière doit être maîtrisée selon la règle usuelle. Noter enfin que la téléportation n’est possible que si le demi-rêve est libre de son mouvement, c’est-à-dire s’il n’est sous l’emprise ni d’un Reflet, ni d’un Tourbillon. Unique.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"BT18LAdIqEgSG2Hh","name":"Réserve en sécurité","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Un haut-rêvant possédant cette tête peut pénétrer sur une case où il a un sort en réserve sans forcément le déclencher s’il ne le souhaite pas. Même chose si un Tourbillon l’abandonne sur une case de réserve. Déclencher un sort en réserve devient un acte volontaire. Même chose pour un échec total en réserve. Cette tête s’applique à toutes les cases. Unique.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} -{"name":"Présent des cités","permission":{"default":0,"Q2G6GTdrotKzYGUC":3},"type":"tete","data":{"description":"

Par cette tête, chaque cité offre automatiquement soit une Fleur des rêves, soit un Passeur, soit un Messager, dès qu’elle est visitée par le demi-rêve du haut-rêvant. Il n’y a pas de d7 à tirer, le haut-rêvant choisit librement ce qu’il préfère, et la rencontre est considérée automatiquement maîtrisée, Fleurs, Messagers et Passeurs ayant une force de 2d6 points. Dès qu’elle a offert son présent, la cité redevient normale en ce qui concerne le tirage des rencontres; il n’y a qu’un seul présent par cité. La tête de Dragon prend fin dès que toutes les cités (22) ont été visitées; entretemps, la tête ne peut être ré-obtenue.

"},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[],"_id":"E4a4O1IdrgbNGpVy"} +{"_id":"E4a4O1IdrgbNGpVy","name":"Présent des cités","permission":{"default":0,"Q2G6GTdrotKzYGUC":3},"type":"tete","data":{"description":"

Par cette tête, chaque cité offre automatiquement soit une Fleur des rêves, soit un Passeur, soit un Messager, dès qu’elle est visitée par le demi-rêve du haut-rêvant. Il n’y a pas de d7 à tirer, le haut-rêvant choisit librement ce qu’il préfère, et la rencontre est considérée automatiquement maîtrisée, Fleurs, Messagers et Passeurs ayant une force de 2d6 points. Dès qu’elle a offert son présent, la cité redevient normale en ce qui concerne le tirage des rencontres; il n’y a qu’un seul présent par cité. La tête de Dragon prend fin dès que toutes les cités (22) ont été visitées; entretemps, la tête ne peut être ré-obtenue.

"},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"SFxPAvWpEGYHI8mO","name":"Connaissance intuitive d'un nouveau sort","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Le haut-rêvant bénéficiaire de cette tête se retrouve en possession d’un nouveau sort ou rituel, déterminé par un procédé aléatoire quelconque.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"VWOXA0q6GB7o8oxz","name":"Don de double-rêve","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Lors de la récupération des points de rêve, permet de jeter 1ddr toutes les demi-heures draconiques au lieu de toutes les heures. Unique.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"YDo0a0ApM8iW9g82","name":"Terre d'attache","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Par cette tête, le haut-rêvant peut désigner une case des TMR de son choix à l’exception d’une case humide. Ensuite, à n’importe quel round de son périple en TMR, il peut s’y téléporter directement quel que soit le nombre de cases qui l’en sépare. Cette téléportation instantanée remplace son mouvement normal et coûte donc un point de fatigue. De même, tout comme après un mouvement normal, 1d7 de rencontre doit être tiré dès l’arrivée dans la terre d’attache. Enfin, le haut-rêvant ne peut s’y téléporter que s’il est libre de son mouvement, c’est-à-dire s’il n’est sous l’emprise ni d’un Reflet d’ancien rêve, ni d’un Tourbillon. Cumulable : on peut avoir plusieurs terres d’attache.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"ZVh8PLlAzAJulr37","name":"Don de déplacement accéléré","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Permet à tout moment l’option du déplacement accéléré dans les TMR sans avoir à dépenser un point de rêve supplémentaire. Unique.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"Zlt01O2sFrVR9pus","name":"Augmentation du seuil de rêve","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Permet d’augmenter le seuil de rêve de 2 points. Cumulable jusqu’à un maximum du double de la caractéristique Rêve.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} -{"_id":"ZuTV36GyOhFgTlE7","name":"Présents de cités","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Par cette tête, chaque cité offre automatiquement soit une Fleur des rêves, soit un Passeur, soit un Messager, dès qu’elle est visitée par le demi-rêve du haut-rêvant. Il n’y a pas de d7 à tirer, le haut-rêvant choisit librement ce qu’il préfère, et la rencontre est considérée automatiquement maîtrisée, Fleurs, Messagers et Passeurs ayant une force de 2d6 points. Dès qu’elle a offert son présent, la cité redevient normale en ce qui concerne le tirage des rencontres; il n’y a qu’un seul présent par cité. La tête de Dragon prend fin dès que toutes les cités (22) ont été visitées; entretemps, la tête ne peut être ré-obtenue.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"a3Y5W0AX5EKxZRSL","name":"Quête des eaux","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Sous l’influence de cette tête, le haut-rêvant est invité à se rendre dans un lac ou dans un marais de son choix. Dès que cette case, lac ou marais, a été maîtrisée selon les règles usuelles, la victoire devient définitive, et la case n’aura plus jamais besoin d’être maîtrisée. Une fois le lac ou le marais choisi, le haut-rêvant ne peut en changer, mais a droit à un nombre illimité d’essais pour le maîtriser. Cumulable : on peut maîtriser définitivement plusieurs lacs ou marais.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} {"_id":"bFdU6ddgj4BAlJZX","name":"Réserve extensible","permission":{"default":0,"jOzRscDxoXZWpGS6":3},"type":"tete","data":{"description":"

Une (seule) case spécifique librement choisie par le haut-rêvant à l’exception d’une case de fleuve, n’est plus dorénavant limitée à un seul sort en réserve. Le haut-rêvant peut y en stocker autant qu’il le désire (dans les limites du nombre permis par ses niveaux). En conséquence, tant que ce maximum n’est pas atteint, le demi-rêve peut entrer dans la case concernée sans déclencher les sorts qui s’y trouvent. Le haut-rêvant peut se contenter d’y passer, ou rajouter un sort aux précédents. Dès que le maximum permis est atteint, le fait de passer par la case déclenche automatiquement l’un des sorts (au choix). Les sorts peuvent être déclenchés l’un après l’autre (rappelons que déclencher un sort fait obligatoirement redescendre le demi-rêve), ou déclenchés ensemble (tout ou partie d’entre eux) à la condition expresse qu’ils aient la même cible (même créature, objet, ou centre de zone). Cumulable : on peut avoir plusieurs cases de réserve extensible.

","refoulement":null},"flags":{},"img":"systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp","effects":[]} From adecbef1788938739256917944667d6280152219 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Fri, 26 Feb 2021 20:46:29 +0100 Subject: [PATCH 21/34] handlebar partiel pour texte d'ambiance --- module/rdd-utility.js | 1 + templates/chat-poesie.html | 14 ++++++++++++++ templates/chat-resultat-chant.html | 16 +--------------- templates/chat-resultat-danse.html | 16 +--------------- templates/chat-resultat-jeu.html | 16 +--------------- templates/chat-resultat-musique.html | 16 +--------------- templates/chat-resultat-oeuvre.html | 16 +--------------- templates/chat-resultat-recettecuisine.html | 17 +---------------- 8 files changed, 21 insertions(+), 91 deletions(-) create mode 100644 templates/chat-poesie.html diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 0c579375..ab25f5bd 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -251,6 +251,7 @@ export class RdDUtility { 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', // messages tchat 'systems/foundryvtt-reve-de-dragon/templates/chat-infojet.html', + 'systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', 'systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', diff --git a/templates/chat-poesie.html b/templates/chat-poesie.html new file mode 100644 index 00000000..dd1c9308 --- /dev/null +++ b/templates/chat-poesie.html @@ -0,0 +1,14 @@ +{{#if description}} +
+ + {{{description}}} + {{#if reference}} +

{{reference}}

+ {{/if}} +
+{{else if reference}} +
+ +

{{reference}}

+
+{{/if}} diff --git a/templates/chat-resultat-chant.html b/templates/chat-resultat-chant.html index 4143eb70..6af6e9d6 100644 --- a/templates/chat-resultat-chant.html +++ b/templates/chat-resultat-chant.html @@ -11,18 +11,4 @@ {{alias}} est peu inspiré(e) et son interprétation a une qualité de {{qualiteFinale}}. {{/if}} -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} diff --git a/templates/chat-resultat-danse.html b/templates/chat-resultat-danse.html index abe93ba7..9d12528b 100644 --- a/templates/chat-resultat-danse.html +++ b/templates/chat-resultat-danse.html @@ -11,18 +11,4 @@ {{alias}} est peu inspiré(e) et son interprétation a une qualité de {{qualiteFinale}}. {{/if}} -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} diff --git a/templates/chat-resultat-jeu.html b/templates/chat-resultat-jeu.html index c8e1736c..6b8c01f3 100644 --- a/templates/chat-resultat-jeu.html +++ b/templates/chat-resultat-jeu.html @@ -11,18 +11,4 @@ {{alias}} a perdu ... {{/if}} -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} diff --git a/templates/chat-resultat-musique.html b/templates/chat-resultat-musique.html index ffea62b6..0b0a6d0b 100644 --- a/templates/chat-resultat-musique.html +++ b/templates/chat-resultat-musique.html @@ -11,18 +11,4 @@ {{alias}} est peu inspiré(e) et son interprétation a une qualité de {{qualiteFinale}}. {{/if}} -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} diff --git a/templates/chat-resultat-oeuvre.html b/templates/chat-resultat-oeuvre.html index 84141952..d7e349e5 100644 --- a/templates/chat-resultat-oeuvre.html +++ b/templates/chat-resultat-oeuvre.html @@ -12,18 +12,4 @@ {{alias}} est peu inspiré(e) et son interprétation a une qualité de {{qualiteFinale}}. {{/if}} -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} diff --git a/templates/chat-resultat-recettecuisine.html b/templates/chat-resultat-recettecuisine.html index c1bc57df..5eb098fd 100644 --- a/templates/chat-resultat-recettecuisine.html +++ b/templates/chat-resultat-recettecuisine.html @@ -16,19 +16,4 @@
Au vu de l'exotisme du plat, les convives devront réussir un jet de Volonté / Cuisine à {{exotismeFinal}}. En cas d'échec, ils peuvent se forcer pour faire plaisir au Maître Queux, mais devront faire un jet de moral Malheureux. {{/if}} - -{{#if oeuvre.data.description}} -
- - {{{oeuvre.data.description}}} - {{#if oeuvre.data.reference}} -

{{oeuvre.data.reference}}

- {{/if}} -
-{{else if oeuvre.data.reference}} -
- -

{{oeuvre.data.reference}}

-
-{{/if}} - +{{> "systems/foundryvtt-reve-de-dragon/templates/chat-poesie.html" oeuvre.data}} From 89d66c1347a74c34765c0c39c22b068b80eb8582 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Fri, 26 Feb 2021 23:54:17 +0100 Subject: [PATCH 22/34] =?UTF-8?q?#164=20:=20une=20seule=20fen=C3=AAtre=20d?= =?UTF-8?q?e=20jet=20autoris=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor.js | 10 ++++++++++ module/rdd-roll.js | 10 +++++++++- system.json | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/module/actor.js b/module/actor.js index 2ecae44a..5ee13feb 100644 --- a/module/actor.js +++ b/module/actor.js @@ -112,6 +112,16 @@ export class RdDActor extends Actor { if (actorData.type === 'vehicule') this._prepareVehiculeData(actorData); } + /* -------------------------------------------- */ + setRollWindowsOpened( flag ) { + this.rollWindowsOpened = flag; + } + + /* -------------------------------------------- */ + isRollWindowsOpened( ) { + return this.rollWindowsOpened; + } + /* -------------------------------------------- */ _prepareCreatureData(actorData) { this.computeEncombrementTotalEtMalusArmure(); diff --git a/module/rdd-roll.js b/module/rdd-roll.js index aff36f6b..079fc277 100644 --- a/module/rdd-roll.js +++ b/module/rdd-roll.js @@ -18,6 +18,12 @@ export class RdDRoll extends Dialog { /* -------------------------------------------- */ static async create(actor, rollData, dialogConfig, ...actions) { + if (actor.isRollWindowsOpened() ) { + ui.notifications.warn("Vous avez déja une fenêtre de Test ouverte, il faut la fermer avant d'en ouvrir une autre.") + return; + } + actor.setRollWindowsOpened(true); + RdDRoll._ensureCorrectActions(actions); RdDRoll._setDefaultOptions(actor, rollData); @@ -102,6 +108,7 @@ export class RdDRoll extends Dialog { close() { if (this.rollData.canClose) { + this.actor.setRollWindowsOpened(false); return super.close(); } ui.notifications.info("Vous devez faire ce jet de dés!"); @@ -112,7 +119,8 @@ export class RdDRoll extends Dialog { async onAction(action, html) { await RdDResolutionTable.rollData(this.rollData); console.log("RdDRoll -=>", this.rollData, this.rollData.rolled); - + this.actor.setRollWindowsOpened(false); + if (action.callbacks) for (let callback of action.callbacks) { if (callback.condition == undefined || callback.condition(this.rollData)) { diff --git a/system.json b/system.json index 871d9a2e..1e23b4f2 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", "description": "Rêve de Dragon RPG for FoundryVTT", - "version": "1.3.23", + "version": "1.3.24", "manifestPlusVersion": "1.0.0", "minimumCoreVersion": "0.7.5", "compatibleCoreVersion": "0.7.9", From bcbd4ab58cced7b8de167fe48a106f0077682984 Mon Sep 17 00:00:00 2001 From: sladecraven Date: Sat, 27 Feb 2021 22:59:10 +0100 Subject: [PATCH 23/34] Fix initiative --- module/rdd-combat.js | 22 ++++++++++++++++++++++ module/rdd-utility.js | 21 --------------------- system.json | 2 +- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/module/rdd-combat.js b/module/rdd-combat.js index b84c8d6a..dafda8ed 100644 --- a/module/rdd-combat.js +++ b/module/rdd-combat.js @@ -9,6 +9,27 @@ import { RdDRoll } from "./rdd-roll.js"; import { RdDRollTables } from "./rdd-rolltables.js"; import { ReglesOptionelles } from "./regles-optionelles.js"; +/* -------------------------------------------- */ +const premierRoundInit = [ + { pattern: 'hast', init: 3.90 }, + { pattern: 'lance', init: 3.85 }, + { pattern: 'baton', init: 3.80 }, + { pattern: 'doubledragonne', init: 3.75 }, + { pattern: 'esparlongue', init: 3.70 }, + { pattern: 'epeedragonne', init: 3.65 }, + { pattern: 'epeebatarde', init: 3.60 }, + { pattern: 'epeecyane', init: 3.55 }, + { pattern: 'epeesorde', init: 3.50 }, + { pattern: 'grandehache', init: 3.45 }, + { pattern: 'bataille', init: 3.40 }, + { pattern: 'epeegnome', init: 3.35 }, + { pattern: 'masse', init: 3.30 }, + { pattern: 'gourdin', init: 3.25 }, + { pattern: 'fléau', init: 3.20 }, + { pattern: 'dague', init: 3.15 }, + { pattern: 'autre', init: 3.10 }, +]; + /* -------------------------------------------- */ export class RdDCombatManager extends Combat { @@ -283,6 +304,7 @@ export class RdDCombatManager extends Combat { /* -------------------------------------------- */ static displayInitiativeMenu(html, combatantId) { + console.log("Combatant ; ", combatantId); const combatant = game.combat.getCombatant(combatantId); let armesList = RdDCombatManager.buildListeActionsCombat(combatant); diff --git a/module/rdd-utility.js b/module/rdd-utility.js index 0c579375..0e952cfe 100644 --- a/module/rdd-utility.js +++ b/module/rdd-utility.js @@ -81,27 +81,6 @@ const tableCaracDerivee = { 32: { xp: 180, poids: "1501-2000", plusdom: +11, sconst: 10, sust: 17 } } -/* -------------------------------------------- */ -const premierRoundInit = [ - { pattern: 'hast', init: 3.90 }, - { pattern: 'lance', init: 3.85 }, - { pattern: 'baton', init: 3.80 }, - { pattern: 'doubledragonne', init: 3.75 }, - { pattern: 'esparlongue', init: 3.70 }, - { pattern: 'epeedragonne', init: 3.65 }, - { pattern: 'epeebatarde', init: 3.60 }, - { pattern: 'epeecyane', init: 3.55 }, - { pattern: 'epeesorde', init: 3.50 }, - { pattern: 'grandehache', init: 3.45 }, - { pattern: 'bataille', init: 3.40 }, - { pattern: 'epeegnome', init: 3.35 }, - { pattern: 'masse', init: 3.30 }, - { pattern: 'gourdin', init: 3.25 }, - { pattern: 'fléau', init: 3.20 }, - { pattern: 'dague', init: 3.15 }, - { pattern: 'autre', init: 3.10 }, -]; - /* -------------------------------------------- */ function _buildAllSegmentsFatigue(max) { const cycle = [5, 2, 4, 1, 3, 0]; diff --git a/system.json b/system.json index 1e23b4f2..70076bb4 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "name": "foundryvtt-reve-de-dragon", "title": "Rêve de Dragon", "description": "Rêve de Dragon RPG for FoundryVTT", - "version": "1.3.24", + "version": "1.3.25", "manifestPlusVersion": "1.0.0", "minimumCoreVersion": "0.7.5", "compatibleCoreVersion": "0.7.9", From 875b051090c77e34edce057692a45f987469a22b Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 27 Feb 2021 22:24:40 +0100 Subject: [PATCH 24/34] fix typos --- templates/casetmr-specific-list.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/casetmr-specific-list.html b/templates/casetmr-specific-list.html index ccedfd1f..48be5d5b 100644 --- a/templates/casetmr-specific-list.html +++ b/templates/casetmr-specific-list.html @@ -5,8 +5,8 @@ - - + + From 0d77b10473b7efa24bbe9d0c60c3fe225b5ff928 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 27 Feb 2021 22:25:15 +0100 Subject: [PATCH 25/34] =?UTF-8?q?Ajout=20extraits=20po=C3=A8mes=20des=20re?= =?UTF-8?q?ncontres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/poetique.js | 202 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 190 insertions(+), 12 deletions(-) diff --git a/module/poetique.js b/module/poetique.js index 58127bf8..e448d6e7 100644 --- a/module/poetique.js +++ b/module/poetique.js @@ -4,25 +4,25 @@ const poesieHautReve = [ { reference: 'Le Ratier Bretonien', extrait: `Le courant du Fleuve -
Te domine et te Porte -
Avant que tu te moeuves -
Combat le, ou il t'emporte` +
Te domine et te Porte +
Avant que tu te moeuves +
Combat le, ou il t'emporte` }, { reference: 'Incompatibilité, Charles Beaudelaire', extrait: `Et lorsque par hasard une nuée errante -
Assombrit dans son vol le lac silencieux, -
On croirait voir la robe ou l'ombre transparente -
D'un esprit qui voyage et passe dans les cieux.` +
Assombrit dans son vol le lac silencieux, +
On croirait voir la robe ou l'ombre transparente +
D'un esprit qui voyage et passe dans les cieux.` }, { reference: 'Au fleuve de Loire, Joachim du Bellay', extrait: `Ô de qui la vive course -
Prend sa bienheureuse source, -
D’une argentine fontaine, -
Qui d’une fuite lointaine, -
Te rends au sein fluctueux -
De l’Océan monstrueux` +
Prend sa bienheureuse source, +
D’une argentine fontaine, +
Qui d’une fuite lointaine, +
Te rends au sein fluctueux +
De l’Océan monstrueux` }, { reference: 'Denis Gerfaud', @@ -61,10 +61,188 @@ const poesieHautReve = [ Nul ne sait qui est le créateur des Dragons, ni qui est leur maître. Mais l'on peut supposer qui est le maître du Rêve des Dragons, c'est Oniros»` }, + { + reference: "La chevelure, Charles Baudelaire", + extrait: `J'irai là-bas où l'arbre et l'homme, pleins de sève, +
Se pâment longuement sous l'ardeur des climats ; +
Fortes tresses, soyez la houle qui m'enlève !` + }, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `En réalité, tous les éléments du rêve des Dragons expriment + le Draconic : chaque pierre, chaque fleur, chaque goutte d'eau, + chaque nuage est porteur d'un message dans la langue des Dragons` + }, + { + reference: "Femmes damnées (2), Charles Baudelaire", + extrait: `Comme je descendais des Fleuves impassibles, +
Je ne me sentis plus guidé par les haleurs : +
Des Peaux-Rouges criards les avaient pris pour cibles, +
Les ayant cloués nus aux poteaux de couleurs.` + }, + { + reference: "Le bateau ivre, Arthur Rimbaud", + extrait: `Loin des peuples vivants, errantes, condamnées, +
A travers les déserts courez comme les loups ; +
Faites votre destin, âmes désordonnées, +
Et fuyez l'infini que vous portez en vous !` + }, + { + reference: "L'Ennemi, Charles Baudelaire", + extrait: `Et qui sait si les fleurs nouvelles que je rêve +
Trouveront dans ce sol lavé comme une grève +
Le mystique aliment qui ferait leur vigueur ?` + }, + { + reference: "Une charogne, Charles Baudelaire", + extrait: `Et le ciel regardait la carcasse superbe +
Comme une fleur s'épanouir. +
La puanteur était si forte, que sur l'herbe +
Vous crûtes vous évanouir.` + }, + { + reference: "Conseil, Victor Hugo", + extrait: `Rois ! la bure est souvent jalouse du velours. +
Le peuple a froid l'hiver, le peuple a faim toujours. +
Rendez-lui son sort plus facile. +
Le peuple souvent porte un bien rude collier. +
Ouvrez l'école aux fils, aux pères l'atelier, +
À tous vos bras, auguste asile !` + }, + { + reference: "El Desdichado, Gérard de Nerval", + extrait: `Suis-je Amour ou Phébus ?... Lusignan ou Biron ? +
Mon front est rouge encor du baiser de la Reine ; +
J'ai rêvé dans la Grotte où nage la sirène...` + }, + { + reference: "Caligula - IIIème chant, Gérard de Nerval", + extrait: `Allez, que le caprice emporte +
Chaque âme selon son désir, +
Et que, close après vous, la porte +
Ne se rouvre plus qu'au plaisir.` + }, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `Les sages ont encore coutume de dire : +
« Mais comment les Dragons peuvent-ils + être influencés par une créature qui, tout + bien considéré, n'existe pas vraiment pour eux, + qui n'est que le fantasme de leur activité nocturne ? »` + }, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `La légende affirme que ce sont les Gnomes qui furent + les premiers haut-rêvants. En observant les pierres précieuses, + les gemmes qui sont les larmes de joie des Dragons, ils parvinrent à + en comprendre la langue. Et l'ayant comprise, ils purent s'en servir + pour influencer le cours du rêve`, + }, + { + reference: "Quand le rêve se brise, Cypora Sebagh", + extrait: `Quand le rêve se brise, +
Dans la plainte du jour, +
Ma mémoire devient grise +
Et sombre, tour à tour, +
Dans le puits du silence +
Et de la solitude ; +
Elle reprend son errance +
Parmi la multitude.` + } + , + { + reference: "Une charogne, Charles Baudelaire", + extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve, +
Une ébauche lente à venir +
Sur la toile oubliée, et que l'artiste achève +
Seulement par le souvenir.` + }, + { + reference: "La chevelure, Charles Baudelaire", + extrait: `Longtemps ! toujours ! ma main dans ta crinière lourde +
Sèmera le rubis, la perle et le saphir, +
Afin qu'à mon désir tu ne sois jamais sourde ! +
N'es-tu pas l'oasis où je rêve, et la gourde +
Où je hume à longs traits le vin du souvenir` + }, + { + reference: "Un Fou et un Sage, Jean de La Fontaine", + extrait: `Certain Fou poursuivait à coups de pierre un Sage. +
Le Sage se retourne et lui dit : Mon ami, +
C'est fort bien fait à toi ; reçois cet écu-ci : +
Tu fatigues assez pour gagner davantage.` + }, + { + reference: "Guitare, Victor Hugo", + extrait: `Je la voyais passer de ma demeure, +
Et c'était tout. +
Mais à présent je m'ennuie à toute heure, +
Plein de dégoût, +
Rêveur oisif, l'âme dans la campagne, +
La dague au clou ... – +
Le vent qui vient à travers la montagne +
M'a rendu fou !` + }, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement + des temps, le commencement des rêves. Durant cette période plus mythique + que réellement historique, les Dragons aimaient à se rêver eux-mêmes.` + }, + { + reference: "Les Djinns, Victor Hugo", + extrait: `C'est l'essaim des Djinns qui passe, +
Et tourbillonne en sifflant ! +
Les ifs, que leur vol fracasse, +
Craquent comme un pin brûlant.`}, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les + Gnomes s'enfoncèrent profondément sous les montagnes et la magie passa aux + mains des Humains qui en usèrent et abusèrent, se croyant devenus les maîtres du monde` + }, + { + reference: "Lily, Pierre Perret", + extrait: `Elle aurait pas cru sans le voir +
Que la couleur du désespoir +
Là-bas aussi ce fût le noir.` + }, + + { + reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet", + extrait: `Qu'est-ce de votre vie ? un tourbillon rouant +
De fumière à flot gris, parmi l'air se jouant, +
Qui passe plus soudain que foudre meurtrière.` + }, + { + reference: "Les Djinns, poème Victor Hugo", + extrait: `Cris de l'enfer! voix qui hurle et qui pleure ! +
L'horrible essaim, poussé par l'aquilon, +
Sans doute, ô ciel ! s'abat sur ma demeure. +
Le mur fléchit sous le noir bataillon. +
La maison crie et chancelle penchée, +
Et l'on dirait que, du sol arrachée, +
Ainsi qu'il chasse une feuille séchée, +
Le vent la roule avec leur tourbillon !` + }, + { + reference: "Rêve de Dragon, Denis Gerfaud", + extrait: `Le monde est Rêve de Dragons, mais nous ne savons +
ni leur apparence ni qui sont les dragons. +
En dépit de l'iconographie qui les clame +
immenses créatures ailées crachant des flammes` + }, + { + reference: "El Desdichado, Gérard de Nerval", + extrait: `Je suis le Ténébreux, – le Veuf, – l'Inconsolé, +
Le Prince d'Aquitaine à la Tour abolie : +
Ma seule Etoile est morte, – et mon luth constellé +
Porte le Soleil noir de la Mélancolie.` + }, ] export class Poetique { - static getExtrait(){ + static getExtrait() { return Misc.rollOneOf(poesieHautReve); } From d2fcb365144f0f3271a5c4cd36a1317de6880b95 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sat, 27 Feb 2021 22:26:14 +0100 Subject: [PATCH 26/34] =?UTF-8?q?Ajout=20de=20m=C3=A9thode=20getTMRDescr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit retourne le nom de la case précédé de l'article --- module/tmr-utility.js | 19 +++++++++++-------- module/tmr/draconique.js | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/module/tmr-utility.js b/module/tmr-utility.js index aa0358ef..222d85c8 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -1,5 +1,6 @@ import { TMRRencontres } from "./tmr-rencontres.js"; import { Misc } from "./misc.js"; +import { Grammar } from "./grammar.js"; /* -------------------------------------------- */ const TMRMapping = { @@ -210,24 +211,21 @@ const TMRMapping = { export const TMRType = { cite: { name: "cité", genre: "f" }, - sanctuaire: { name: "sanctuaire" }, - plaines: { name: "plaines", genre: "p" }, + sanctuaire: { name: "sanctuaire" , genre: 'm'}, + plaines: { name: "plaines", genre: "fp" }, pont: { name: "pont", genre: "m" }, - collines: { name: "collines", genre: "p" }, + collines: { name: "collines", genre: "fp" }, foret: { name: "forêt", genre: "f" }, - monts: { name: "monts", genre: "p" }, + monts: { name: "monts", genre: "mp" }, desert: { name: "désert", genre: "m" }, fleuve: { name: "fleuve", genre: "m" }, lac: { name: "lac", genre: "m" }, - marais: { name: "marais", genre: "m" }, + marais: { name: "marais", genre: "mp" }, gouffre: { name: "gouffre", genre: "m" }, necropole: { name: "nécropole", genre: "f" }, desolation: { name: "désolation", genre: "f" } } -/* -------------------------------------------- */ -const caseSpecificModes = ["attache", "trounoir", "debordement", "reserve_extensible", "maitrisee"]; - /* -------------------------------------------- */ const tmrRandomMovePatten = [{ name: 'top', x: 0, y: -1 }, @@ -335,6 +333,11 @@ export class TMRUtility { return TMRMapping[coord]?.label ?? (coord+": case inconnue"); } + static getTMRDescr(coord) { + const tmr = TMRMapping[coord]; + return Grammar.articleDetermine(tmr.genre)+' '+tmr.label; + } + static isCaseHumide(tmr) { return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais'; } diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js index 9af391ec..4349c0ae 100644 --- a/module/tmr/draconique.js +++ b/module/tmr/draconique.js @@ -16,6 +16,7 @@ export class Draconique static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); } tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); } + tmrDescr(linkData) { return TMRUtility.getTMRDescr(linkData.data.coord); } static register(draconique) { registeredEffects[draconique.code()] = draconique; From d179661a222b682e14da8d3b98d865fd79a5bc93 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:26:32 +0100 Subject: [PATCH 27/34] =?UTF-8?q?#166=20Supprimer=20seulement=20le=20sort?= =?UTF-8?q?=20d=C3=A9clench=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor.js | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/module/actor.js b/module/actor.js index 5ee13feb..dec691aa 100644 --- a/module/actor.js +++ b/module/actor.js @@ -313,15 +313,13 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async deleteSortReserve(sortReserve) { let reserve = duplicate(this.data.data.reve.reserve); - let len = reserve.list.length; - let i = 0; - 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]); - } - if (newTable.length != len) { - reserve.list = newTable; + let tmr = TMRUtility.getTMR(sortReserve.coord); + let index = reserve.list.findIndex(tmr.type == 'fleuve' + ? sort => (TMRUtility.getTMR(sort.coord).type == 'fleuve' && sort.sort.name == sortReserve.sort.name) + : sort => (sort.coord == sortReserve.coord && sort.sort.name == sortReserve.sort.name) + ); + if (index >=0 ) { + reserve.list.splice(index,1); await this.update({ "data.reve.reserve": reserve }); } } From dc66e10f75fa23d6eeaf1ba03b25bf94c0950178 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:38:40 +0100 Subject: [PATCH 28/34] fix Grammar --- module/grammar.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/module/grammar.js b/module/grammar.js index e75bdc77..7a35cebc 100644 --- a/module/grammar.js +++ b/module/grammar.js @@ -26,7 +26,7 @@ export class Grammar { /* -------------------------------------------- */ static articleDetermine(genre) { - switch (toLowerCaseNoAccent(genre)) { + switch (Grammar.toLowerCaseNoAccent(genre)) { case 'f': case 'feminin': return 'la'; case 'p': case 'mp': case 'fp': case 'pluriel': return 'les'; default: @@ -35,8 +35,8 @@ export class Grammar { } /* -------------------------------------------- */ - static articleIndétermine(genre) { - switch (toLowerCaseNoAccent(genre)) { + static articleIndetermine(genre) { + switch (Grammar.toLowerCaseNoAccent(genre)) { case 'f': case 'feminin': return 'une'; case 'p': case 'fp': case 'mp': case 'pluriel': return 'des'; case 'n': case 'neutre': return 'du' @@ -58,7 +58,7 @@ export class Grammar { * @param {...any} mots */ static accord(genre, ...mots) { - switch (toLowerCaseNoAccent(genre)) { + switch (Grammar.toLowerCaseNoAccent(genre)) { default: case 'n': case 'neutre': case 'm': case 'masculin': return mots[0]; From fc3aaeb207eb60c658d82f123777ec95dcdeec02 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:40:32 +0100 Subject: [PATCH 29/34] =?UTF-8?q?Ajout=20commande=20id=C3=A9e=20fixe/d?= =?UTF-8?q?=C3=A9sir=20lancinant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/rdd-commands.js | 2 ++ module/rdd-rolltables.js | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/module/rdd-commands.js b/module/rdd-commands.js index b085c758..a10392ff 100644 --- a/module/rdd-commands.js +++ b/module/rdd-commands.js @@ -23,6 +23,8 @@ export class RdDCommands { rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" }); rddCommands.registerCommand({ path: ["/table", "queues"], func: (content, msg, params) => RdDRollTables.getQueue(true), descr: "Tire une Queue de Dragon" }); + rddCommands.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe(true), descr: "Tire une Idée fixe" }); + rddCommands.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant(true), descr: "Tire un Désir Lancinant" }); rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre(true), descr: "Tire une Ombre de Dragon" }); rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR(true), descr: "Tire une Tête de Dragon pour Hauts Revants" }); rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete(true), descr: "Tire une Tête de Dragon" }); diff --git a/module/rdd-rolltables.js b/module/rdd-rolltables.js index 957c130a..74d06152 100644 --- a/module/rdd-rolltables.js +++ b/module/rdd-rolltables.js @@ -48,14 +48,22 @@ export class RdDRollTables { static async getQueue(toChat = false) { let queue = await RdDRollTables.drawItemFromRollTable("Queues de dragon", toChat); if (queue.name.toLowerCase().includes('lancinant') ) { - queue = await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat); + return await RdDRollTables.getDesirLancinant(toChat); } if (queue.name.toLowerCase().includes('fixe') ) { - queue = await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat); + return await RdDRollTables.getIdeeFixe(toChat); } return queue; } + static async getDesirLancinant(toChat = false) { + return await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat); + } + + static async getIdeeFixe(toChat = false) { + return await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat); + } + /* -------------------------------------------- */ static async getTeteHR(toChat = false) { return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat); From 002822d55973d4f9d38f2d011321129d0159cc2c Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:50:15 +0100 Subject: [PATCH 30/34] =?UTF-8?q?Refactor:=20extrait=20m=C3=A9thodes=20com?= =?UTF-8?q?munes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - suppression de casetmr lors de visite/conquete - suppression de toutes les cases TMRs liées - notification lors de suppression d'une casetmr pour enlever la queue --- module/actor.js | 10 ++++++++++ module/rdd-tmr-dialog.js | 20 ++++++++++--------- module/tmr/conquete.js | 7 ------- module/tmr/desorientation.js | 10 ---------- module/tmr/draconique.js | 36 +++++++++++++++++++++++++---------- module/tmr/fermeture-cites.js | 7 ------- module/tmr/pelerinage.js | 9 --------- 7 files changed, 47 insertions(+), 52 deletions(-) diff --git a/module/actor.js b/module/actor.js index dec691aa..5bd0daf4 100644 --- a/module/actor.js +++ b/module/actor.js @@ -3197,6 +3197,9 @@ export class RdDActor extends Actor { case 'souffle': await this.onDeleteOwnedDraconique(item, options, id); break; + case 'casetmr': + await this.onDeleteOwnedCaseTmr(item, options, id); + break; } } @@ -3218,6 +3221,13 @@ export class RdDActor extends Actor { } } + async onDeleteOwnedCaseTmr(item, options, id) { + let draconique = Draconique.all().find(it => it.isCase(item)); + if (draconique) { + draconique.onActorDeleteCaseTmr(this, item) + } + } + notifyGestionTeteSouffleQueue(item, manualMessage=true){ ChatMessage.create({ whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index a3bcff7e..ecbc3caf 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -558,8 +558,10 @@ export class RdDTMRDialog extends Dialog { await this._conquerir(tmr, { difficulte: -9, action: 'Conquérir la cité', - onConqueteReussie: r => EffetsDraconiques.fermetureCites.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), - onConqueteEchec: r => this.close(), + onConqueteReussie: r => EffetsDraconiques.fermetureCites.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), + onConqueteEchec: r => { + this.close() + }, canClose: false }); } @@ -576,8 +578,8 @@ export class RdDTMRDialog extends Dialog { await this._conquerir(tmr, { difficulte: -7, action: 'Conquérir', - onConqueteReussie: r => EffetsDraconiques.conquete.onConquete(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), - onConqueteEchec: r => { }, + onConqueteReussie: r => EffetsDraconiques.conquete.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), + onConqueteEchec: r => this.close(), canClose: false }); } @@ -639,8 +641,8 @@ export class RdDTMRDialog extends Dialog { dialog.render(true); } - async validerPelerinage(tmr) { - await EffetsDraconiques.pelerinage.onFinPelerinage(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); + async validerVisite(tmr) { + await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); } @@ -836,17 +838,17 @@ export class RdDTMRDialog extends Dialog { await this.manageCaseHumide(tmr); await this.conquerirCiteFermee(tmr); await this.conquerirTMR(tmr); - await this.validerPelerinage(tmr); + await this.validerVisite(tmr); await this.declencheSortEnReserve(tmr.coord); await this.actor.checkSoufflePeage(tmr); } } - + /* -------------------------------------------- */ async forceDemiRevePositionView() { this._updateDemiReve(); } - + /* -------------------------------------------- */ async forceDemiRevePosition(coord) { await this.actor.updateCoordTMR(coord); diff --git a/module/tmr/conquete.js b/module/tmr/conquete.js index 92d665c4..550c6427 100644 --- a/module/tmr/conquete.js +++ b/module/tmr/conquete.js @@ -35,11 +35,4 @@ export class Conquete extends Draconique { await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id); } - async onConquete(actor, tmr, onRemoveToken) { - let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord)); - for (let casetmr of existants) { - await actor.deleteOwnedItem(casetmr.data.sourceid); - onRemoveToken(tmr, casetmr); - } - } } diff --git a/module/tmr/desorientation.js b/module/tmr/desorientation.js index f2dad665..1dcec96a 100644 --- a/module/tmr/desorientation.js +++ b/module/tmr/desorientation.js @@ -24,10 +24,6 @@ export class Desorientation extends Draconique { return Object.keys(TMRType).filter(it => !dejaDesorientes.includes(it)); } - async onActorDeleteOwned(actor, souffle) { - await this._supprimerCasesTmr(actor, souffle); - } - code() { return 'desorientation' } tooltip(linkData) { return `Désorientation, cette case n'existe plus !` } img() { return 'icons/svg/explosion.svg' } @@ -51,11 +47,5 @@ export class Desorientation extends Draconique { } } - async _supprimerCasesTmr(actor, souffle) { - let caseTmrs = actor.data.items.filter(it => it.data.sourceId == souffle._id); - for (let casetmr of caseTmrs) { - await actor.deleteOwnedItem(casetmr._id); - } - } } diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js index 4349c0ae..8c3ea81a 100644 --- a/module/tmr/draconique.js +++ b/module/tmr/draconique.js @@ -7,8 +7,7 @@ const registeredEffects = [ /** * Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR */ -export class Draconique -{ +export class Draconique { static isCaseTMR(element) { return element.type == 'casetmr'; } static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; } static isSouffleDragon(element) { return element.type == 'souffle'; } @@ -29,6 +28,7 @@ export class Draconique static all() { return Object.values(registeredEffects); } + static get(code) { return registeredEffects[code]; } @@ -57,10 +57,11 @@ export class Draconique } async onActorDeleteOwned(actor, item) { - let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == item._id); - for (let casetmr of caseTmrs) { - await actor.deleteOwnedItem(casetmr._id); - } + this.deleteCasesTmr(actor, item); + return false; + } + + async onActorDeleteCaseTmr(actor, casetmr) { return false; } /** @@ -73,7 +74,7 @@ export class Draconique * @returns un tooltip à afficher au dessus du token */ tooltip(linkData) { return undefined } - + /** * @param {*} img l'url du fichier image à utiliser pour le token. Si indéfini (et si createSprite n'est pas surchargé), * un disque est utilisé. @@ -103,7 +104,7 @@ export class Draconique if (this.img()) { return pixiTMR.sprite(this.code()); } - else{ + else { return pixiTMR.circle() } } @@ -121,11 +122,26 @@ export class Draconique return list.find(c => this.isCase(c, coord)); } - async createCaseTmr(actor, label, tmr, sourceId=undefined) { + async createCaseTmr(actor, label, tmr, sourceId = undefined) { await actor.createOwnedItem({ name: label, type: 'casetmr', img: this.img(), _id: randomID(16), - data: { coord: tmr.coord, specific: this.code(), sourceid:sourceId } + data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId } }); } + async deleteCasesTmr(actor, draconique) { + let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id); + for (let casetmr of caseTmrs) { + await actor.deleteOwnedItem(casetmr._id); + } + } + + async onVisiteSupprimer(actor, tmr, onRemoveToken) { + let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord)); + for (let casetmr of existants) { + await actor.deleteOwnedItem(casetmr._id); + onRemoveToken(tmr, casetmr); + } + } + } \ No newline at end of file diff --git a/module/tmr/fermeture-cites.js b/module/tmr/fermeture-cites.js index 6a8602d3..8d695ae6 100644 --- a/module/tmr/fermeture-cites.js +++ b/module/tmr/fermeture-cites.js @@ -35,11 +35,4 @@ export class FermetureCites extends Draconique { await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle._id); } } - - async onConquete(actor, tmr, onRemoveToken) { - const citeFermee = actor.data.items.find(it => this.isCase(it, tmr.coord)); - await actor.deleteOwnedItem(citeFermee._id); - onRemoveToken(tmr, citeFermee); - } - } diff --git a/module/tmr/pelerinage.js b/module/tmr/pelerinage.js index 76cc2fe9..d9ba19c5 100644 --- a/module/tmr/pelerinage.js +++ b/module/tmr/pelerinage.js @@ -30,13 +30,4 @@ export class Pelerinage extends Draconique { decallage: tmrConstants.right }); } - - async onFinPelerinage(actor, tmr, onRemoveToken) { - const pelerinages = actor.data.items.filter(it => this.isCase(it, tmr.coord)); - for (let p of pelerinages){ - await actor.deleteOwnedItem(p.data.sourceid); - onRemoveToken(tmr, p); - } - } - } From 9878946109baddea5adbf5b75acf84ead275b409 Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:50:46 +0100 Subject: [PATCH 31/34] =?UTF-8?q?Extrait=20m=C3=A9thode=20Actor.getDemiRev?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/module/actor.js b/module/actor.js index 5bd0daf4..1031637b 100644 --- a/module/actor.js +++ b/module/actor.js @@ -310,6 +310,9 @@ export class RdDActor extends Actor { } return duplicate(list[0]); } + getDemiReve() { + return this.data.data.reve.tmrpos.coord; + } /* -------------------------------------------- */ async deleteSortReserve(sortReserve) { let reserve = duplicate(this.data.data.reve.reserve); @@ -1187,7 +1190,7 @@ export class RdDActor extends Actor { //console.log("List", rencontres, len); let newTable = []; for (i = 0; i < len; i++) { - if (rencontres.list[i].coord != this.data.data.reve.tmrpos.coord) + if (rencontres.list[i].coord != this.getDemiReve()) newTable.push(rencontres.list[i]); } if (newTable.length != len) { @@ -1204,7 +1207,7 @@ export class RdDActor extends Actor { let i = 0; let already = false; for (i = 0; i < len; i++) { - if (rencontres.list[i].coord == this.data.data.reve.tmrpos.coord) + if (rencontres.list[i].coord == this.getDemiReve()) already = true; } if (!already) { @@ -1226,9 +1229,7 @@ export class RdDActor extends Actor { /* -------------------------------------------- */ async updateCoordTMR(coord) { - let tmrPos = duplicate(this.data.data.reve.tmrpos); - tmrPos.coord = coord; - await this.update({ "data.reve.tmrpos": tmrPos }); + await this.update({ "data.reve.tmrpos.coord": coord }); } /* -------------------------------------------- */ From e37b5758d31ab367f3a46b5661b6ef674cc4ac5e Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:52:58 +0100 Subject: [PATCH 32/34] Suppression de queues TMR finies --- module/tmr/conquete.js | 4 ++++ module/tmr/draconique.js | 1 - module/tmr/pelerinage.js | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/module/tmr/conquete.js b/module/tmr/conquete.js index 550c6427..ba7dffeb 100644 --- a/module/tmr/conquete.js +++ b/module/tmr/conquete.js @@ -35,4 +35,8 @@ export class Conquete extends Draconique { await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id); } + async onActorDeleteCaseTmr(actor, casetmr) { + await actor.deleteOwnedItem(casetmr.data.sourceid); + } + } diff --git a/module/tmr/draconique.js b/module/tmr/draconique.js index 8c3ea81a..4bf8a34d 100644 --- a/module/tmr/draconique.js +++ b/module/tmr/draconique.js @@ -143,5 +143,4 @@ export class Draconique { onRemoveToken(tmr, casetmr); } } - } \ No newline at end of file diff --git a/module/tmr/pelerinage.js b/module/tmr/pelerinage.js index d9ba19c5..ec9e4010 100644 --- a/module/tmr/pelerinage.js +++ b/module/tmr/pelerinage.js @@ -30,4 +30,9 @@ export class Pelerinage extends Draconique { decallage: tmrConstants.right }); } + + async onActorDeleteCaseTmr(actor, casetmr) { + await actor.deleteOwnedItem(casetmr.data.sourceid); + } + } From 2fed3947cece8e6e8077baa1dc4b3f37bd7d5ebb Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:54:19 +0100 Subject: [PATCH 33/34] Ajout de souffle dans certains cas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - conquete de cité échouée --- module/rdd-tmr-dialog.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index ecbc3caf..4f876aa2 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -498,9 +498,7 @@ export class RdDTMRDialog extends Dialog { } async _resultatMaitriseCaseHumide(rollData) { - if (rollData.rolled.isETotal) { - rollData.souffle = await this.actor.ajouterSouffle({ chat: false }); - } + await this.souffleSiEchecTotal(rollData); this.toclose = rollData.rolled.isEchec; if (rollData.rolled.isSuccess && rollData.double) { rollData.previous = { rolled: rollData.rolled, ajustements: rollData.ajustements }; @@ -518,6 +516,12 @@ export class RdDTMRDialog extends Dialog { } } + async souffleSiEchecTotal(rollData) { + if (rollData.rolled.isETotal) { + rollData.souffle = await this.actor.ajouterSouffle({ chat: false }); + } + } + /* -------------------------------------------- */ isCaseHumide(tmr) { if (!(TMRUtility.isCaseHumide(tmr) || this.isCaseHumideAdditionelle(tmr))) { @@ -560,6 +564,7 @@ export class RdDTMRDialog extends Dialog { action: 'Conquérir la cité', onConqueteReussie: r => EffetsDraconiques.fermetureCites.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), onConqueteEchec: r => { + this.souffleSiEchecTotal(rollData); this.close() }, canClose: false From c1a8a24ee75aae062d558f6c01aca24dde83e56d Mon Sep 17 00:00:00 2001 From: Vincent Vandemeulebrouck Date: Sun, 28 Feb 2021 01:56:17 +0100 Subject: [PATCH 34/34] =?UTF-8?q?Ajout=20P=C3=A9riple=20&=20urgence=20drac?= =?UTF-8?q?onique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module/actor.js | 20 ---------- module/rdd-tmr-dialog.js | 37 ++++++++++++++----- module/tmr-utility.js | 31 ++++++++++++---- module/tmr/effets-draconiques.js | 25 +++++++++++-- module/tmr/periple.js | 44 ++++++++++++++++++++++ module/tmr/urgence-draconique.js | 55 ++++++++++++++++++++++++++++ templates/casetmr-specific-list.html | 21 ++++++----- 7 files changed, 181 insertions(+), 52 deletions(-) create mode 100644 module/tmr/periple.js create mode 100644 module/tmr/urgence-draconique.js diff --git a/module/actor.js b/module/actor.js index 1031637b..31385304 100644 --- a/module/actor.js +++ b/module/actor.js @@ -1157,26 +1157,6 @@ export class RdDActor extends Actor { return tmrInnaccessibles.map(it => it.data.coord); } - /* -------------------------------------------- */ - displayTMRQueueSouffleInformation() { - let messages = []; - for (let item of this.data.items) { - if (EffetsDraconiques.isUrgenceDraconique(item)) { - messages.push("Vous souffrez d'une Urgence Draconique : " + item.data.description); - } - if (EffetsDraconiques.isPeriple(item)) { - messages.push("Vous souffrez du Souffle Périple. Vous devez gérer manuellement le détail du Périple.
" + item.data.description); - } - } - - if (messages.length > 0) { - ChatMessage.create({ - whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), - content: "RAPPEL !
" + messages.join('
') - }); - } - } - /* -------------------------------------------- */ getTMRRencontres() { return this.data.data.reve.rencontre; diff --git a/module/rdd-tmr-dialog.js b/module/rdd-tmr-dialog.js index 4f876aa2..cbc1aafe 100644 --- a/module/rdd-tmr-dialog.js +++ b/module/rdd-tmr-dialog.js @@ -108,6 +108,11 @@ export class RdDTMRDialog extends Dialog { this._createTokens(); } + removeToken(tmr, casetmr) { + this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id); + this.updateTokens() + } + /* -------------------------------------------- */ _getTokensCasesTmr() { return this.casesSpeciales.map(c => this._tokenCaseSpeciale(c)).filter(token => token); @@ -142,7 +147,7 @@ export class RdDTMRDialog extends Dialog { async activateListeners(html) { super.activateListeners(html); - document.getElementById("tmrrow1").insertCell(1).append(this.pixiApp.view); + document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view); if (this.viewOnly) { html.find('#lancer-sort').remove(); @@ -168,7 +173,6 @@ export class RdDTMRDialog extends Dialog { let tmr = TMRUtility.getTMR(this.actor.data.data.reve.tmrpos.coord); await this.manageRencontre(tmr, () => { this.postRencontre(tmr); - this.actor.displayTMRQueueSouffleInformation(); }); } @@ -571,10 +575,20 @@ export class RdDTMRDialog extends Dialog { }); } } - - removeToken(tmr, casetmr) { - this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id); - this.updateTokens() + /* -------------------------------------------- */ + async purifierPeriple(tmr) { + if (EffetsDraconiques.periple.find(this.casesSpeciales, tmr.coord)) { + await this._conquerir(tmr, { + difficulte: EffetsDraconiques.periple.getDifficulte(tmr), + action: 'Purifier ' + TMRUtility.getTMRDescr(tmr.coord), + onConqueteReussie: r => EffetsDraconiques.periple.onVisiteSupprimer(r.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)), + onConqueteEchec: r => { + this.souffleSiEchecTotal(rollData); + this.close() + }, + canClose: false + }); + } } /* -------------------------------------------- */ @@ -648,6 +662,7 @@ export class RdDTMRDialog extends Dialog { async validerVisite(tmr) { await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); + await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr)); } @@ -656,11 +671,12 @@ export class RdDTMRDialog extends Dialog { let sortReserveList = TMRUtility.getSortReserveList(this.sortsReserves, coord); if (sortReserveList.length > 0) { - if (EffetsDraconiques.isSortImpossible(this.actor)) { + if (EffetsDraconiques.isSortReserveImpossible(this.actor)) { ui.notifications.error("Une queue ou un souffle vous empèche de déclencher de sort!"); return; } - if (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord)) { + if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && + (EffetsDraconiques.isReserveEnSecurite(this.actor) || this.isReserveExtensible(coord))) { let msg = "Vous êtes sur une case avec un Sort en Réserve. Grâce à votre Tête Reserve en Sécurité ou Réserve Exensible, vous pouvez contrôler le déclenchement. Cliquez si vous souhaitez le déclencher :
    "; for (let sortReserve of sortReserveList) { msg += "
  • " + sortReserve.sort.name + "
  • "; @@ -670,9 +686,9 @@ export class RdDTMRDialog extends Dialog { content: msg, whisper: ChatMessage.getWhisperRecipients(game.user.name) }); - } else { - await this.processSortReserve(sortReserveList[0]); + return; } + await this.processSortReserve(sortReserveList[0]); } } @@ -842,6 +858,7 @@ export class RdDTMRDialog extends Dialog { if (!(this.viewOnly || this.currentRencontre)) { await this.manageCaseHumide(tmr); await this.conquerirCiteFermee(tmr); + await this.purifierPeriple(tmr); await this.conquerirTMR(tmr); await this.validerVisite(tmr); await this.declencheSortEnReserve(tmr.coord); diff --git a/module/tmr-utility.js b/module/tmr-utility.js index 222d85c8..cd2d3387 100644 --- a/module/tmr-utility.js +++ b/module/tmr-utility.js @@ -211,7 +211,7 @@ const TMRMapping = { export const TMRType = { cite: { name: "cité", genre: "f" }, - sanctuaire: { name: "sanctuaire" , genre: 'm'}, + sanctuaire: { name: "sanctuaire", genre: 'm' }, plaines: { name: "plaines", genre: "fp" }, pont: { name: "pont", genre: "m" }, collines: { name: "collines", genre: "fp" }, @@ -330,12 +330,12 @@ export class TMRUtility { } static getTMRLabel(coord) { - return TMRMapping[coord]?.label ?? (coord+": case inconnue"); + return TMRMapping[coord]?.label ?? (coord + ": case inconnue"); } static getTMRDescr(coord) { const tmr = TMRMapping[coord]; - return Grammar.articleDetermine(tmr.genre)+' '+tmr.label; + return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label; } static isCaseHumide(tmr) { @@ -387,7 +387,7 @@ export class TMRUtility { currentPos.x = currentPos.x + direction.x; currentPos.y = currentPos.y + direction.y; if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Sortie de carte ! Ré-insertion aléatoire - coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos)); + coord = TMRUtility.getTMR(TMRUtility.convertToTMRCoord(currentPos)); } else { coord = await actor.reinsertionAleatoire('Sortie de carte'); } @@ -438,7 +438,7 @@ export class TMRUtility { return reserveList.filter(it => TMRUtility.getTMR(it.coord).type == 'fleuve'); } // Reserve sur un case "normale" - return reserveList.filter(it => it.coord == coord); + return reserveList.filter(it => it.coord == coord); } /* -------------------------------------------- */ @@ -453,9 +453,8 @@ export class TMRUtility { for (let dy = -portee; dy <= portee; dy++) { // Loop thru lines const currentPos = { x: centerPos.x + dx, y: centerPos.y + dy }; if (this._checkTMRCoord(currentPos.x, currentPos.y)) { // Coordinate is valie - let posPicNow = this.computeRealPictureCoordinates(currentPos, tmrConstants); - let dist = Math.sqrt(Math.pow(posPicNow.x - posPic.x, 2) + Math.pow(posPicNow.y - posPic.y, 2)) / tmrConstants.cellw; - if (dist < portee + 0.5) { + let dist = this.distancePosTMR(centerPos, currentPos); + if (dist <= portee) { caseList.push(this.convertToTMRCoord(currentPos)); // Inside the area } } @@ -463,5 +462,21 @@ export class TMRUtility { } return caseList; } + + static distanceTMR(coord1, coord2) { + let pos1 = this.convertToCellPos(coord1); + let pos2 = this.convertToCellPos(coord2); + return this.distancePosTMR(pos1, pos2); + } + + static distancePosTMR(pos1, pos2) { + const dx = pos2.x - pos1.x; + const dy = pos2.y - pos1.y; + const abs_dx = Math.abs(dx); + const abs_dy = Math.abs(dy); + const distance = Math.sign(dx) == Math.sign(dy) ? Math.max(abs_dx, abs_dy) : (abs_dx + abs_dy); + return distance; + } + } diff --git a/module/tmr/effets-draconiques.js b/module/tmr/effets-draconiques.js index ab8bdc3d..6eefe7f3 100644 --- a/module/tmr/effets-draconiques.js +++ b/module/tmr/effets-draconiques.js @@ -14,6 +14,8 @@ import { PresentCites } from "./present-cites.js"; import { Desorientation } from "./desorientation.js"; import { Conquete } from "./conquete.js"; import { Pelerinage } from "./pelerinage.js"; +import { Periple } from "./periple.js"; +import { UrgenceDraconique } from "./urgence-draconique.js"; export class EffetsDraconiques { @@ -32,6 +34,8 @@ export class EffetsDraconiques { static desorientation = new Desorientation(); static conquete = new Conquete(); static pelerinage = new Pelerinage(); + static periple = new Periple(); + static urgenceDraconique = new UrgenceDraconique(); static init() { Draconique.register(EffetsDraconiques.carteTmr); @@ -49,6 +53,8 @@ export class EffetsDraconiques { Draconique.register(EffetsDraconiques.desorientation); Draconique.register(EffetsDraconiques.conquete); Draconique.register(EffetsDraconiques.pelerinage); + Draconique.register(EffetsDraconiques.periple); + Draconique.register(EffetsDraconiques.urgenceDraconique); } /* -------------------------------------------- */ @@ -112,8 +118,7 @@ export class EffetsDraconiques { } static isPeriple(element) { - // TODO - return EffetsDraconiques.isMatching(element, it => Draconique.isSouffleDragon(it) && ir.name.toLowerCase() == 'périple'); + return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.periple.match(it)); } static isDesorientation(element) { @@ -122,7 +127,19 @@ export class EffetsDraconiques { /* -------------------------------------------- */ static isSortImpossible(element) { - return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.conquete.match(it) || EffetsDraconiques.pelerinage.match(it)); + return EffetsDraconiques.isMatching(element, it => + EffetsDraconiques.conquete.match(it) || + EffetsDraconiques.periple.match(it) || + EffetsDraconiques.urgenceDraconique.match(it) || + EffetsDraconiques.pelerinage.match(it) + ); + } + static isSortReserveImpossible(element) { + return EffetsDraconiques.isMatching(element, it => + EffetsDraconiques.conquete.match(it) || + EffetsDraconiques.periple.match(it) || + EffetsDraconiques.pelerinage.match(it) + ); } static isConquete(element) { @@ -138,7 +155,7 @@ export class EffetsDraconiques { } static isUrgenceDraconique(element) { - return EffetsDraconiques.isMatching(element, it => Draconique.isQueueDragon(it) && it.name.toLowerCase() == 'urgence draconique'); + return EffetsDraconiques.isMatching(element, it => EffetsDraconiques.urgenceDraconique.match(it)); } /* -------------------------------------------- */ diff --git a/module/tmr/periple.js b/module/tmr/periple.js new file mode 100644 index 00000000..feba1a2b --- /dev/null +++ b/module/tmr/periple.js @@ -0,0 +1,44 @@ +import { Grammar } from "../grammar.js"; +import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js"; +import { Draconique } from "./draconique.js"; + +export class Periple extends Draconique { + + constructor() { + super(); + } + + type() { return 'souffle' } + match(item) { return Draconique.isSouffleDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('periple'); } + manualMessage() { return false } + + async onActorCreateOwned(actor, souffle) { + let terrain = new Roll("1d2").evaluate().total == 1 ? 'sanctuaire' : 'necropole'; + let tmrs = TMRUtility.getListTMR(terrain); + for (let tmr of tmrs) { + await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle._id); + } + } + + + code() { return 'periple' } + tooltip(linkData) { return `Votre Périple passe par ${this.tmrDescr(linkData)}` } + img() { return 'icons/svg/acid.svg' } + + createSprite(pixiTMR) { + return pixiTMR.sprite(this.code(), { + zIndex: tmrTokenZIndex.conquete, + alpha: 1, + color: tmrColors.souffle, + taille: tmrConstants.twoThird, + decallage: tmrConstants.right + }); + } + getDifficulte(tmr) { + switch (tmr.type) { + case 'sanctuaire': return -3; + case 'necropole': return -5; + } + return 0; + } +} \ No newline at end of file diff --git a/module/tmr/urgence-draconique.js b/module/tmr/urgence-draconique.js new file mode 100644 index 00000000..8af5c992 --- /dev/null +++ b/module/tmr/urgence-draconique.js @@ -0,0 +1,55 @@ +import { ChatUtility } from "../chat-utility.js"; +import { Grammar } from "../grammar.js"; +import { Misc } from "../misc.js"; +import { RdDRollTables } from "../rdd-rolltables.js"; +import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js"; +import { Draconique } from "./draconique.js"; + +export class UrgenceDraconique extends Draconique { + + constructor() { + super(); + } + + type() { return 'queue' } + match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); } + manualMessage() { return false } + async onActorCreateOwned(actor, queue) { + let coordSortsReserve = (actor.data.data.reve.reserve?.list.map(it => it.coord)) ?? []; + if (coordSortsReserve.length == 0) { + // La queue se transforme en idée fixe + let ideeFixe = await RdDRollTables.getIdeeFixe(); + ChatMessage.create({ + whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), + content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${queue.name}` + }); + await actor.createOwnedItem(ideeFixe); + await actor.deleteOwnedItem(queue._id); + return; + } + else { + let demiReve = actor.getDemiReve(); + coordSortsReserve.sort((a, b) => TMRUtility.distanceTMR(a, demiReve) - TMRUtility.distanceTMR(b, demiReve)); + let tmr = TMRUtility.getTMR(coordSortsReserve[0]); + await this.createCaseTmr(actor, 'Urgence draconique: ' + tmr.label, tmr, queue._id); + } + } + + async onActorDeleteCaseTmr(actor, casetmr) { + await actor.deleteOwnedItem(casetmr.data.sourceid); + } + + code() { return 'urgence' } + tooltip(linkData) { return `Urgence draconique!` } + img() { return 'icons/svg/hazard.svg' } + + createSprite(pixiTMR) { + return pixiTMR.sprite(this.code(), + { + zIndex: tmrTokenZIndex.conquete, + color: tmrColors.queues, + taille: tmrConstants.full, + decallage: { x: 2, y: 0 } + }); + } +} diff --git a/templates/casetmr-specific-list.html b/templates/casetmr-specific-list.html index 48be5d5b..136f1f6d 100644 --- a/templates/casetmr-specific-list.html +++ b/templates/casetmr-specific-list.html @@ -1,12 +1,13 @@ + + + + + + + + + + - - - - - - - - - - +