forked from public/foundryvtt-reve-de-dragon
		
	Compare commits
	
		
			22 Commits
		
	
	
		
			12.0.32
			...
			5ac9c682d9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 5ac9c682d9 | |||
| 6de19eb357 | |||
| 90d096a6df | |||
| c733644f3a | |||
| de9d3bbb48 | |||
| efdffd171c | |||
| 8406c8434a | |||
| 135e5e46a0 | |||
| 969bc3b573 | |||
| a9eb101c9d | |||
| d53da1f011 | |||
| ab0f7e563f | |||
| 57c41a0218 | |||
| 1b75decb18 | |||
| 551438f514 | |||
| 792558ac84 | |||
| 06aff9a3c0 | |||
| 7e736a00d7 | |||
| b87f406093 | |||
| 785bd4b9ce | |||
| daca86b1df | |||
| aa52e26e1a | 
							
								
								
									
										18
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,4 +1,22 @@ | ||||
| # 12.0 | ||||
| ## 12.0.34 - la tête d'Astrobazzarh | ||||
| - support de liens "jets de dés" | ||||
|   - on peut ajouter des liens "jet de dés" dans les journaux, descriptions, notes, maladresses, ... | ||||
|   - avec la syntaxe `@roll[...]` on peut ajouter le lien vers: | ||||
|     - un jet de caractéristique/compétence `@roll[carac/competence/difficulte]` / `@roll[carac/difficulte]` / `@roll[carac/competence]`  | ||||
|     - une formule foundry `@roll[2d6]` pour lancer 2d6  | ||||
|     - une manipulation alchimique `@roll[couleur vert-bleu]` | ||||
|   - les liens "jet avec caractéristiques" s'appliquent: | ||||
|     - à tous les tokens sélectionnés | ||||
|     - sinon, à l'acteur propriétaire (dans le cas d'un Item) ou à l'acteur courant | ||||
|     - sinon, au personnage du joueur | ||||
|   - on peut poster les liens dans le tchat pour proposer un jet aux joueurs | ||||
| - gestion des blocs secrets dans les descriptions | ||||
|  | ||||
| ## 12.0.33 - la vieillesse d'Astrobazzarh | ||||
| - retour de l'expérience pour les joueurs | ||||
| - suppression du message "Pas de caractéristique" sur les jets d'odorat-goût | ||||
|  | ||||
| ## 12.0.32 - les rêveries d'Astrobazzarh | ||||
| - Ajout des Items Race pour gérer les ajustements liés aux races | ||||
|  | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js"; | ||||
| import { RdDCoeur } from "./coeur/rdd-coeur.js"; | ||||
| import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"; | ||||
| import { RdDItemRace } from "./item/race.js"; | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| /** | ||||
| @@ -44,8 +45,8 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|       cssClass: this.isEditable ? "editable" : "locked", | ||||
|       limited: this.actor.limited, | ||||
|       owner: this.actor.isOwner, | ||||
|       biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }), | ||||
|       notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }), | ||||
|       biographie: await RdDTextEditor.enrichHTML(this.actor.system.biographie, this.actor), | ||||
|       notes: await RdDTextEditor.enrichHTML(this.actor.system.notes, this.actor), | ||||
|     }); | ||||
|     foundry.utils.mergeObject(formData.calc, { | ||||
|       surenc: this.actor.computeMalusSurEncombrement(), | ||||
| @@ -221,7 +222,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|     } | ||||
|  | ||||
|     // Points de reve actuel | ||||
|     this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true)) | ||||
|     this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', {resistance:true})) | ||||
|     this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) | ||||
|  | ||||
|     this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence')) | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import { RdDItemSigneDraconique } from "./item/signedraconique.js"; | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; | ||||
| import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; | ||||
| import { Draconique } from "./tmr/draconique.js"; | ||||
| import { LIST_CARAC, RdDCarac } from "./rdd-carac.js"; | ||||
| import { LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js"; | ||||
| import { DialogConsommer } from "./dialog-item-consommer.js"; | ||||
| import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; | ||||
| import { RollDataAjustements } from "./rolldata-ajustements.js"; | ||||
| @@ -662,15 +662,15 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   /* -------------------------------------------- */ | ||||
|   async updateCarac(caracName, to) { | ||||
|     to = Number(to) | ||||
|     if (!RdDItemRace.checkRacialMax(this, caracName, to)){ | ||||
|     if (!RdDItemRace.checkRacialMax(this, caracName, to)) { | ||||
|       return | ||||
|     } | ||||
|     if (caracName == LIST_CARAC.reve.code) { | ||||
|     if (caracName == LIST_CARAC_PERSONNAGE.reve.code) { | ||||
|       if (to > Misc.toInt(this.system.reve.seuil.value)) { | ||||
|         this.setPointsDeSeuil(to); | ||||
|       } | ||||
|     } | ||||
|     if (caracName == LIST_CARAC.chance.code) { | ||||
|     if (caracName == LIST_CARAC_PERSONNAGE.chance.code) { | ||||
|       if (to > Misc.toInt(this.system.compteurs.chance.value)) { | ||||
|         this.setPointsDeChance(to); | ||||
|       } | ||||
| @@ -1387,7 +1387,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|  | ||||
|     await RdDResolutionTable.rollData(ethylismeData.jetVie); | ||||
|     this._gererExperience(ethylismeData.jetVie); | ||||
|     this.gererExperience(ethylismeData.jetVie); | ||||
|     RollDataAjustements.calcul(ethylismeData.jetVie, this); | ||||
|     if (ethylismeData.jetVie.rolled.isSuccess) { | ||||
|       ethylisme.nb_doses++; | ||||
| @@ -1419,7 +1419,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|           finalLevel: Number(ethylisme.value) + Number(this.system.compteurs.moral.value) | ||||
|         } | ||||
|         await RdDResolutionTable.rollData(ethylismeData.jetVolonte); | ||||
|         this._gererExperience(ethylismeData.jetVolonte); | ||||
|         this.gererExperience(ethylismeData.jetVolonte); | ||||
|         RollDataAjustements.calcul(ethylismeData.jetVolonte, this); | ||||
|       } | ||||
|     } | ||||
| @@ -1596,7 +1596,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { | ||||
|     if (!Misc.isFirstConnectedGM()) { | ||||
|     if (!Misc.hasConnectedGM()) { | ||||
|       return | ||||
|     } | ||||
|     hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) | ||||
| @@ -1799,38 +1799,8 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** | ||||
|    * Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue | ||||
|    * @param {*} caracName  | ||||
|    * @param {*} compName  | ||||
|    * @param {*} diff  | ||||
|    * @param {*} options  | ||||
|    * @returns  | ||||
|    */ | ||||
|   async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) { | ||||
|     const carac = this.getCaracByName(caracName); | ||||
|     if (!carac) { | ||||
|       ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`) | ||||
|       return; | ||||
|     } | ||||
|     const competence = this.getCompetence(compName); | ||||
|     let rollData = { | ||||
|       alias: this.getAlias(), | ||||
|       caracValue: Number(carac.value), | ||||
|       selectedCarac: carac, | ||||
|       competence: competence, | ||||
|       diffLibre: diff, | ||||
|       show: { title: options?.title ?? '' } | ||||
|     }; | ||||
|     RollDataAjustements.calcul(rollData, this); | ||||
|     await RdDResolutionTable.rollData(rollData); | ||||
|     this._gererExperience(rollData); | ||||
|     await RdDResolutionTable.displayRollData(rollData, this) | ||||
|     return rollData.rolled; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _gererExperience(rollData) { | ||||
|   gererExperience(rollData) { | ||||
|     const callback = this.createCallbackExperience(); | ||||
|     if (callback.condition(rollData)) { | ||||
|       callback.action(rollData); | ||||
| @@ -1880,26 +1850,6 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     return undefined; | ||||
|   } | ||||
|  | ||||
|   async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) { | ||||
|     RdDEmpoignade.checkEmpoignadeEnCours(this) | ||||
|     const competence = this.getCompetence(compName); | ||||
|     await this.openRollDialog({ | ||||
|       name: 'jet-competence', | ||||
|       label: 'Jet ' + Grammar.apostrophe('de', competence.name), | ||||
|       template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', | ||||
|       rollData: { | ||||
|         alias: this.getAlias(), | ||||
|         carac: this.system.carac, | ||||
|         selectedCarac: this.getCaracByName(caracName), | ||||
|         selectedCaracName: caracName, | ||||
|         diffLibre: diff, | ||||
|         competence: competence, | ||||
|         show: { title: options?.title ?? '' } | ||||
|       }, | ||||
|       callbackAction: r => this.$onRollCompetence(r, options) | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async rollTache(id, options = {}) { | ||||
|     RdDEmpoignade.checkEmpoignadeEnCours(this) | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { RdDSheetUtility } from "../rdd-sheet-utility.js"; | ||||
| @@ -27,7 +28,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet { | ||||
|  | ||||
|     this.html.find('.button-encaissement').click(async event => this.actor.encaisser()) | ||||
|     this.html.find('.roll-carac').click(async event => { | ||||
|       this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))}); | ||||
|       this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))}) | ||||
|     this.html.find('.roll-competence').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event))); | ||||
|     this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1)); | ||||
|     this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1)); | ||||
| @@ -47,6 +48,9 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet { | ||||
|         } | ||||
|       }], { renderSheet: true }) | ||||
|     ) | ||||
|     this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor)) | ||||
|     this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event)) | ||||
|  | ||||
|  | ||||
|     if (this.options.vueDetaillee) { | ||||
|       // On carac change | ||||
|   | ||||
| @@ -22,6 +22,7 @@ import { RdDCombat } from "../rdd-combat.js"; | ||||
| import { RdDEmpoignade } from "../rdd-empoignade.js"; | ||||
| import { RdDPossession } from "../rdd-possession.js"; | ||||
| import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js"; | ||||
| import { RollDataAjustements } from "../rolldata-ajustements.js"; | ||||
|  | ||||
| /** | ||||
|  * Classe de base pour les acteurs disposant de rêve (donc, pas des objets) | ||||
| @@ -293,6 +294,57 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|   createCallbackAppelAuMoral() { return this.createEmptyCallback(); } | ||||
|   async _onCloseRollDialog(html) { } | ||||
|  | ||||
|   async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) { | ||||
|     RdDEmpoignade.checkEmpoignadeEnCours(this) | ||||
|     const competence = this.getCompetence(compName); | ||||
|     await this.openRollDialog({ | ||||
|       name: 'jet-competence', | ||||
|       label: competence? 'Jet ' + Grammar.apostrophe('de', competence.name) : `Jet sans compétence (${compName})`, | ||||
|       template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', | ||||
|       rollData: { | ||||
|         alias: this.getAlias(), | ||||
|         carac: this.system.carac, | ||||
|         selectedCarac: this.getCaracByName(caracName), | ||||
|         selectedCaracName: caracName, | ||||
|         diffLibre: diff, | ||||
|         competence: competence, | ||||
|         show: { title: options?.title ?? '' } | ||||
|       }, | ||||
|       callbackAction: r => this.$onRollCompetence(r, options) | ||||
|     }); | ||||
|   } | ||||
|   /** | ||||
|    * Méthode pour faire un jet prédéterminer sans ouvrir la fenêtre de dialogue | ||||
|    * @param {*} caracName code ou label de la caractéristique. On peut utiliser 'intel' pour Intellect. | ||||
|    * @param {*} compName nom de compétence ou nom abrégé. | ||||
|    * @param {*} diff difficulté (0 si undefined) | ||||
|    * @param {*} options | ||||
|    * @returns le jet effectué | ||||
|    */ | ||||
|   async doRollCaracCompetence(caracName, compName, diff, options = { title: "" }) { | ||||
|     const carac = this.getCaracByName(caracName); | ||||
|     if (!carac) { | ||||
|       ui.notifications.warn(`${this.name} n'a pas de caractéristique correspondant à ${caracName}`) | ||||
|       return | ||||
|     } | ||||
|     const competence = this.getCompetence(compName); | ||||
|     let rollData = { | ||||
|       alias: this.getAlias(), | ||||
|       caracValue: Number(carac.value), | ||||
|       selectedCarac: carac, | ||||
|       competence: competence, | ||||
|       diffLibre: diff ?? 0, | ||||
|       show: { title: options?.title ?? '' } | ||||
|     } | ||||
|     RollDataAjustements.calcul(rollData, this); | ||||
|     await RdDResolutionTable.rollData(rollData); | ||||
|     this.gererExperience(rollData); | ||||
|     await RdDResolutionTable.displayRollData(rollData, this) | ||||
|     return rollData.rolled; | ||||
|   } | ||||
|  | ||||
|   gererExperience(rollData) { } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async roll() { | ||||
|     RdDEmpoignade.checkEmpoignadeEnCours(this) | ||||
| @@ -311,14 +363,14 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|         competences: this.itemTypes['competence'] | ||||
|       }, | ||||
|       callbackAction: r => this.$onRollCaracResult(r) | ||||
|     }); | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async rollCarac(caracName, jetResistance = undefined) { | ||||
|   async rollCarac(caracName, options = {}) { | ||||
|     if (Grammar.equalsInsensitive(caracName, 'taille')) { | ||||
|       return | ||||
|     } | ||||
|     foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false }) | ||||
|     RdDEmpoignade.checkEmpoignadeEnCours(this) | ||||
|     let selectedCarac = this.getCaracByName(caracName) | ||||
|     console.log("selectedCarac", selectedCarac) | ||||
| @@ -329,7 +381,8 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|       rollData: { | ||||
|         selectedCarac: selectedCarac, | ||||
|         competences: this.itemTypes['competence'], | ||||
|         jetResistance: jetResistance ? caracName : undefined | ||||
|         diffLibre: options.diff ?? 0, | ||||
|         jetResistance: options.resistance ? caracName : undefined | ||||
|       }, | ||||
|       callbackAction: r => this.$onRollCaracResult(r) | ||||
|     }); | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import { RdDSheetUtility } from "../rdd-sheet-utility.js"; | ||||
| import { Monnaie } from "../item-monnaie.js"; | ||||
| import { RdDItem, ITEM_TYPES } from "../item.js"; | ||||
| import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| /** | ||||
| @@ -35,8 +36,8 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|       img: this.actor.img, | ||||
|       name: this.actor.name, | ||||
|       system: this.actor.system, | ||||
|       description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }), | ||||
|       notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }), | ||||
|       description: await RdDTextEditor.enrichHTML(this.actor.system.description, this.actor), | ||||
|       notesmj: await RdDTextEditor.enrichHTML(this.actor.system.notesmj, this.actor), | ||||
|       options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable), | ||||
|       effects: this.actor.effects | ||||
|     } | ||||
|   | ||||
| @@ -21,7 +21,7 @@ export class RdDBaseActor extends Actor { | ||||
|  | ||||
|   static $findCaracByName(carac, name) { | ||||
|     const caracList = Object.entries(carac); | ||||
|     let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique' }); | ||||
|     let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique', onMessage: m => { } }); | ||||
|     if (!entry || entry.length == 0) { | ||||
|       entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' }); | ||||
|     } | ||||
| @@ -81,7 +81,6 @@ export class RdDBaseActor extends Actor { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   static getRealActor(actorId, tokenId) { | ||||
|     if (tokenId) { | ||||
|       let token = canvas.tokens.get(tokenId) | ||||
| @@ -161,8 +160,11 @@ export class RdDBaseActor extends Actor { | ||||
|     return RdDBaseActor.$findCaracByName(carac, name); | ||||
|   } | ||||
|  | ||||
|   mapCarac(caracCode) { return caracCode } | ||||
|  | ||||
|   getCaracByName(name) { | ||||
|     switch (Grammar.toLowerCaseNoAccent(name)) { | ||||
|     name = this.mapCarac(Grammar.toLowerCaseNoAccent(name)) | ||||
|     switch (name) { | ||||
|       case 'reve-actuel': case 'reve actuel': | ||||
|         return this.getCaracReveActuel(); | ||||
|       case 'chance-actuelle': case 'chance-actuelle': | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { LIST_CARAC_AUTRES } from "../rdd-carac.js"; | ||||
| import { RdDBaseActorSang } from "./base-actor-sang.js"; | ||||
|  | ||||
| export class RdDCreature extends RdDBaseActorSang { | ||||
| @@ -32,4 +34,16 @@ export class RdDCreature extends RdDBaseActorSang { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   mapCarac(caracCode) { | ||||
|     switch (caracCode) { | ||||
|       case 'vue': case 'ouie': case 'odoratgout': case 'empathie': case 'perception': | ||||
|         return 'perception' | ||||
|       case 'agilite': | ||||
|         return 'force' | ||||
|       case 'force': case 'constitution': case 'taille': case 'reve': case 'volonte': | ||||
|         return caracCode | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -117,4 +117,14 @@ export class RdDEntite extends RdDBaseActorReve { | ||||
|       super.setEntiteReveAccordee(actor) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   mapCarac(caracCode) { | ||||
|     switch (caracCode) { | ||||
|       case 'taille': | ||||
|       case 'reve': | ||||
|         return caracCode | ||||
|     } | ||||
|     return 'reve' | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -34,7 +34,6 @@ const XREGEXP_WEAPON_MANIEMENT = "(?<maniement>(" + Misc.join(Object.keys(MANIEM | ||||
|  | ||||
| const XREGEXP_SORT_VOIE = "(?<voies>[OHNT](\\/[OHNT])*)" | ||||
| const XREGEXP_SORT_NAME = "(?<name>[^\\(]+)" | ||||
| // const XREGEXP_SORT_CASE = "(?<coord>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2})+)" | ||||
| const XREGEXP_SORT_CASE = "(?<coord>([A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+|[A-M]\\d{1,2}))" | ||||
|  | ||||
| const XREGEXP_SORT = "(" + XREGEXP_SORT_VOIE | ||||
|   | ||||
							
								
								
									
										78
									
								
								module/apps/rdd-text-roll-editor.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								module/apps/rdd-text-roll-editor.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| import "./xregexp-all.js"; | ||||
| import { SystemCompendiums } from "../settings/system-compendiums.js"; | ||||
| import { ACTOR_TYPES } from "../item.js"; | ||||
| import { TextRollAlchimie } from "./textroll/text-roll-alchimie.js"; | ||||
| import { TextRollCaracCompetence } from "./textroll/text-roll-carac-competence.js"; | ||||
| import { TextRollFormula } from "./textroll/text-roll-formula.js"; | ||||
| import { TextRollManager } from "./textroll/text-roll-formatter.js"; | ||||
|  | ||||
| const TEXT_ROLL_MANAGERS = [ | ||||
|   new TextRollAlchimie(), | ||||
|   new TextRollCaracCompetence(), | ||||
|   new TextRollFormula()] | ||||
|  | ||||
| export class RdDTextEditor { | ||||
|   static registerChatCallbacks(html) { | ||||
|     html.on("click", '.roll-text', async event => await RdDTextEditor.rollText(event)) | ||||
|   } | ||||
|  | ||||
|   static async enrichHTML(text, object, options = {showlink:true}) { | ||||
|     const context = { | ||||
|       text, | ||||
|       object, | ||||
|       options, | ||||
|       competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage), | ||||
|     } | ||||
|  | ||||
|     for (let manager of TEXT_ROLL_MANAGERS) { | ||||
|       context.code = manager.code | ||||
|       context.template = manager.template | ||||
|       context.text = await manager.onReplaceRoll(context); | ||||
|     } | ||||
|  | ||||
|     return await TextEditor.enrichHTML(context.text, { | ||||
|       relativeTo: object, | ||||
|       secrets: object?.isOwner, | ||||
|       async: true | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   static async _applyReplaceAll(manager, context) { | ||||
|     context.code = manager.code | ||||
|     context.template = manager.template | ||||
|     context.text = await manager.onReplaceRoll(context); | ||||
|     return context.text | ||||
|   } | ||||
|  | ||||
|   static getEventElement(event) { | ||||
|     return $(event.currentTarget)?.parents(".roll-text-link"); | ||||
|   } | ||||
|  | ||||
|   static async rollText(event, actor) { | ||||
|     const code = TextRollManager.getNode(event)?.data('code') | ||||
|     const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code) | ||||
|     if (manager) { | ||||
|       await manager.onRollText(event, actor) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static async chatRollText(event) { | ||||
|     const node = TextRollManager.getNode(event); | ||||
|     if (node) { | ||||
|       const code = node.data('code') | ||||
|       const param = node.data('json') | ||||
|       const manager = TEXT_ROLL_MANAGERS.find(it => it.code == code) | ||||
|  | ||||
|       const text = await TextRollManager.createRollText( | ||||
|         { | ||||
|           code, | ||||
|           template: manager.template, | ||||
|           options: { showLink: false } | ||||
|         }, | ||||
|         param) | ||||
|       ChatMessage.create({ | ||||
|         content: text | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										79
									
								
								module/apps/textroll/text-roll-alchimie.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								module/apps/textroll/text-roll-alchimie.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| import "../xregexp-all.js"; | ||||
| import { ACTOR_TYPES, ITEM_TYPES } from "../../item.js"; | ||||
| import { RdDCarac } from "../../rdd-carac.js"; | ||||
| import { RdDUtility } from "../../rdd-utility.js"; | ||||
| import { RdDAlchimie } from "../../rdd-alchimie.js"; | ||||
| import { TextRollManager } from "./text-roll-formatter.js"; | ||||
|  | ||||
| const REGEX_ALCHIMIE_TERMES = "(?<termes>(\\w|-)+)" | ||||
| const REGEX_ALCHIMIE_MANIP = "(?<manip>(couleur|consistance))" | ||||
| const XREGEXP_ROLL_ALCHIMIE = XRegExp("@roll\\[" + REGEX_ALCHIMIE_MANIP + "\\s+" + REGEX_ALCHIMIE_TERMES + "\\]", 'giu') | ||||
| const XREGEXP_ROLL_ALCHIMIE_MANIP = XRegExp("@" + REGEX_ALCHIMIE_MANIP + "\\{" + REGEX_ALCHIMIE_TERMES + "\\}", 'giu') | ||||
|  | ||||
| /** | ||||
|  * classe pour gérer les jets d'alchimie | ||||
|  */ | ||||
| export class TextRollAlchimie { | ||||
|   get code() { return 'alchimie' } | ||||
|   get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-alchimie.hbs` } | ||||
|  | ||||
|   async onReplaceRoll(context) { | ||||
|     const handler = new AlchimieTextBuilder(context) | ||||
|     return await handler.replaceAll() | ||||
|   } | ||||
|  | ||||
|   async onRollText(event, actor) { | ||||
|     actor = this.getSelectedActor(actor) | ||||
|     if (actor) { | ||||
|       const node = TextRollManager.getNode(event) | ||||
|       const recetteId = node.data('recetteid') | ||||
|       const manip = node.data('manip') | ||||
|       const termes = node.data('termes') | ||||
|       if (recetteId) { | ||||
|         await actor.effectuerTacheAlchimie(recetteId, manip, termes) | ||||
|       } | ||||
|       else { | ||||
|         const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip)) | ||||
|         const diff = RdDAlchimie.getDifficulte(termes) | ||||
|         await actor.rollCaracCompetence(carac.code, 'Alchimie', diff) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getSelectedActor(actor) { | ||||
|     actor = actor ?? RdDUtility.getSelectedActor() | ||||
|     if (actor && actor.type == ACTOR_TYPES.personnage) { | ||||
|       return actor | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
| } | ||||
|  | ||||
| class AlchimieTextBuilder { | ||||
|   constructor(context) { | ||||
|     this.context = context | ||||
|   } | ||||
|  | ||||
|   async replaceAll() { | ||||
|     await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE, async (rollMatch, i) => await this.replaceMatch(rollMatch, i)) | ||||
|     await XRegExp.forEach(this.context.text, XREGEXP_ROLL_ALCHIMIE_MANIP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i)) | ||||
|     return this.context.text | ||||
|   } | ||||
|  | ||||
|   async replaceMatch(rollMatch, i) { | ||||
|     if (rollMatch.termes && rollMatch.manip) { | ||||
|       const manip = rollMatch.manip | ||||
|       const termes = rollMatch.termes | ||||
|       const carac = RdDCarac.caracDetails(RdDAlchimie.getCaracTache(manip)) | ||||
|       const diff = RdDAlchimie.getDifficulte(termes) | ||||
|       const recette = (this.context.object instanceof Item && this.context.object.type == ITEM_TYPES.recettealchimique) ? this.context.object : undefined | ||||
|       const replacement = await TextRollManager.createRollText(this.context, | ||||
|         { | ||||
|           code: this.context.code, | ||||
|           manip, termes, carac, diff, recetteid: recette?.id, | ||||
|         }) | ||||
|       this.context.text = this.context.text.replace(rollMatch[0], replacement); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										98
									
								
								module/apps/textroll/text-roll-carac-competence.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								module/apps/textroll/text-roll-carac-competence.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| import "../xregexp-all.js"; | ||||
| import { RdDCarac } from "../../rdd-carac.js"; | ||||
| import { RdDItemCompetence } from "../../item-competence.js"; | ||||
| import { RdDUtility } from "../../rdd-utility.js"; | ||||
| import { TextRollManager } from "./text-roll-formatter.js"; | ||||
|  | ||||
| const REGECP_CARAC = "(?<carac>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+)" | ||||
| const REGEXP_COMP = "(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ\\s\\-]+))?" | ||||
| const REGEXP_DIFF = "(/(?<diff>[\\+\\-]?\\d+(d\\d+)?))?" | ||||
| const REGEXP_ROLL_CARAC_COMP = REGECP_CARAC + REGEXP_COMP + REGEXP_DIFF | ||||
| const XREGEXP_ROLL_CARAC_COMP = XRegExp("@roll\\[" + REGEXP_ROLL_CARAC_COMP + "\\]", 'giu') | ||||
|  | ||||
| /** | ||||
|  * classe pour gérer les jets de caractéristique/compétence depuis | ||||
|  * les journaux/descriptions | ||||
|  */ | ||||
| export class TextRollCaracCompetence { | ||||
|   get code() { return 'carac' } | ||||
|   get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-carac-competence.hbs` } | ||||
|  | ||||
|   async onReplaceRoll(context) { | ||||
|     const handler = new CaracCompetenceTextBuilder(context) | ||||
|     return await handler.replaceAll() | ||||
|   } | ||||
|  | ||||
|   async onRollText(event, actor) { | ||||
|     const node = TextRollManager.getNode(event) | ||||
|     const caracCode = node.data('carac-code') | ||||
|     if (caracCode) { | ||||
|       const competence = node.data('competence') | ||||
|       const diff = await this.calculDiff(node) | ||||
|       const actors = this.getSelectedActors(actor) | ||||
|       actors.forEach(async it => await this.doRoll(it, caracCode, competence, diff)) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async calculDiff(node) { | ||||
|     const diff = node.data('diff') ?? 0 | ||||
|     if (!Number.isInteger(diff)) { | ||||
|       const roll = new Roll(diff) | ||||
|       await roll.evaluate() | ||||
|       await roll.toMessage({ flavor: `La difficulté de ${diff} a donné ${roll.total}` }) | ||||
|       return roll.total | ||||
|     } | ||||
|     return diff | ||||
|   } | ||||
|  | ||||
|   async doRoll(actor, caracCode, competence, diff) { | ||||
|     caracCode = actor.mapCarac(caracCode) | ||||
|     if (caracCode) { | ||||
|       if (competence) { | ||||
|         await actor.rollCaracCompetence(caracCode, competence, diff) | ||||
|       } | ||||
|       else { | ||||
|         await actor.rollCarac(caracCode, { diff }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getSelectedActors(actor) { | ||||
|     const selected = canvas.tokens.controlled.map(it => it.actor).filter(it => it) | ||||
|     if (selected.length > 0) { | ||||
|       return selected | ||||
|     } | ||||
|     actor = actor ?? RdDUtility.getSelectedActor() | ||||
|     if (actor) { | ||||
|       return [actor] | ||||
|     } | ||||
|     return [] | ||||
|   } | ||||
| } | ||||
|  | ||||
| class CaracCompetenceTextBuilder { | ||||
|   constructor(context) { | ||||
|     this.context = context | ||||
|   } | ||||
|  | ||||
|   async replaceAll() { | ||||
|     await XRegExp.forEach(this.context.text, XREGEXP_ROLL_CARAC_COMP, async (rollMatch, i) => await this.replaceMatch(rollMatch, i)) | ||||
|     return this.context.text | ||||
|   } | ||||
|  | ||||
|   async replaceMatch(rollMatch, i) { | ||||
|     const carac = RdDCarac.caracDetails(rollMatch.carac) | ||||
|     if (carac) { | ||||
|       const competence = rollMatch.competence ? RdDItemCompetence.findCompetence(this.context.competences, rollMatch.competence) : undefined | ||||
|       const replacement = await TextRollManager.createRollText(this.context, | ||||
|         { | ||||
|           code: this.context.code, | ||||
|           carac: carac, | ||||
|           competence: competence?.name, | ||||
|           diff: rollMatch.diff, | ||||
|         }) | ||||
|       this.context.text = this.context.text.replace(rollMatch[0], replacement) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										13
									
								
								module/apps/textroll/text-roll-formatter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								module/apps/textroll/text-roll-formatter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
|  | ||||
| export class TextRollManager { | ||||
|  | ||||
|   static async createRollText(context, param) { | ||||
|     return await renderTemplate(context.template, { | ||||
|       param, options: context.options | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   static getNode(event) { | ||||
|     return $(event.currentTarget)?.parents(".roll-text-link"); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										51
									
								
								module/apps/textroll/text-roll-formula.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								module/apps/textroll/text-roll-formula.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| import "../xregexp-all.js"; | ||||
| import { TextRollManager } from "./text-roll-formatter.js"; | ||||
|  | ||||
| const REGEXP_ROLL_FORMULA = "(?<formula>[^\\[\\]]+)" | ||||
| const XREGEXP_ROLL_FORMULA = XRegExp("@roll\\[" + REGEXP_ROLL_FORMULA + "\\]", 'giu') | ||||
|  | ||||
| /** | ||||
|  * classe pour gérer les jets de dés (formules Foundry) | ||||
|  */ | ||||
| export class TextRollFormula { | ||||
|   get code() { return 'formula' } | ||||
|   get template() { return `systems/foundryvtt-reve-de-dragon/templates/apps/textroll/link-text-roll-formula.hbs` } | ||||
|  | ||||
|   async onReplaceRoll(context) { | ||||
|     const handler = new FormulaTextBuilder(context) | ||||
|     return await handler.replaceAll() | ||||
|   } | ||||
|  | ||||
|   async onRollText(event, actor) { | ||||
|     const node = TextRollManager.getNode(event) | ||||
|     const rollFormula = node.data('roll-formula') | ||||
|     if (rollFormula) { | ||||
|       const roll = new Roll(rollFormula) | ||||
|       await roll.evaluate() | ||||
|       await roll.toMessage() | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| class FormulaTextBuilder { | ||||
|   constructor(context) { | ||||
|     this.context = context | ||||
|   } | ||||
|  | ||||
|   async replaceAll() { | ||||
|     await XRegExp.forEach(this.context.text, XREGEXP_ROLL_FORMULA, | ||||
|       async (rollMatch, i) => await this.replaceMatch(rollMatch, i)) | ||||
|     return this.context.text | ||||
|   } | ||||
|  | ||||
|   async replaceMatch(rollMatch, i) { | ||||
|     if (rollMatch.formula) { | ||||
|       const replacement = await TextRollManager.createRollText(this.context, | ||||
|         { | ||||
|           code: this.context.code, | ||||
|           formula: rollMatch.formula, | ||||
|         }) | ||||
|       this.context.text = this.context.text.replace(rollMatch[0], replacement) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -2002,7 +2002,7 @@ XRegExp.exec = function (str, regex, pos, sticky) { | ||||
|  */ | ||||
|  | ||||
|  | ||||
| XRegExp.forEach = function (str, regex, callback) { | ||||
| XRegExp.forEach = async function (str, regex, callback) { | ||||
|   var pos = 0; | ||||
|   var i = -1; | ||||
|   var match; | ||||
| @@ -2014,7 +2014,7 @@ XRegExp.forEach = function (str, regex, callback) { | ||||
|     // at least. Actually, because of the way `XRegExp.exec` caches globalized versions of | ||||
|     // regexes, mutating the regex will not have any effect on the iteration or matched strings, | ||||
|     // which is a nice side effect that brings extra safety. | ||||
|     callback(match, ++i, str, regex); | ||||
|     await callback(match, ++i, str, regex); | ||||
|     pos = match.index + (match[0].length || 1); | ||||
|   } | ||||
| }; | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| import { Misc } from "./misc.js"; | ||||
| import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
|  | ||||
|  | ||||
| /** | ||||
| @@ -198,6 +199,7 @@ export class ChatUtility { | ||||
|   static async onCreateChatMessage(chatMessage, options, id) { | ||||
|     if (chatMessage.isAuthor) { | ||||
|       await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp()); | ||||
|       await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, {showLink:false}) }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import { RdDBaseActor } from "../actor/base-actor.js"; | ||||
| import { ChatUtility } from "../chat-utility.js"; | ||||
| import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; | ||||
|  | ||||
| const INFO_COEUR = 'info-coeur'; | ||||
|  | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon'; | ||||
| export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon'; | ||||
| export const LOG_HEAD = 'RdD | '; | ||||
| export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon' | ||||
| export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon' | ||||
| export const LOG_HEAD = 'RdD | ' | ||||
|  | ||||
| export const HIDE_DICE = 'hide'; | ||||
| export const SHOW_DICE = 'show'; | ||||
| export const HIDE_DICE = 'hide' | ||||
| export const SHOW_DICE = 'show' | ||||
|  | ||||
| export const ENTITE_INCARNE = 'incarne'; | ||||
| export const ENTITE_NONINCARNE = 'nonincarne'; | ||||
| export const ENTITE_BLURETTE = 'blurette'; | ||||
| export const ENTITE_INCARNE = 'incarne' | ||||
| export const ENTITE_NONINCARNE = 'nonincarne' | ||||
| export const ENTITE_BLURETTE = 'blurette' | ||||
|  | ||||
| export const RDD_CONFIG = { | ||||
|   niveauEthylisme : [ | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import { RdDItemSort } from "./item-sort.js"; | ||||
| import { RdDUtility } from "./rdd-utility.js"; | ||||
| import { RdDAlchimie } from "./rdd-alchimie.js"; | ||||
| import { RdDItemCompetence } from "./item-competence.js"; | ||||
| import { RdDHerbes } from "./rdd-herbes.js"; | ||||
| import { RdDGemme } from "./rdd-gemme.js"; | ||||
| @@ -12,8 +11,9 @@ import { SystemCompendiums } from "./settings/system-compendiums.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
| import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; | ||||
| import { ITEM_TYPES, RdDItem } from "./item.js"; | ||||
| import { ACTOR_TYPES, ITEM_TYPES, RdDItem } from "./item.js"; | ||||
| import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
|  | ||||
| /** | ||||
|  * Extend the basic ItemSheet for RdD specific items | ||||
| @@ -97,11 +97,11 @@ export class RdDItemSheet extends ItemSheet { | ||||
|       name: this.item.name, | ||||
|       system: this.item.system, | ||||
|       actorId: this.actor?.id, | ||||
|       description: await TextEditor.enrichHTML(this.item.system.description, { async: true }), | ||||
|       descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }), | ||||
|       description: await RdDTextEditor.enrichHTML(this.item.system.description, this.item), | ||||
|       descriptionmj: await RdDTextEditor.enrichHTML(this.item.system.descriptionmj, this.item), | ||||
|       isComestible: this.item.getUtilisationCuisine(), | ||||
|       options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable), | ||||
|       competences: await SystemCompendiums.getCompetences('personnage'), | ||||
|       competences: await SystemCompendiums.getCompetences(ACTOR_TYPES.personnage), | ||||
|       categories: RdDItem.getCategories(this.item.type), | ||||
|     } | ||||
|  | ||||
| @@ -120,18 +120,17 @@ export class RdDItemSheet extends ItemSheet { | ||||
|       formData.competences = formData.competences.filter(it => it.isCompetenceArme()) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.recettecuisine) { | ||||
|       formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true }) | ||||
|       formData.ingredients = await RdDTextEditor.enrichHTML(this.item.system.ingredients, this.item) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.extraitpoetique) { | ||||
|       formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true }) | ||||
|       formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true }) | ||||
|       formData.extrait = await RdDTextEditor.enrichHTML(this.item.system.extrait, this.item) | ||||
|       formData.texte = await RdDTextEditor.enrichHTML(this.item.system.texte, this.item) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.recettealchimique) { | ||||
|       RdDAlchimie.processManipulation(this.item, this.actor?.id); | ||||
|       formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true }) | ||||
|       formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true }) | ||||
|       formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true }) | ||||
|       formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true }) | ||||
|       formData.manipulation = await RdDTextEditor.enrichHTML(this.item.system.manipulation, this.item) | ||||
|       formData.utilisation = await RdDTextEditor.enrichHTML(this.item.system.utilisation, this.item) | ||||
|       formData.enchantement = await RdDTextEditor.enrichHTML(this.item.system.enchantement, this.item) | ||||
|       formData.sureffet = await RdDTextEditor.enrichHTML(this.item.system.sureffet, this.item) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.gemme) { | ||||
|       formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); | ||||
| @@ -207,17 +206,8 @@ export class RdDItemSheet extends ItemSheet { | ||||
|     this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item)); | ||||
|     this.html.find('input[name="system.cacher_points_de_tache"]').change(async event => await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked })); | ||||
|  | ||||
|     this.html.find('.alchimie-tache a').click((event) => { | ||||
|       let actor = this._getEventActor(event); | ||||
|       if (actor) { | ||||
|         let recetteId = event.currentTarget.attributes['data-recette-id'].value; | ||||
|         let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value; | ||||
|         let tacheData = event.currentTarget.attributes['data-alchimie-data'].value; | ||||
|         actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); | ||||
|       } else { | ||||
|         ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique."); | ||||
|       } | ||||
|     }); | ||||
|     this.html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor)) | ||||
|     this.html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event)) | ||||
|  | ||||
|     if (this.actor) { | ||||
|       this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem())); | ||||
| @@ -272,7 +262,7 @@ export class RdDItemSheet extends ItemSheet { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async supprimerBonusCase(deleteCoord){ | ||||
|   async supprimerBonusCase(deleteCoord) { | ||||
|     if (this.item.type == ITEM_TYPES.sort) { | ||||
|       const oldList = RdDItemSort.getBonusCaseList(this.item) | ||||
|       const newList = oldList.filter(it => it.case != deleteCoord); | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { ITEM_TYPES, RdDItem } from "../item.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
| import { LIST_CARAC, RdDCarac } from "../rdd-carac.js"; | ||||
| import { LIST_CARAC_PERSONNAGE, RdDCarac } from "../rdd-carac.js"; | ||||
|  | ||||
| export class RdDItemRace extends RdDItem { | ||||
|  | ||||
| @@ -12,7 +12,7 @@ export class RdDItemRace extends RdDItem { | ||||
|  | ||||
|   static checkRacialMax(actor, code, value) { | ||||
|     const race = RdDItemRace.getRace(actor) | ||||
|     if (code == LIST_CARAC.force.code) { | ||||
|     if (code == LIST_CARAC_PERSONNAGE.force.code) { | ||||
|       if (!race.isForceValid(actor, value)) { | ||||
|         ui.notifications.warn(race.system.carac.force.limitmessage) | ||||
|         return false | ||||
| @@ -55,7 +55,7 @@ export class RdDItemRace extends RdDItem { | ||||
|     if (value == undefined) { | ||||
|       value = path ? foundry.utils.getProperty(actor, path) : 0 | ||||
|     } | ||||
|     if (code == LIST_CARAC.force.code) { | ||||
|     if (code == LIST_CARAC_PERSONNAGE.force.code) { | ||||
|       return value >= this.getForceMax(actor) | ||||
|     } | ||||
|     const max = foundry.utils.getProperty(this, path) ?? -1 | ||||
|   | ||||
| @@ -106,7 +106,7 @@ export class RdDItemSigneDraconique extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   static async randomSigneDescription() { | ||||
|     return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false); | ||||
|     return await RdDRollTables.drawTextFromRollTable("Signes draconiques", {toChat:false}); | ||||
|    } | ||||
|  | ||||
| } | ||||
							
								
								
									
										29
									
								
								module/journal/journal-sheet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								module/journal/journal-sheet.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; | ||||
| import { SYSTEM_RDD } from "../constants.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
|  | ||||
|  | ||||
| export class RdDJournalSheet extends JournalTextPageSheet { | ||||
|   static register() { | ||||
|     DocumentSheetConfig.unregisterSheet(JournalEntryPage, "core", JournalTextPageSheet) | ||||
|     DocumentSheetConfig.registerSheet(JournalEntryPage, | ||||
|       SYSTEM_RDD, | ||||
|       RdDJournalSheet, { | ||||
|       types: ["text"], | ||||
|       makeDefault: true, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   async getData(options) { | ||||
|     const journalData = await super.getData(options); | ||||
|     journalData.editor.content = await RdDTextEditor.enrichHTML(journalData.document.text.content, this.object) | ||||
|     return journalData | ||||
|   } | ||||
|  | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|  | ||||
|     html.find('.roll-text').click(async event => await RdDTextEditor.rollText(event, this.actor)) | ||||
|     html.find('.chat-roll-text').click(async event => await RdDTextEditor.chatRollText(event)) | ||||
|   } | ||||
| } | ||||
| @@ -1,5 +1,12 @@ | ||||
| import { Grammar } from "./grammar.js"; | ||||
|  | ||||
| const DEFAULT_FIND_OPTIONS = { | ||||
|   mapper: it => it.name, | ||||
|   preFilter: it => true, | ||||
|   description: 'valeur', | ||||
|   onMessage: m => ui.notifications.info(m) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * This class is intended as a placeholder for utility methods unrelated | ||||
|  * to actual classes of the game system or of FoundryVTT | ||||
| @@ -209,6 +216,10 @@ export class Misc { | ||||
|   static isFirstConnectedGM() { | ||||
|     return game.user == Misc.firstConnectedGM(); | ||||
|   } | ||||
|    | ||||
|   static hasConnectedGM() { | ||||
|     return Misc.firstConnectedGM(); | ||||
|   } | ||||
|  | ||||
|   static firstConnectedGMId() { | ||||
|     return Misc.firstConnectedGM()?.id; | ||||
| @@ -226,13 +237,7 @@ export class Misc { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static findFirstLike(value, elements, options = {}) { | ||||
|     options = foundry.utils.mergeObject({ | ||||
|       mapper: it => it.name, | ||||
|       preFilter: it => true, | ||||
|       description: 'valeur', | ||||
|       onMessage: m => ui.notifications.info(m) | ||||
|     }, options, { overwrite: true, inplace: false }); | ||||
|  | ||||
|     options = foundry.utils.mergeObject(DEFAULT_FIND_OPTIONS, options, { overwrite: true, inplace: false }); | ||||
|     const subset = this.findAllLike(value, elements, options); | ||||
|     if (subset.length == 0) { | ||||
|       console.log(`Aucune ${options.description} pour ${value}`); | ||||
| @@ -251,13 +256,7 @@ export class Misc { | ||||
|   } | ||||
|  | ||||
|   static findAllLike(value, elements, options = {}) { | ||||
|     options = foundry.utils.mergeObject({ | ||||
|       mapper: it => it.name, | ||||
|       preFilter: it => true, | ||||
|       description: 'valeur', | ||||
|       onMessage: m => ui.notifications.info(m) | ||||
|     }, options); | ||||
|  | ||||
|     options = foundry.utils.mergeObject(DEFAULT_FIND_OPTIONS, options, { overwrite: true, inplace: false }); | ||||
|     if (!value) { | ||||
|       options.onMessage(`Pas de ${options.description} correspondant à une valeur vide`); | ||||
|       return []; | ||||
|   | ||||
| @@ -1,48 +1,8 @@ | ||||
| /* -------------------------------------------- */ | ||||
| import { Misc } from "./misc.js"; | ||||
|  | ||||
| const matchOperations = new RegExp(/@(\w*){([\w\-]+)}/ig); | ||||
| const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i); | ||||
| /* -------------------------------------------- */ | ||||
| export class RdDAlchimie { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static processManipulation(recette, actorId = undefined) { | ||||
|     let manip = recette.system.manipulation; | ||||
|     let matchArray = manip.match(matchOperations); | ||||
|     if (matchArray) { | ||||
|       for (let matchStr of matchArray) { | ||||
|         let result = matchStr.match(matchOperationTerms); | ||||
|         if (result[1] && result[2]) { | ||||
|           let commande = Misc.upperFirst(result[1]); | ||||
|           let replacement = this[`_alchimie${commande}`](recette, result[2], actorId); | ||||
|           manip = manip.replace(result[0], replacement); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     recette.system.manipulation_update = manip; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static _alchimieCouleur(recette, couleurs, actorId) { | ||||
|     return RdDAlchimie._alchimieLink(recette, couleurs, actorId,  'couleur',  'Température'); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static _alchimieConsistance(recette, consistances, actorId) { | ||||
|     return RdDAlchimie._alchimieLink(recette, consistances, actorId,  'consistance',  'Consistance'); | ||||
|   } | ||||
|  | ||||
|   static _alchimieLink(recette, termes, actorId, tacheAlchimie, labelTache) { | ||||
|     const difficulte = RdDAlchimie.getDifficulte(termes); | ||||
|     const link = actorId ? ` <a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="${tacheAlchimie}" data-alchimie-data="${termes}">` : ''; | ||||
|     const endLink = actorId ? '</a>' : ''; | ||||
|     return `<span class="alchimie-tache">${link}${labelTache} ${termes} (${difficulte})${endLink}</span>`; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static getDifficulte(aspects) { | ||||
|     let elements = aspects.split('-'); | ||||
|   static getDifficulte(termes) { | ||||
|     let elements = termes.split('-'); | ||||
|     let composantes = elements.length; | ||||
|     let distincts = Object.keys(Misc.classifyFirst(elements, it => it)).length; | ||||
|     if (distincts == 1) { | ||||
| @@ -58,5 +18,4 @@ export class RdDAlchimie { | ||||
|     } | ||||
|     return 'intellect'; | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -37,7 +37,7 @@ const TABLE_CARACTERISTIQUES_DERIVEES = { | ||||
|   32: { xp: 180, niveau: 11, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 } | ||||
| }; | ||||
|  | ||||
| export const LIST_CARAC = { | ||||
| export const LIST_CARAC_PERSONNAGE = { | ||||
|   'taille': { code: 'taille', label: 'Taille', isCarac: true, path: 'system.carac.taille.value' }, | ||||
|   'apparence': { code: 'apparence', label: 'Apparence', isCarac: true, path: 'system.carac.apparence.value' }, | ||||
|   'constitution': { code: 'constitution', label: 'Constitution', isCarac: true, path: 'system.carac.constitution.value' }, | ||||
| @@ -56,18 +56,43 @@ export const LIST_CARAC = { | ||||
|   'beaute': { code: 'beaute', label: 'Beauté', isCarac: false, path: 'system.background.beaute.value' } | ||||
| } | ||||
|  | ||||
| export const LIST_CARAC_AUTRES = { | ||||
|   'perception': { code: 'perception', label: 'Perception',  path: 'system.carac.perception.value' }, | ||||
| } | ||||
|  | ||||
| const LIST_CARAC_DERIVEE = { | ||||
|   'melee': { code: "melee", label: 'Mêlée', path: 'system.carac.melee.value' }, | ||||
|   'tir': { code: "tir", label: 'Tir', path: 'system.carac.tir.value' }, | ||||
|   'lancer': { code: "lancer", label: 'Lancer', path: 'system.carac.lancer.value' }, | ||||
|   'derobee': { code: "derobee", label: 'Dérobée', path: 'system.carac.derobee.value' }, | ||||
|   'chance-actuelle': { code: "chance-actuelle", label: 'Chance actuelle', path: 'system.carac.lancer.value' }, | ||||
|   'reve-actuel': { code: "reve-actuel", label: 'Rêve actuel', path: 'system.reve.reve.value' }, | ||||
| } | ||||
|  | ||||
| const LIST_CARAC_ROLL = Object.values(LIST_CARAC_PERSONNAGE).filter(it => it.isCarac && it.code != 'taille') | ||||
|   .concat(Object.values(LIST_CARAC_AUTRES)) | ||||
|   .concat(Object.values(LIST_CARAC_DERIVEE)) | ||||
|  | ||||
| export class RdDCarac { | ||||
|  | ||||
|   static caracDetails(name) { | ||||
|     let entry = Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.code, description: 'caractéristique', onMessage: m => { } }) | ||||
|     if (entry) { | ||||
|       return entry | ||||
|     } | ||||
|     return Misc.findFirstLike(name, LIST_CARAC_ROLL, { mapper: it => it.label, description: 'caractéristique' }) | ||||
|   } | ||||
|  | ||||
|   static carac(code) { | ||||
|     return LIST_CARAC[code] | ||||
|     return LIST_CARAC_PERSONNAGE[code] | ||||
|   } | ||||
|  | ||||
|   static label(code) { | ||||
|     return  RdDCarac.carac(code)?.label ?? '---' | ||||
|   }   | ||||
|     return RdDCarac.carac(code)?.label ?? '---' | ||||
|   } | ||||
|  | ||||
|   static caracs(filter = it => it.isCarac) { | ||||
|     return Object.values(LIST_CARAC).filter(filter) | ||||
|     return Object.values(LIST_CARAC_PERSONNAGE).filter(filter) | ||||
|   } | ||||
|  | ||||
|   static isAgiliteOuDerobee(selectedCarac) { | ||||
|   | ||||
| @@ -472,15 +472,15 @@ export class RdDCombat { | ||||
|   /* -------------------------------------------- */ | ||||
|   static registerChatCallbacks(html) { | ||||
|     for (let button of [ | ||||
|       '#parer-button', | ||||
|       '#esquiver-button', | ||||
|       '#particuliere-attaque', | ||||
|       '#encaisser-button', | ||||
|       '#appel-chance-defense', | ||||
|       '#appel-destinee-defense', | ||||
|       '#appel-chance-attaque', | ||||
|       '#appel-destinee-attaque', | ||||
|       '#echec-total-attaque', | ||||
|       '.parer-button', | ||||
|       '.esquiver-button', | ||||
|       '.particuliere-attaque', | ||||
|       '.encaisser-button', | ||||
|       '.appel-chance-defense', | ||||
|       '.appel-destinee-defense', | ||||
|       '.appel-chance-attaque', | ||||
|       '.appel-destinee-attaque', | ||||
|       '.echec-total-attaque', | ||||
|     ]) { | ||||
|       html.on("click", button, event => { | ||||
|         const rddCombat = RdDCombat.rddCombatForAttackerAndDefender( | ||||
| @@ -539,22 +539,22 @@ export class RdDCombat { | ||||
|     const compId = event.currentTarget.attributes['data-compid']?.value; | ||||
|  | ||||
|     switch (button) { | ||||
|       case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); | ||||
|       case '#parer-button': return this.parade(attackerRoll, armeParadeId); | ||||
|       case '#esquiver-button': return this.esquive(attackerRoll, compId, competence); | ||||
|       case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll); | ||||
|       case '#echec-total-attaque': return this._onEchecTotal(attackerRoll); | ||||
|       case '.particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); | ||||
|       case '.parer-button': return this.parade(attackerRoll, armeParadeId); | ||||
|       case '.esquiver-button': return this.esquive(attackerRoll, compId, competence); | ||||
|       case '0encaisser-button': return this.encaisser(attackerRoll, defenderRoll); | ||||
|       case '.echec-total-attaque': return this._onEchecTotal(attackerRoll); | ||||
|  | ||||
|       case '#appel-chance-attaque': return this.attacker.rollAppelChance( | ||||
|       case '.appel-chance-attaque': return this.attacker.rollAppelChance( | ||||
|         () => this.attaqueChanceuse(attackerRoll), | ||||
|         () => this._onEchecTotal(attackerRoll)); | ||||
|       case '#appel-chance-defense': return this.defender.rollAppelChance( | ||||
|       case '.appel-chance-defense': return this.defender.rollAppelChance( | ||||
|         () => this.defenseChanceuse(attackerRoll, defenderRoll), | ||||
|         () => this.afficherOptionsDefense(attackerRoll, defenderRoll, { defenseChance: true })); | ||||
|       case '#appel-destinee-attaque': return this.attacker.appelDestinee( | ||||
|       case '.appel-destinee-attaque': return this.attacker.appelDestinee( | ||||
|         () => this.attaqueSignificative(attackerRoll), | ||||
|         () => { }); | ||||
|       case '#appel-destinee-defense': return this.defender.appelDestinee( | ||||
|       case '.appel-destinee-defense': return this.defender.appelDestinee( | ||||
|         () => this.defenseDestinee(defenderRoll), | ||||
|         () => { }); | ||||
|     } | ||||
| @@ -967,7 +967,6 @@ export class RdDCombat { | ||||
|   async _onAttaqueEchec(rollData) { | ||||
|     console.log("RdDCombat.onAttaqueEchec >>>", rollData); | ||||
|     await RdDResolutionTable.displayRollData(rollData, this.attacker, 'chat-resultat-attaque.html'); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   | ||||
| @@ -75,6 +75,8 @@ import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium | ||||
| import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js" | ||||
| import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js" | ||||
| import { RdDStatBlockParser } from "./apps/rdd-import-stats.js" | ||||
| import { RdDJournalSheet } from "./journal/journal-sheet.js" | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js" | ||||
|  | ||||
| /** | ||||
|  * RdD system | ||||
| @@ -128,7 +130,7 @@ export class SystemReveDeDragon { | ||||
|     console.log(`Initializing Reve de Dragon System Settings`) | ||||
|  | ||||
|     // preload handlebars templates | ||||
|     RdDUtility.preloadHandlebarsTemplates() | ||||
|     await RdDUtility.preloadHandlebarsTemplates() | ||||
|     AppPersonnageAleatoire.preloadHandlebars() | ||||
|     RdDItemSort.preloadHandlebars() | ||||
|  | ||||
| @@ -196,6 +198,7 @@ export class SystemReveDeDragon { | ||||
|     RdDItemSheet.register(RdDIngredientItemSheet) | ||||
|     RdDItemSheet.register(RdDServiceItemSheet) | ||||
|     RdDItemSheet.register(RdDBlessureItemSheet) | ||||
|     RdDJournalSheet.register() | ||||
|  | ||||
|     Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, { | ||||
|       types: [ | ||||
|   | ||||
| @@ -8,6 +8,7 @@ import { RdDCarac } from "./rdd-carac.js"; | ||||
| import { RdDResolutionTable } from "./rdd-resolution-table.js"; | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { ACTOR_TYPES } from "./item.js"; | ||||
|  | ||||
| /** | ||||
|  * Extend the base Dialog entity to select roll parameters | ||||
| @@ -62,7 +63,7 @@ export class RdDRoll extends Dialog { | ||||
|       forceDiceResult: -1 | ||||
|     } | ||||
|     // Mini patch :Ajout du rêve actuel | ||||
|     if (actor.system.type == "personnage") { | ||||
|     if (actor.type == ACTOR_TYPES.personnage) { | ||||
|       defaultRollData.carac["reve-actuel"] = actor.system.reve.reve | ||||
|     } | ||||
|  | ||||
| @@ -131,11 +132,12 @@ export class RdDRoll extends Dialog { | ||||
|     console.log('RdDRoll.activateListeners', this.rollData); | ||||
|  | ||||
|     // Update html, according to rollData | ||||
|     if (this.rollData.competence) { | ||||
|       const defaut_carac = this.rollData.competence.system.defaut_carac | ||||
|     if (!this.rollData.selectedCarac && this.rollData.competence) { | ||||
|       // Set the default carac from the competence item | ||||
|       this.rollData.selectedCarac = this.rollData.carac[defaut_carac]; | ||||
|       this.html.find("[name='carac']").val(defaut_carac); | ||||
|       this.rollData.selectedCarac = this.rollData.carac[this.actor.mapCarac(this.rollData.competence.system.defaut_carac)] | ||||
|     } | ||||
|     if (this.rollData.selectedCarac) { | ||||
|       this.html.find("[name='carac']").val(RdDCarac.caracDetails(this.rollData.selectedCarac.label).code) | ||||
|     } | ||||
|     if (this.rollData.selectedSort) { | ||||
|       this.setSelectedSort(this.rollData.selectedSort); | ||||
| @@ -173,7 +175,7 @@ export class RdDRoll extends Dialog { | ||||
|       this.updateRollResult(html); | ||||
|       this.html.find("[name='diffLibre']").val(this.rollData.diffLibre); | ||||
|     }); | ||||
|     this.html.find('.roll-carac-competence').change((event) => { | ||||
|     this.html.find('.roll-text').change((event) => { | ||||
|       const competence = event.currentTarget.value | ||||
|       this.rollData.competence = this.rollData.competences.find(it => Grammar.equalsInsensitive(it.name, competence)) | ||||
|       this.updateRollResult(html); | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
| import { CompendiumTable, CompendiumTableHelpers, SystemCompendiums } from "./settings/system-compendiums.js"; | ||||
|  | ||||
| export class RdDRollTables { | ||||
| @@ -28,8 +29,8 @@ export class RdDRollTables { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async drawTextFromRollTable(tableName, toChat) { | ||||
|     const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat); | ||||
|   static async drawTextFromRollTable(tableName, options = {}) { | ||||
|     const drawResult = await RdDRollTables.genericGetTableResult(tableName, options.toChat); | ||||
|     return drawResult.text; | ||||
|   } | ||||
|  | ||||
| @@ -103,7 +104,7 @@ export class RdDRollTables { | ||||
|   static async getMaladresse(options = { toChat: false, arme: false }) { | ||||
|     return await RdDRollTables.drawTextFromRollTable( | ||||
|       options.arme ? "Maladresse armé" : "Maladresses non armé", | ||||
|       options.toChat); | ||||
|       options) | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -22,6 +22,7 @@ import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js"; | ||||
| import { RDD_CONFIG } from "./constants.js"; | ||||
| import { RdDBaseActor } from "./actor/base-actor.js"; | ||||
| import { RdDCarac } from "./rdd-carac.js"; | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| // This table starts at 0 -> niveau -10 | ||||
| @@ -289,7 +290,8 @@ export class RdDUtility { | ||||
|     Handlebars.registerHelper('grammar-apostrophe', (article, str) => Grammar.apostrophe(article, str)); | ||||
|     Handlebars.registerHelper('grammar-un', str => Grammar.articleIndetermine(str)); | ||||
|     Handlebars.registerHelper('grammar-accord', (genre, ...args) => Grammar.accord(genre, args)); | ||||
|      | ||||
|     Handlebars.registerHelper('json-stringify', object => JSON.stringify(object)) | ||||
|  | ||||
|     // math | ||||
|     Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); | ||||
|     Handlebars.registerHelper('repeat', function(n, block) { | ||||
| @@ -339,7 +341,7 @@ export class RdDUtility { | ||||
|     Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type)); | ||||
|     Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord)); | ||||
|  | ||||
|     return loadTemplates(templatePaths); | ||||
|     await loadTemplates(templatePaths); | ||||
|   } | ||||
|  | ||||
|   static getItem(itemId, actorId = undefined) { | ||||
| @@ -695,6 +697,7 @@ export class RdDUtility { | ||||
|     RdDCombat.registerChatCallbacks(html) | ||||
|     RdDEmpoignade.registerChatCallbacks(html) | ||||
|     RdDCoeur.registerChatCallbacks(html) | ||||
|     RdDTextEditor.registerChatCallbacks(html) | ||||
|  | ||||
|     // Gestion spécifique message passeurs | ||||
|     html.on("click", '.tmr-passeur-coord a', event => { | ||||
|   | ||||
| @@ -184,16 +184,16 @@ system: | ||||
|       value: '+0' | ||||
|       label: +dom | ||||
|       derivee: true | ||||
|     vitesse: | ||||
|       type: string | ||||
|       value: 12/28 | ||||
|       label: Vitesse | ||||
|       derivee: true | ||||
|     encombrement: | ||||
|       type: number | ||||
|       value: 0 | ||||
|       label: Encombrement | ||||
|       derivee: false | ||||
|     vitesse: | ||||
|       type: string | ||||
|       value: 12/28 | ||||
|       label: Vitesse | ||||
|       derivee: true | ||||
|     protection: | ||||
|       type: number | ||||
|       value: 4 | ||||
| @@ -207,28 +207,19 @@ system: | ||||
|       value: 0 | ||||
|       label: Sur-encombrement | ||||
|   description: >- | ||||
|     <h1>Description</h1> | ||||
|  | ||||
|     <p>Description Le chrasme (prononcer krasme) est une sorte de cafard | ||||
|     géant à carapace de crabe aux jointures poilues. Il mesure en | ||||
|     moyenne 1 m de haut sur 1m50 de long, et peut peser jusqu’à 50 | ||||
|     kg. Doté de mandibules acérées et puissantes, il est | ||||
|     redouté pour son venin mortel.</p> | ||||
|  | ||||
|     <h1>Mœurs</h1> | ||||
|  | ||||
|     <p>Le chrasme vit dans les lieux sombres, cavernes et souterrains, où | ||||
|     il se nourrit de tout. Paranos le Moindre affirme qu’à | ||||
|     défaut d’une meilleure chère, il peut même se | ||||
|     sustenter de cailloux. Il déteste la lumière comme son cousin | ||||
|     de petite taille, mais a toutefois un comportement différent: au lieu | ||||
|     de fuir, il entre dans une rage féroce et se rue sur le porteur de | ||||
|     lumière pour le réduire en charpie. Savez-vous, cher Paranos, | ||||
|     que vous nous faites un peu peur ?</p> | ||||
|  | ||||
|     <h1>Venin</h1> | ||||
|     <p>@UUID[Compendium.foundryvtt-reve-de-dragon.maladies-et-poisons.Item.cFMUtU6LZG0mKeDl]{Venin | ||||
|     de chrasme}</p> <p></p> | ||||
|     <h1>Description</h1><p>Description Le chrasme (prononcer krasme) est une | ||||
|     sorte de cafard géant à carapace de crabe aux jointures poilues. Il mesure | ||||
|     en moyenne 1 m de haut sur 1m50 de long, et peut peser jusqu’à 50 kg. Doté | ||||
|     de mandibules acérées et puissantes, il est redouté pour son venin | ||||
|     mortel.</p><h1>Mœurs</h1><p>Le chrasme vit dans les lieux sombres, cavernes | ||||
|     et souterrains, où il se nourrit de tout. Paranos le Moindre affirme qu’à | ||||
|     défaut d’une meilleure chère, il peut même se sustenter de cailloux. Il | ||||
|     déteste la lumière comme son cousin de petite taille, mais a toutefois un | ||||
|     comportement différent: au lieu de fuir, il entre dans une rage féroce et se | ||||
|     rue sur le porteur de lumière pour le réduire en charpie. Savez-vous, cher | ||||
|     Paranos, que vous nous faites un peu peur | ||||
|     ?</p><h1>Venin</h1><p>@UUID[Compendium.foundryvtt-reve-de-dragon.maladies-et-poisons.Item.cFMUtU6LZG0mKeDl]{Venin | ||||
|     de chrasme}</p><p></p> | ||||
|   race: '' | ||||
|   notesmj: '' | ||||
| ownership: | ||||
| @@ -311,7 +302,13 @@ prototypeToken: | ||||
|       texture: null | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.32 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736537299708 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| flags: {} | ||||
| _key: '!actors!yL1XStIKWxGnhKvR' | ||||
|  | ||||
|   | ||||
| @@ -203,10 +203,10 @@ system: | ||||
|  | ||||
|     <p>En combat, quand un drakkule réussit une particulière et | ||||
|     cause au moins une blessure légère, il reste accroché | ||||
|     à sa victime qui perd alors automatiquement 1d6 points | ||||
|     à sa victime qui perd alors automatiquement @roll[1d6] points | ||||
|     d’endurance par round sous l’effet de la saignée. Quand | ||||
|     l’endurance tombe à zéro, le drakkule continue à | ||||
|     la vider de son sang à raison de 1d6 points de vie par round. Le | ||||
|     la vider de son sang à raison de @roll[1d6] points de vie par round. Le | ||||
|     drakkule ne se détache que <em>blessé gravement </em>ou | ||||
|     <em>sonné</em>. Pour se dégager, la victime ne peut utiliser | ||||
|     que Corps à corps (totaliser 2 points d’empoignade) ou une | ||||
|   | ||||
| @@ -137,7 +137,7 @@ system: | ||||
|     elles-mêmes, leur grincement involontaire est une torture. Toute | ||||
|     personne se trouvant dans un rayon de 10m doit manquer un jet | ||||
|     d’OUÏE à +5. Si le jet réussit, perte de 1 point | ||||
|     d’endurance, puis jet de VOLONTÉ à -5. Si le jet de | ||||
|     d’endurance, puis jet de @roll[volonté/-5]. Si le jet de | ||||
|     VOLONTÉ échoue, le personnage est sonné | ||||
|     jusqu’à la fin du round suivant.</p> | ||||
|  | ||||
|   | ||||
| @@ -174,8 +174,8 @@ system: | ||||
|     agressivité s’appliquant aux humanoïdes. S’agissant | ||||
|     d’un pouvoir inné, elles n’ont ni à monter dans | ||||
|     les TMR, ni à dépenser de points de rêve. La victime | ||||
|     doit jouer un jet de résistance standard, r-8, et en cas | ||||
|     d’échec, réussir un jet de VOLONTÉ à -3 | ||||
|     doit jouer un jet de résistance standard, @roll[reve-actuel/-8], et en cas | ||||
|     d’échec, réussir un jet de @roll[Volonté/-3] | ||||
|     pour pouvoir attaquer la harpie. Le JR n’est à jouer | ||||
|     qu’une seule fois, tandis qu’en cas d’échec, le jet | ||||
|     de VOLONTÉ est à jouer tous les rounds. La non | ||||
|   | ||||
| @@ -201,7 +201,7 @@ system: | ||||
|  | ||||
|     <p>La sirène a un chant attractif pouvant porter jusqu’à | ||||
|     50 m. Toute personne, homme ou femme, percevant ce chant, même faible | ||||
|     et lointain, doit tenter un jet de VOLONTÉ à -3. Sur toute | ||||
|     et lointain, doit tenter un jet de  @roll[Volonté/-3]. Sur toute | ||||
|     réussite, le personnage est libre de sa décision"; sur tout | ||||
|     échec, il est irrésistiblement attiré vers la source du | ||||
|     chant. Quand plusieurs sirènes chantent simultanément, le jet | ||||
| @@ -220,7 +220,7 @@ system: | ||||
|     corps, même visage. Certaines sirènes, plus rarement, donnent | ||||
|     des illusions d’hommes. Contrairement aux illusions des Yeux | ||||
|     d’Hypnos, l’illusion des sirènes donne lieu à un | ||||
|     jet de résistance (standard, r-8). Comme pour les chants, ce JR est | ||||
|     jet de résistance (standard, @roll[reve-actuel/-8]). Comme pour les chants, ce JR est | ||||
|     global : s’il réussit, toutes les sirènes apparaissent | ||||
|     sous leur véritable apparence; s’il échoue, toutes sont | ||||
|     perçues sous leur apparence illusoire.</p> | ||||
|   | ||||
| @@ -228,8 +228,8 @@ system: | ||||
|     désolations et autres lieux où Thanatos a laissé son | ||||
|     empreinte. Ils possèdent le même pouvoir de non | ||||
|     agressivité s’appliquant aux humanoïdes que la harpie. La | ||||
|     victime doit jouer un jet de résistance standard, r-8, et en cas | ||||
|     d’échec, réussir un jet de VOLONTÉ à -3 | ||||
|     victime doit jouer un jet de résistance standard, @roll[reve-actuel/-8], et en cas | ||||
|     d’échec, réussir un jet de @roll[Volonté/-3] | ||||
|     pour pouvoir attaquer le tournedent. Le JR n’est à jouer | ||||
|     qu’une seule fois, et en cas d’échec, le jet de | ||||
|     VOLONTÉ est à jouer tous les rounds. La non agressivité | ||||
|   | ||||
| @@ -17,9 +17,8 @@ system: | ||||
|     à long terme, mais tout autant de l’empathie pour bluffer lors | ||||
|     des surenchères.</p> | ||||
|  | ||||
|     <p>Pour simuler une partie, jouer un jet de CHANCE à zéro | ||||
|     (ajusté astrologiquement), suivi d’un jet d’EMPATHIE/Jeu | ||||
|     à zéro, et additionner les points de tâche obtenus par | ||||
|     <p>Pour simuler une partie, jouer un jet de @roll[chance/0] | ||||
|     (ajusté astrologiquement), suivi d’un jet d’@roll[EMPATHIE/Jeu/0], et additionner les points de tâche obtenus par | ||||
|     les deux jets. Le vainqueur est celui qui en totalise le plus.</p> | ||||
|   descriptionmj: '' | ||||
|   type: carte | ||||
|   | ||||
| @@ -104,7 +104,7 @@ system: | ||||
|     Dès qu’il se sent lésé, offensé, victime | ||||
|     d’un tort même insignifiant, il faut qu’il se venge | ||||
|     et que sa vengeance soit mortelle. Il peut jouer un jet de | ||||
|     VOLONTÉ/ moral à zéro. Si le jet réussit, il | ||||
|     @roll[Volonté/0] (avec moral). Si le jet réussit, il | ||||
|     peut encore laisser couver sa haine ; s’il échoue, il doit agir | ||||
|     immédiatement. Il est conseillé que le gardien des rêves | ||||
|     prenne alors le contrôle du personnage s’il s’agit | ||||
|   | ||||
| @@ -104,7 +104,7 @@ system: | ||||
|     pareille. Son moral tombe directement à -3 et ne pourra pas remonter | ||||
|     tant que durera la possession. Chaque fois qu’une action dangereuse se | ||||
|     présente, incluant toute action de combat y compris l’esquive, | ||||
|     la victime doit jouer un jet de VOLONTÉ/moral à zéro. | ||||
|     la victime doit jouer un jet de @roll[Volonté/0] avec moral. | ||||
|     Si ce jet échoue, la victime ne fait rien que trembler et claquer des | ||||
|     dents.</p> | ||||
|   race: '' | ||||
|   | ||||
| @@ -132,8 +132,8 @@ system: | ||||
|     les désolations et les ruines. Il combat avec son bec | ||||
|     acéré. Outre les dommages qu’il cause (+dom +1), chaque | ||||
|     fois qu’il porte un coup, même une simple | ||||
|     contusion-éraflure, sa victime doit réussir un jet de points | ||||
|     de rêve actuels ajusté négativement au niveau de | ||||
|     contusion-éraflure, sa victime doit réussir un jet de @roll[reve-actuel] | ||||
|     ajusté négativement au niveau de | ||||
|     l’entité, ou perdre 1 point de chance. Les points de chance | ||||
|     ainsi perdus peuvent être regagnés selon la règle | ||||
|     normale. Détruite, l’entité ne laisse pour tout vestige | ||||
|   | ||||
| @@ -158,8 +158,8 @@ system: | ||||
|     <p>Les quauquemaires hantent les endroits lugubres et désolés, | ||||
|     les ruines principalement. Ils chantent au coucher du soleil, et leur chant | ||||
|     est si lugubre, prometteur d’angoisse et de cauchemar, que quiconque | ||||
|     l’entend et manque un jet de points de rêve actuels | ||||
|     ajusté négativement au niveau de l’entité, ne | ||||
|     l’entend et manque un jet de points de @roll[reve-actuel] ajusté | ||||
|     négativement au niveau de l’entité, ne | ||||
|     fait que des cauchemars hideux au cours de sa prochaine nuit de sommeil. En | ||||
|     termes de règles, cela signifie : pas de souvenir de | ||||
|     l’archétype et donc pas de jet de stress au matin ; pas de | ||||
|   | ||||
| @@ -134,8 +134,8 @@ system: | ||||
|     nécropoles, catacombes et autres lieux de sépulture. Comme les | ||||
|     autres entités, leur raison d’être est de | ||||
|     détruire. Le spectacle d’un squelette est d’une horreur | ||||
|     tellement contre nature qu’il demande un jet de VOLONTÉ | ||||
|     à -3. En cas d’échec, le personnage est frappé | ||||
|     tellement contre nature qu’il demande un jet de @roll[Volonté/-3]. | ||||
|     En cas d’échec, le personnage est frappé | ||||
|     d’effroi. En termes de règles, il est en demi- surprise | ||||
|     jusqu’à la fin du round suivant. Une fois détruit, les | ||||
|     ossements constitutifs du squelette s’éparpillent sur le sol, | ||||
|   | ||||
| @@ -19,8 +19,8 @@ system: | ||||
|     dans une pipe ou préparée en décoction. Dans les deux | ||||
|     cas, une dose doit être composée de 7 brins. Dès la dose | ||||
|     absorbée (bue ou fumée), le consommateur doit jouer un JR | ||||
|     r-force, c’est-à-dire un jet de points de rêve | ||||
|     ajusté négativement à la force de l’herbe. Si le | ||||
|     r-force, c’est-à-dire un jet de @roll[reve-actuel] ajusté | ||||
|      négativement à la force de l’herbe. Si le | ||||
|     JR réussit, aucun effet ne se produit"; s’il échoue, le | ||||
|     consommateur gagne immédiatement un nombre de points de rêve | ||||
|     égal à la force de l’herbe, puis en échange, | ||||
|   | ||||
| @@ -506,8 +506,8 @@ system: | ||||
|     <p style="box-sizing: border-box; user-select: text; color: #191813; | ||||
|     font-family: CaslonAntique; font-size: 16px; letter-spacing: 1px; | ||||
|     text-align: justify; background-color: #f5f5f0;"><strong style="box-sizing: | ||||
|     border-box; user-select: text;">VOLONTÉ/moral à - | ||||
|     (degré d’exotisme) + (Cuisine)</strong></p> | ||||
|     border-box; user-select: text;">@roll[Volonté/Cuisibe] (avec moral) à - | ||||
|     (degré d’exotisme) </strong></p> | ||||
|  | ||||
|     <p style="box-sizing: border-box; user-select: text; color: #191813; | ||||
|     font-family: CaslonAntique; font-size: 16px; letter-spacing: 1px; | ||||
|   | ||||
| @@ -23,31 +23,29 @@ system: | ||||
|  | ||||
|     <p>Les points de VUE perdus ne peuvent être regagnés que quand | ||||
|     la maladie est entièrement guérie. À chaque point de | ||||
|     vie regagné, jouer un jet de CONSTITUTION ajusté | ||||
|     vie regagné, jouer un jet de @roll[Constitution] ajusté | ||||
|     négativement par les points de vie toujours manquants. Puis selon le | ||||
|     résultat:</p> | ||||
|  | ||||
|     <ul> | ||||
|  | ||||
|     <li><strong><em>Particulière            | ||||
|                       | ||||
|     </em></strong>Regain de 2 points de VUE</li> | ||||
|     <li><strong><em>Particulière</em></strong>  Regain de 2 points | ||||
|     de VUE</li> | ||||
|  | ||||
|     <li><strong><em>Normale et significative</em></strong>      | ||||
|     Regain de 1 point de VUE</li> | ||||
|     <li><strong><em>Normale et significative</em></strong>  Regain de 1 | ||||
|     point de VUE</li> | ||||
|  | ||||
|     <li><strong><em>Échec et Échec particulier</em></strong>  | ||||
|     <li><strong><em>Échec et Échec particulier</em></strong>   | ||||
|     Aucun regain</li> | ||||
|  | ||||
|     <li><strong><em>Échec total</em>          | ||||
|                           | ||||
|     </strong>Aggravation, re-perte d’un point de VUE</li> | ||||
|     <li><strong><em>Échec total</em></strong>  Aggravation, | ||||
|     re-perte d’un point de VUE</li> | ||||
|  | ||||
|     </ul> | ||||
|  | ||||
|     <p>Si tous les points de vie ont été regagnés et | ||||
|     qu’il manque toujours un ou plusieurs points de VUE, jouer un jet de | ||||
|     CONSTITUTION à zéro toutes les 12 heures, et appliquer les | ||||
|     @roll[Constitution/0] toutes les 12 heures, et appliquer les | ||||
|     mêmes résultats que ci-dessus.</p> | ||||
|  | ||||
|     <p>Une potion d’herbes de soin enchantée peut faire regagner | ||||
|   | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -16,10 +16,10 @@ system: | ||||
|  | ||||
|     <p>Il confère un bonus de +5 à tous les jets de | ||||
|     DEXTÉRITÉ, de Tir et de Lancer, et est suivi d’une perte | ||||
|     de 1d6 points d’endurance.</p> | ||||
|     de @roll[1d6] points d’endurance.</p> | ||||
|   enchantement: >- | ||||
|     <p>Si la potion est enchantée, l’effet magique n’a lieu | ||||
|     que si un jet de résistance standard est échoué.</p> | ||||
|     que si un jet de résistance standard @roll[reve-actuel] est échoué.</p> | ||||
|  | ||||
|     <p>L’effet se produit alors dans le round consécutif au jet de | ||||
|     résistance (au lieu de 2 minutes) et voit sa durée | ||||
| @@ -32,8 +32,8 @@ system: | ||||
|     sur-effet se produise  : la perte totale du goût et de | ||||
|     l’odorat (ODORAT-GOÛT tombe à zéro).</p> | ||||
|  | ||||
|     <p>Pour le regain, jouer tous les matins un jet d’ODORAT- GOÛT | ||||
|     (originel) à zéro et regagner selon le barème des | ||||
|     <p>Pour le regain, jouer tous les matins un jet  | ||||
|     @roll[odorat-gout] (originel)et regagner selon le barème des | ||||
|     points de tâche.</p> | ||||
|   manipulation: >- | ||||
|     <ul><li>Piler à froid <strong>2 doigts de graisse de carpe</strong> et | ||||
|   | ||||
| @@ -23,7 +23,8 @@ system: | ||||
|     points d’endurance.</p> | ||||
|   enchantement: >- | ||||
|     <p>Si la potion est enchantée, l’effet magique n’a lieu | ||||
|     que si un jet de résistance standard est échoué.</p> | ||||
|     que si un jet de résistance standard @roll[reve-actuel] est | ||||
|     échoué.</p> | ||||
|  | ||||
|     <p>L’effet se produit alors dans le round consécutif au jet de | ||||
|     résistance (au lieu de 2 minutes) et voit sa durée | ||||
|   | ||||
| @@ -18,8 +18,8 @@ system: | ||||
|  | ||||
|     <p>Si un personnage ainsi rendu dérisoire participe à un combat, il peut | ||||
|     tenter une fois par round de lancer une plaisanterie en guise d’attaque | ||||
|     (tout en esquivant/parant normalement). Il joue pour cela APPARENCE/ Comédie | ||||
|     à -1d4 (ce d4 résume les conditions ponctuelles plus ou moins propices, et | ||||
|     (tout en esquivant/parant normalement). Il joue pour cela @roll[APPARENCE/Comédie/-1d4] | ||||
|     (ce d4 résume les conditions ponctuelles plus ou moins propices, et | ||||
|     il est en fait soustrait du bonus de +4 conféré par le sort). Puis selon la | ||||
|     réussite, on obtient un ajustement :</p> | ||||
|  | ||||
| @@ -56,10 +56,10 @@ system: | ||||
|     </table> | ||||
|  | ||||
|     <p>Tous les autres engagés dans la mêlée capables de comprendre la blague, y | ||||
|     compris les compagnons du plaisantin, jouent alors VOLONTÉ/<em>moins | ||||
|     compris les compagnons du plaisantin, jouent alors @roll[Volonté] <em>moins | ||||
|     </em>moral à + (ajustement) + (Comédie facultativement). Tout échec provoque | ||||
|     un état de demi-surprise pour la fin du round et tout le round suivant. En | ||||
|     cas d’échec total à son jet d’APPARENCE/Comédie, le plaisantin est le seul à | ||||
|     cas d’échec total à son jet d’@roll[Apparence/Comédie], le plaisantin est le seul à | ||||
|     rire de sa blague, et entre automatiquement en demi-surprise jusqu’à la fin | ||||
|     du round suivant.</p> | ||||
|   descriptionmj: '' | ||||
|   | ||||
| @@ -7,7 +7,7 @@ system: | ||||
|   description: >- | ||||
|     <p>Ce sort provoque l’illusion d’une grande fatigue, qui est interprétée | ||||
|     comme une fatigue réelle. La victime marque instantanément 6 cases de | ||||
|     fatigue, puis joue un jet de VOLONTÉ à -5 avec un éventuel bonus de +1 par | ||||
|     fatigue, puis joue un jet de @roll[Volonté/-5] avec un éventuel bonus de +1 par | ||||
|     point de CONSTITUTION au-dessus de 15. Si le jet de VOLONTÉ réussit, il n’y | ||||
|     a pas d’autre conséquence que les cases de fatigue. Si le jet échoue, tout | ||||
|     dépend alors de l’activité actuelle de la cible. Si elle est en condition de | ||||
|   | ||||
| @@ -9,7 +9,7 @@ system: | ||||
|     humanoïdes. La suggestion d’une idée drolatique plonge la | ||||
|     cible dans un irrépressible fou-rire, automatique le premier round. | ||||
|     Puis pour les rounds suivants, la cible doit réussir un jet de | ||||
|     VOLONTÉ/ <em>moins </em>moral à -5, ou continuer à | ||||
|     @roll[Volonté/-5] <em>moins </em>moral, ou continuer à | ||||
|     rire. Tant que la cible rit, elle est considérée en | ||||
|     <em>demi-surprise</em>.</p> | ||||
|   descriptionmj: '' | ||||
|   | ||||
| @@ -25,7 +25,7 @@ system: | ||||
|     pouvant aller de 0 à 7 (1d8-1). Pour en supporter le goût "étrange et venu | ||||
|     d’ailleurs", les convives doivent réussir un jet de :</p> | ||||
|  | ||||
|     <p><strong>VOLONTÉ/moral à - (degré d’exotisme) + (Cuisine)</strong></p> | ||||
|     <p><strong>@roll[Volonté/Cuisine] (avec moral) à - (degré d’exotisme)</strong></p> | ||||
|  | ||||
|     <p>Si le jet est réussi, le personnage n’est pas choqué par l’exotisme et | ||||
|     peut même en apprécier la gastronomie. Pour tout échec, le personnage est | ||||
|   | ||||
| @@ -7,7 +7,7 @@ system: | ||||
|   description: >- | ||||
|     <p>L’effet de Peur ne s’applique qu’aux humanoïdes. La suggestion d’une | ||||
|     horreur intense cause une peur réelle. La victime doit réussir un jet de | ||||
|     VOLONTÉ à -5 ou être sonnée en cas d’échec. Le jet de VOLONTÉ doit être | ||||
|     @roll[Volonté/-5] ou être sonnée en cas d’échec. Le jet de VOLONTÉ doit être | ||||
|     renouvelé de round en round jusqu’à ce qu’il réussisse. Tant qu’il échoue, | ||||
|     la victime reste en <em>demi-surprise</em>.</p> | ||||
|   descriptionmj: '' | ||||
|   | ||||
| @@ -18,7 +18,7 @@ system: | ||||
|     impossible d’obtenir le sosie parfait de quelqu’un, tout comme il est | ||||
|     difficile à un peintre d’obtenir un portrait parfaitement ressemblant. Si un | ||||
|     haut-rêvant désire donner à sa cible la même apparence que quelqu’un | ||||
|     d’autre, il doit jouer un jet de VUE à -8, et obtiendra une ressemblance | ||||
|     d’autre, il doit jouer un jet de @roll[Vue/-8], et obtiendra une ressemblance | ||||
|     plus ou moins approchante selon son genre de résultat. Inventer un humanoïde | ||||
|     anonyme quoique doté de traits spécifiques (blond, gros nez, une verrue au | ||||
|     menton, etc.) s’obtient sans problème. Comme toujours en ce qui concerne | ||||
|   | ||||
| @@ -18,7 +18,7 @@ system: | ||||
|     @UUID[Compendium.foundryvtt-reve-de-dragon.rappel-des-regles.JournalEntry.ZmMoOtUdgjMd4cNs]{Conflit | ||||
|     de sens}. Le cri illusoire d’un animal doit être le cri d’un animal connu, | ||||
|     et vouloir donner à un humanoïde la même voix que quelqu’un d’autre demande | ||||
|     un jet d’OUÏE à -8, avec les mêmes remarques que pour Transfiguration. Noter | ||||
|     un jet d’@roll[Ouie/-8], avec les mêmes remarques que pour Transfiguration. Noter | ||||
|     que seule la voix est changée, sans affecter en rien le contenu du discours. | ||||
|     Enfin, de même que la taille reste la même pour les illusions visuelles, le | ||||
|     volume sonore de l’illusion auditive est celui de la cible. Une souris ne | ||||
|   | ||||
| @@ -37,9 +37,9 @@ system: | ||||
|     créateur de l'objet et non de l'utilisateur, et quand le sort a une durée | ||||
|     HN, c'est également l'heure de naissance du créateur. Le seul paramétrage | ||||
|     inutile est l'heure de naissance de la cible en prévision du jet de | ||||
|     résistance. Quand un JR est possible, il est toujours r-8, quelle que soit | ||||
|     la cible. S'il réussit, le sort se dissipe aussitôt sans revenir vers | ||||
|     l'utilisateur.</p> | ||||
|     résistance. Quand un JR est possible, il est toujours @roll[reve-actuel/-8], | ||||
|     quelle que soit la cible. S'il réussit, le sort se dissipe aussitôt sans | ||||
|     revenir vers l'utilisateur.</p> | ||||
|  | ||||
|     <p>L'objet réussit son lancer, sans jet de dés. Lancer un sort via un objet | ||||
|     magique n'est pas plus économique en points de rêve que de la lancer | ||||
|   | ||||
| @@ -12,9 +12,9 @@ system: | ||||
|     arrêtant totalement la vue. De l’intérieur, il est | ||||
|     pareillement impossible de voir ce qui se passe à | ||||
|     l’extérieur"; on peut seulement tenter de voir ce qui se passe | ||||
|     à l’intérieur en réussissant un jet de VUE | ||||
|     ajusté négativement par le nombre de points de rêve | ||||
|     dépensés.</p> | ||||
|     à l’intérieur en réussissant un jet de | ||||
|     @roll[Vue] ajusté négativement par le nombre de points de | ||||
|     rêve dépensés.</p> | ||||
|   descriptionmj: '' | ||||
|   draconic: Oniros | ||||
|   duree: HN | ||||
|   | ||||
| @@ -19,7 +19,7 @@ system: | ||||
|     zombis, et contrairement aux entités de cauchemar incarnées qui peuvent | ||||
|     dépasser cette limite, la caractéristique RÊVE d'un squelette invoqué ne | ||||
|     peut jamais dépasser sa caractéristique TAILLE. Sa hideur est telle que | ||||
|     quiconque l'aperçoit doit réussir un jet de VOLONTÉ à -3 ou être en | ||||
|     quiconque l'aperçoit doit réussir un jet de @roll[VOLONTÉ/-3] ou être en | ||||
|     demi-surprise jusqu'à la fin du round suivant.</p> | ||||
|  | ||||
|     <p>Un squelette invoqué est aux ordres de son invocateur et n'agit qu'aux | ||||
|   | ||||
| @@ -13,7 +13,7 @@ system: | ||||
|     à zéro) ou subir en retour l'effet de son sort.</p> | ||||
|  | ||||
|     <p>Le flétrissement n'est pas définitif. Chaque jour, à lextrême fin du | ||||
|     Château Dormant, la victime peur jouer un jet d'APPARENCE à zéro en prenant | ||||
|     Château Dormant, la victime peur jouer un jet d'@roll[APPARENCE/0] en prenant | ||||
|     non pas son APPARENCE actuelle, mais son APPARENCE initiale. Toute réussite | ||||
|     : regain de 1 point en APPARENCE et de 2 points de Beauté. Tout échec : pas | ||||
|     de regain pour aujourd'hui. Dans tous les cas, ni l'APPARENCE ni la Beauté | ||||
|   | ||||
| @@ -10,7 +10,7 @@ system: | ||||
|     maîtrise. Cette dernière est automatique, comme avec les écailles de Narcos, | ||||
|     mais au lieu de coûter des points de rêve, elle coûte un nombre de | ||||
|     <em>points de vie</em> égal au nombre de griffes, chaque point de vie perdu | ||||
|     s'accompagnant d'une perte d'1d6 points d'endurance. Il n'y a pas de jet de | ||||
|     s'accompagnant d'une perte d'@roll[1d6] points d'endurance. Il n'y a pas de jet de | ||||
|     résistance. La maîtrise (et la perte de points de vie) a lieu au moment où | ||||
|     l'objet contenant la griffe est utilisé selon sa fonction : arme frappant, | ||||
|     bague au doigt, bracelet au poignet, etc. Si l'objet n'a pas de fonction | ||||
|   | ||||
| @@ -8,7 +8,7 @@ system: | ||||
|     <p>Le principe de fonctionnement de la griffe morbide de Thanatos est | ||||
|     analogue à celui de la simple griffe. C'en est une variante plus mortelle. | ||||
|     La maîtrise ayant lieu, la victime perd autant de points de vie qu'il y a de | ||||
|     griffes morbides, ainsi que 1d6 points d'endurance par point de vie perdu, | ||||
|     griffes morbides, ainsi que @roll[1d6] points d'endurance par point de vie perdu, | ||||
|     puis joue une JR standard r-8. JR réussi, l'effet s'arrête là ; JR échoué, | ||||
|     le mal s'est implanté en elle. Tous les jours, à l'extrême fin du Château | ||||
|     Dormant, la victime de la griffe morbide doit tenter un jet de Vie et en | ||||
|   | ||||
| @@ -4,7 +4,7 @@ type: souffle | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Le vieillissement est de 1d7 ans. Jouer un jet de Constitution ajusté | ||||
|     <p>Le vieillissement est de 1d7 ans. Jouer un jet de @roll[Constitution] ajusté | ||||
|     négativement au nombre d’années perdues. En cas d’échec, perte définitive | ||||
|     d’un point en Constitution.</p> | ||||
|   descriptionmj: '' | ||||
|   | ||||
| @@ -22,8 +22,9 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à | ||||
|       -1d6 ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir | ||||
|       @roll[Empathie/Vigilance/-1d6] ou être en | ||||
|       demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -39,7 +40,7 @@ results: | ||||
|   - _id: APqyDePFzBaROB6i | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Chute : Encaissement à -1d6 sur la table des Coups non mortels.' | ||||
|     text: 'Chute : Encaissement à @roll[-1d6] sur la table des Coups non mortels.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -72,7 +73,7 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Arme choquée : L’arme utilisée joue un jet de Résistance à -2d6 et perd ce | ||||
|       Arme choquée : L’arme utilisée joue un jet de Résistance à @roll[-2d6] et perd ce | ||||
|       nombre de points de résistance en cas d’échec. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
| @@ -90,7 +91,7 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise | ||||
|       Déséquilibré : Réussir @roll[Agilité/Vigilance/-1d6] ou être en demi-surprise | ||||
|       jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
| @@ -107,7 +108,7 @@ results: | ||||
|   - _id: GOYmqZj1Lnc0cKO9 | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Faux mouvement : Perte de 2d6 points d’endurance.' | ||||
|     text: 'Faux mouvement : Perte de @roll[2d6] points d’endurance.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -124,7 +125,7 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise | ||||
|       Déséquilibré : Réussir @roll[Agilité/Vigilance/-1d6] ou être en demi-surprise | ||||
|       jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
| @@ -142,7 +143,7 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Arme choquée : L’arme utilisée joue un jet de Résistance à -2d6 et perd ce | ||||
|       Arme choquée : L’arme utilisée joue un jet de Résistance à @roll[-2d6] et perd ce | ||||
|       nombre de points de résistance en cas d’échec. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
| @@ -175,7 +176,7 @@ results: | ||||
|   - _id: c61AFRaP9poCmr9B | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Chute : Encaissement à -1d6 sur la table des Coups non mortels.' | ||||
|     text: 'Chute : Encaissement à @roll[-1d6] sur la table des Coups non mortels.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -192,8 +193,9 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à | ||||
|       -1d6 ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir  | ||||
|       @roll[Empathie/Vigilance/-1d6] ou être en | ||||
|       demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
|   | ||||
| @@ -22,8 +22,9 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à | ||||
|       -1d6 ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir | ||||
|       @roll[Empathie/Vigilance/-1d6] ou être en | ||||
|       demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -39,7 +40,7 @@ results: | ||||
|   - _id: 1DtaMqWygL8BjZjw | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Chute : Encaissement à -1d6 sur la table des Coups non mortels.' | ||||
|     text: 'Chute : Encaissement à @roll[-1d6] sur la table des Coups non mortels.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -56,8 +57,8 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise | ||||
|       jusqu’à la fin du round suivant. | ||||
|       Déséquilibré : Réussir @roll[Agilité/Vigilance/-1d6] | ||||
|       ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -73,7 +74,7 @@ results: | ||||
|   - _id: kyAKakRIPGKr6Gdy | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Faux mouvement : Perte de 2d6 points d’endurance.' | ||||
|     text: 'Faux mouvement : Perte de @roll[2d6] points d’endurance.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -90,8 +91,8 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Déséquilibré : Réussir Agilité/Vigilance à -1d6 ou être en demi-surprise | ||||
|       jusqu’à la fin du round suivant. | ||||
|       Déséquilibré : Réussir @roll[Agilité/Vigilance/-1d6] | ||||
|       ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -107,7 +108,7 @@ results: | ||||
|   - _id: NY1uI3k3YbJKQddk | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: 'Chute : Encaissement à -1d6 sur la table des Coups non mortels.' | ||||
|     text: 'Chute : Encaissement à @roll[-1d6] sur la table des Coups non mortels.' | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
| @@ -124,8 +125,9 @@ results: | ||||
|     flags: {} | ||||
|     type: text | ||||
|     text: >- | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir Empathie/Vigilance à | ||||
|       -1d6 ou être en demi-surprise jusqu’à la fin du round suivant. | ||||
|       Ami bousculé : Le compagnon bousculé doit réussir | ||||
|       @roll[Empathie/Vigilance/-1d6] ou être en | ||||
|       demi-surprise jusqu’à la fin du round suivant. | ||||
|     img: icons/svg/d20-black.svg | ||||
|     weight: 1 | ||||
|     range: | ||||
|   | ||||
| @@ -10,7 +10,8 @@ system: | ||||
|     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 | ||||
|     maîtrisée, Fleurs, Messagers et Passeurs ayant une force de @roll[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, | ||||
|   | ||||
| @@ -5,13 +5,13 @@ flags: {} | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Un jet d’Empathie à zéro permet de rendre amical un animal non agressif | ||||
|     ou de rendre neutre un animal agressif. Les animaux restent neutres\amicaux | ||||
|     <p>Un jet d’@roll[empathie/0] permet de rendre amical un animal non agressif | ||||
|     ou de rendre neutre un animal agressif. Les animaux restent neutres/amicaux | ||||
|     jusqu’à ce qu’un événement significatif, agression ou autre, vienne tout | ||||
|     remettre en question. Ce n’est pas un lien magique. Un seul jet par animal. | ||||
|     Un animal rendu neutre par ce don ne peut pas ensuite être rendu amical par | ||||
|     un second jet. Enfin l’étendue de la neutralité\ amitié de l’animal dépend | ||||
|     de chaque espèce et est à décider dans chaque cas particulier par le gardien | ||||
|     un second jet. Enfin l’étendue de la neutralité/amitié de l’animal dépend de | ||||
|     chaque espèce et est à décider dans chaque cas particulier par le gardien | ||||
|     des rêves. Cumulable.</p> | ||||
|   descriptionmj: '' | ||||
|   frequence: 6 | ||||
| @@ -24,7 +24,12 @@ folder: null | ||||
| sort: 0 | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.33 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736617623199 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| _key: '!items!wlbbh75GZWks3Ehb' | ||||
|  | ||||
|   | ||||
| @@ -5,9 +5,9 @@ flags: {} | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Un jet d’Empathie à zéro permet de deviner la direction du nord, et d’une | ||||
|     manière générale de retrouver une certaine direction quand on est perdu ou | ||||
|     par manque de visibilité (nuit, brouillard, souterrain, etc.). | ||||
|     <p>Un jet d’@roll[empathie/0] permet de deviner la direction du nord, et | ||||
|     d’une manière générale de retrouver une certaine direction quand on est | ||||
|     perdu ou par manque de visibilité (nuit, brouillard, souterrain, etc.). | ||||
|     Cumulable.</p> | ||||
|   descriptionmj: '' | ||||
|   frequence: 6 | ||||
| @@ -20,7 +20,12 @@ folder: null | ||||
| sort: 0 | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.33 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736617654367 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| _key: '!items!slnKVCfHbLwbXi4Z' | ||||
|  | ||||
|   | ||||
| @@ -5,10 +5,10 @@ flags: {} | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Un jet de Volonté à zéro permet de s’endormir instantanément et de dormir | ||||
|     au moins jusqu’à la fin de la prochaine heure, même sans aucun point de | ||||
|     fatigue. Permet également de se réveiller au bout d’un laps de temps donné, | ||||
|     "programmé" au moment de s’endormir. Cumulable.</p> | ||||
|     <p>Un jet de @roll[Volonté/0] permet de s’endormir instantanément et de | ||||
|     dormir au moins jusqu’à la fin de la prochaine heure, même sans aucun point | ||||
|     de fatigue. Permet également de se réveiller au bout d’un laps de temps | ||||
|     donné, "programmé" au moment de s’endormir. Cumulable.</p> | ||||
|   descriptionmj: '' | ||||
|   frequence: 6 | ||||
|   hautrevant: false | ||||
| @@ -20,7 +20,12 @@ folder: null | ||||
| sort: 0 | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.33 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736617674311 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| _key: '!items!N6guZDGzzZjt9GrR' | ||||
|  | ||||
|   | ||||
| @@ -5,8 +5,8 @@ flags: {} | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Un jet d’Empathie à zéro permet de deviner que l’on vous ment, sans pour | ||||
|     autant connaître la teneur du mensonge. Ne s’applique qu’au mensonge | ||||
|     <p>Un jet d’@roll[empathie/0] permet de deviner que l’on vous ment, sans | ||||
|     pour autant connaître la teneur du mensonge. Ne s’applique qu’au mensonge | ||||
|     volontaire, pas au mensonge par omission ni par ignorance. Cumulable.</p> | ||||
|   descriptionmj: '' | ||||
|   frequence: 6 | ||||
| @@ -19,7 +19,12 @@ folder: null | ||||
| sort: 0 | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.33 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736617720094 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| _key: '!items!OZZbiBiLlM6Y8lEY' | ||||
|  | ||||
|   | ||||
| @@ -5,10 +5,10 @@ flags: {} | ||||
| img: systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp | ||||
| system: | ||||
|   description: >- | ||||
|     <p>Un jet de VUE à zéro permet de distinguer une aura bleutée délimitant les | ||||
|     zones magiques d’Oniros ou entourant les objets enchantés ou les créatures | ||||
|     soumises à l’effet d’un sort ou d’un rituel. Un seul essai par zone, objet | ||||
|     ou personnage. Cumulable.</p> | ||||
|     <p>Un jet de @roll[vue/0] permet de distinguer une aura bleutée délimitant | ||||
|     les zones magiques d’Oniros ou entourant les objets enchantés ou les | ||||
|     créatures soumises à l’effet d’un sort ou d’un rituel. Un seul essai par | ||||
|     zone, objet ou personnage. Cumulable.</p> | ||||
|   descriptionmj: '' | ||||
|   frequence: 6 | ||||
|   hautrevant: false | ||||
| @@ -20,7 +20,12 @@ folder: null | ||||
| sort: 0 | ||||
| _stats: | ||||
|   systemId: foundryvtt-reve-de-dragon | ||||
|   systemVersion: 12.0.22 | ||||
|   systemVersion: 12.0.33 | ||||
|   coreVersion: '12.331' | ||||
|   createdTime: null | ||||
|   modifiedTime: 1736617743760 | ||||
|   lastModifiedBy: Hp9ImM4o9YRTSdfu | ||||
|   compendiumSource: null | ||||
|   duplicateSource: null | ||||
| _key: '!items!QWouooLkM7pE2yG1' | ||||
|  | ||||
|   | ||||
| @@ -1038,10 +1038,20 @@ a.rdd-world-content-link { | ||||
|   white-space: nowrap; | ||||
|   word-break: break-all; | ||||
| } | ||||
|  | ||||
| span.content-link, | ||||
| a.content-link { | ||||
|   background: hsla(45, 100%, 80%, 0.2); | ||||
|   color: hsla(300, 70%, 20%, 0.8); | ||||
|   font-weight: 560; | ||||
|   padding: 0.1rem 0.3rem; | ||||
|   border: 1px solid var(--color-border-dark-tertiary); | ||||
|   border-radius: 0.25rem; | ||||
|   white-space: nowrap; | ||||
|   word-break: break-all; | ||||
| } | ||||
|  | ||||
|  | ||||
| li label.compteur { | ||||
|   display: inline-block; | ||||
|   flex-direction: row; | ||||
| @@ -1067,14 +1077,6 @@ li label.compteur { | ||||
|   max-width: 90%; | ||||
| } | ||||
|  | ||||
| .alchimie-tache { | ||||
|   font-weight: bold; | ||||
|   background: rgb(182, 180, 179); | ||||
|   border: 1px solid rgba(72, 46, 28, 1); | ||||
|   border-radius: 0.25rem; | ||||
|   color: rgba(212, 27, 27, 0.5); | ||||
| } | ||||
|  | ||||
| .window-app.sheet .window-content .tooltip:hover .tooltiptext { | ||||
|   top: 2rem; | ||||
|   left: 2rem; | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| { | ||||
|   "id": "foundryvtt-reve-de-dragon", | ||||
|   "title": "Rêve de Dragon", | ||||
|   "version": "12.0.32", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.32/rddsystem.zip", | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.32/system.json", | ||||
|   "version": "12.0.34", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.34/rddsystem.zip", | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.34/system.json", | ||||
|   "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", | ||||
|   "compatibility": { | ||||
|     "minimum": "11", | ||||
|   | ||||
| @@ -3,9 +3,9 @@ | ||||
|     "types": ["personnage", "creature", "entite", "commerce", "vehicule"], | ||||
|     "templates": { | ||||
|       "description": { | ||||
|         "description": "Description ...", | ||||
|         "description": "", | ||||
|         "race": "", | ||||
|         "notesmj": "Notes du MJ" | ||||
|         "notesmj": "" | ||||
|       }, | ||||
|       "subacteurs": { | ||||
|         "subacteurs": { | ||||
|   | ||||
							
								
								
									
										0
									
								
								templates/apps/textroll/chat-link-text-roll.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								templates/apps/textroll/chat-link-text-roll.hbs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										13
									
								
								templates/apps/textroll/link-text-roll-alchimie.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								templates/apps/textroll/link-text-roll-alchimie.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| <span class="content-link roll-text-link" | ||||
|     data-code="{{param.code}}" | ||||
|     data-json="{{json-stringify param}}" | ||||
|     data-manip="{{param.manip}}" | ||||
|     data-termes="{{param.termes}}" | ||||
|     {{#if recetteid}}data-recetteid="{{param.recetteid}}"{{/if}}> | ||||
| <a class="roll-text" data-tooltip="{{upperFirst param.carac.label}}/Alchimie à {{param.diff}}"> | ||||
|     {{~param.manip}} {{param.termes~}} | ||||
| </a> | ||||
| {{~#if options.showlink}} | ||||
|  <a class="chat-roll-text" data-tooltip="Montrer"><i class="fas fa-comment"></i></a> | ||||
| {{/if~}} | ||||
| </span> | ||||
							
								
								
									
										14
									
								
								templates/apps/textroll/link-text-roll-carac-competence.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								templates/apps/textroll/link-text-roll-carac-competence.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| <span class="content-link roll-text-link" | ||||
|     data-code="{{param.code}}" | ||||
|     data-json="{{json-stringify param}}" | ||||
|     data-carac-code="{{param.carac.code}}" | ||||
|     {{#if param.competence}}data-competence="{{param.competence}}"{{/if~}} | ||||
|     {{#if param.diff}}data-diff="{{param.diff}}"{{/if~}}> | ||||
| <a class="roll-text"> | ||||
|     {{~uppercase param.carac.label~}} | ||||
|     {{#if param.competence}} / {{upperFirst param.competence}}{{/if~}} | ||||
|     {{#if param.diff}} à {{param.diff}}{{/if~}}</a> | ||||
| {{~#if options.showlink}} | ||||
|  <a class="chat-roll-text" data-tooltip="Montrer"><i class="fas fa-comment"></i></a> | ||||
| {{/if~}} | ||||
| </span> | ||||
							
								
								
									
										9
									
								
								templates/apps/textroll/link-text-roll-formula.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/apps/textroll/link-text-roll-formula.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <span class="content-link roll-text-link" | ||||
|     data-code="{{param.code}}" | ||||
|     data-json="{{json-stringify param}}" | ||||
|     data-roll-formula="{{param.formula}}"> | ||||
| <a class="roll-text">{{~param.formula~}}</a> | ||||
| {{~#if options.showlink}} | ||||
|  <a class="chat-roll-text" data-tooltip="Montrer"><i class="fas fa-comment"></i></a> | ||||
| {{/if~}} | ||||
| </span> | ||||
| @@ -3,21 +3,21 @@ | ||||
|   <br> | ||||
|   {{#if (eq attacker.type 'personnage')}} | ||||
|     {{#unless essais.attaqueChance}} | ||||
|       <a class='chat-card-button' id='appel-chance-attaque' | ||||
|       <a class='chat-card-button appel-chance-attaque' | ||||
|         data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> | ||||
|         Faire appel à la chance</a> | ||||
|       </a> | ||||
|       <br> | ||||
|     {{/unless}} | ||||
|     {{#if (gt attacker.system.compteurs.destinee.value 0)}} | ||||
|       <a class='chat-card-button' id='appel-destinee-attaque' | ||||
|       <a class='chat-card-button appel-destinee-attaque' | ||||
|         data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> | ||||
|         Utiliser la destinée</a> | ||||
|       </a> | ||||
|       <br> | ||||
|     {{/if}} | ||||
|   {{/if}} | ||||
|   <a class='chat-card-button' id='echec-total-attaque' | ||||
|   <a class='chat-card-button echec-total-attaque' | ||||
|     data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> | ||||
|     Tirer la maladresse ! | ||||
|   </a> | ||||
|   | ||||
| @@ -2,19 +2,19 @@ | ||||
|   <h4 class="rdd-roll-part">{{alias}} réussit une attaque particulière!</strong></h4> | ||||
|   {{#if isForce}} | ||||
|   <br> | ||||
|   <a class="chat-card-button" id="particuliere-attaque" data-mode="force" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="force" data-attackerId="{{attackerId}}"> | ||||
|     Attaquer en Force | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   {{#if isRapide}} | ||||
|   <br> | ||||
|   <a class="chat-card-button" id="particuliere-attaque" data-mode="rapidite" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="rapidite" data-attackerId="{{attackerId}}"> | ||||
|     Attaquer en Rapidité | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   {{#if isFinesse}} | ||||
|   <br> | ||||
|   <a class="chat-card-button" id="particuliere-attaque" data-mode="finesse" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="finesse" data-attackerId="{{attackerId}}"> | ||||
|     Attaquer en Finesse | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   | ||||
| @@ -20,14 +20,14 @@ | ||||
|         {{#if essais.defense}} | ||||
|           {{#unless essais.defenseChance}} | ||||
|             {{#if (eq defender.type 'personnage')}} | ||||
|               <a class='chat-card-button' id='appel-chance-defense' | ||||
|               <a class='chat-card-button appel-chance-defense' | ||||
|                 data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> | ||||
|                 Faire appel à la chance</a> | ||||
|               </a> | ||||
|               <br> | ||||
|             {{/if}} | ||||
|             {{#if (and (eq defender.type 'personnage') (gt defender.system.compteurs.destinee.value 0))}} | ||||
|               <a class='chat-card-button' id='appel-destinee-defense' | ||||
|               <a class='chat-card-button appel-destinee-defense' | ||||
|                 data-attackerId='{{attackerId}}' data-attackerTokenId='{{attackerToken.id}}' data-defenderTokenId='{{defenderToken.id}}'> | ||||
|                 Utiliser la destinée</a> | ||||
|               </a> | ||||
| @@ -36,7 +36,7 @@ | ||||
|           {{/unless}} | ||||
|         {{else}} | ||||
|           {{#each armes as |arme key|}} | ||||
|             <a class='chat-card-button' id='parer-button' | ||||
|             <a class='chat-card-button parer-button' | ||||
|               data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}' | ||||
|               data-armeid='{{arme._id}}'> | ||||
|               Parer avec {{arme.name}} | ||||
| @@ -52,7 +52,7 @@ | ||||
|             <br> | ||||
|             {{/each}} | ||||
|             {{#if mainsNues}} | ||||
|             <a class='chat-card-button' id='parer-button' | ||||
|             <a class='chat-card-button parer-button' | ||||
|             data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}' | ||||
|             data-armeid='{{arme._id}}' data-competence='{{arme.system.competence}}'> | ||||
|             Parer à mains nues à {{diffLibre}}{{#if arme.nbUsage}} (Utilisations : {{arme.nbUsage}}){{/if}} | ||||
| @@ -61,7 +61,7 @@ | ||||
|           {{/if}} | ||||
|           {{#if (ne attaqueCategorie 'tir')}} | ||||
|           {{#each esquives as |esquive key|}} | ||||
|             <a class='chat-card-button' id='esquiver-button'  | ||||
|             <a class='chat-card-button esquiver-button'  | ||||
|               data-attackerId='{{../attackerId}}' data-defenderTokenId='{{../defenderToken.id}}' data-attackerTokenId='{{../attackerToken.id}}' | ||||
|               data-compid='{{esquive._id}}'  data-competence='{{esquive.name}}'> | ||||
|               {{esquive.name}} | ||||
| @@ -76,7 +76,7 @@ | ||||
|           {{/if}} | ||||
|         {{/if}} | ||||
|       {{/unless}} | ||||
|     <a class='chat-card-button' id='encaisser-button'  | ||||
|     <a class='chat-card-button encaisser-button'  | ||||
|       data-attackerId='{{attackerId}}' data-defenderTokenId='{{defenderToken.id}}' data-attackerTokenId='{{attackerToken.id}}'> | ||||
|       Encaisser à {{plusMoins dmg.total}} | ||||
|       {{#if (eq dmg.mortalite 'non-mortel')~}} | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|     <div class="flexcol"> | ||||
|       <span><label class="item-label">Manipulation : </label></span> | ||||
|       <div class="form-group medium-editor"> | ||||
|         {{editor manipulation_update target="system.manipulation" button=true owner=options.isOwner editable=options.editable engine="prosemirror"}} | ||||
|         {{editor manipulation target="system.manipulation" button=true owner=options.isOwner editable=options.editable engine="prosemirror"}} | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="flexcol"> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| {{#if @root.competences}} | ||||
| <div class="form-group"> | ||||
|   <label for="roll-carac-competence">Compétence</label> | ||||
|   <select name="roll-carac-competence" class="roll-carac-competence" data-dtype="String"> | ||||
|   <label for="roll-text">Compétence</label> | ||||
|   <select name="roll-text" class="roll-text" data-dtype="String"> | ||||
|     {{#select ''}}<option value="">Sans compétence</option> | ||||
|     {{>"systems/foundryvtt-reve-de-dragon/templates/enum-competence.html"}} | ||||
|     {{/select}} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user