Compare commits
	
		
			21 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b09b095897 | |||
| d81965155c | |||
| 9fa8a2e6f3 | |||
| da7f87fd45 | |||
| 6aba92900c | |||
| 4939e5564e | |||
| 40be65a94e | |||
| 633638a9ab | |||
| 88a3464eed | |||
| 921e470498 | |||
| 0009876a6d | |||
| 54785f0c3a | |||
| df76c4bd78 | |||
| 5f3c678195 | |||
| 89bbe63340 | |||
| 149990e352 | |||
| 3e355784c7 | |||
| b92055d5dd | |||
| 220f8142f5 | |||
| a8bb00ad0b | |||
| 78e30b5503 | 
							
								
								
									
										35
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,9 +1,35 @@ | ||||
| # 12.0 | ||||
|  | ||||
| ## 12.0.44 - Les errements d'Astrobazzarh, suite | ||||
|  | ||||
| - on peut de nouveau dormir et se réveiller reposé | ||||
| - les possessions utilisent maintenant correctement le rêve actuel | ||||
| - les sorts variables ne causent plus de soucis de voie pour le lancement de sorts | ||||
| - les acteurs ayant un sort avec un coût de rêve entier ne sont plus considérés | ||||
|   comme pouvant avoir un rêve variable | ||||
|  | ||||
| ## 12.0.42 - Les errements d'Astrobazzarh | ||||
|  | ||||
| - Correction de différentes automatisations de combat incorrectes | ||||
| - Correction des jets `@roll[vue/-2]` qui tentaient de chercher une compétence -2 (à cause des armes à 1/2 mains) | ||||
|  | ||||
| ## 12.0.41 - La loupe d'Astrobazzarh | ||||
|  | ||||
| - On peut de nouveau effectuer des tirages cachés | ||||
| - Le stress transformé est bien diminué lorsqu'on met le stress dans une compétence | ||||
|  | ||||
| ## 12.0.40 - Les mains d'Astrobazzarh | ||||
|  | ||||
| - correction des attaques particulières en combat | ||||
| - correction de message sur les min/max liés aux modificateurs de races (s'applique uniquement sur la taille) | ||||
|  | ||||
| ## 12.0.39 - Les mains d'Astrobazzarh | ||||
|  | ||||
| - les armes à 1 ou 2 mains fonctionnent dans les liens de jets de dés | ||||
| - commande `/jet` pour poster une demande de jet de dés | ||||
|  | ||||
| ## 12.0.38 - Les prévisions d'Astrobazzarh | ||||
|  | ||||
| - Correction de modifications de personnages qui ne s'affichaient pas: | ||||
|   - changements d'endurance/vie/fatigue, transformé, ... | ||||
| - Migration des compétences "Ecriture" en "Écriture" dans les tâches, livres, oeuvres et méditations | ||||
| @@ -13,12 +39,14 @@ | ||||
|   - utilisation de l'extension hbs pour tous les fichiers handlebars | ||||
|  | ||||
| ## 12.0.37 - Les enchantements d'Astrobazzarh | ||||
|  | ||||
| - les potions ont un état, seules les potions liquides sont enchantables | ||||
| - les lancements de sorts du jour sont conservés jusqu'à chateau dormant | ||||
| - lorsqu'un joueur souhaite enchanter une potion, les sorts d'enchantements/purification/permanence doivent avoir été lancés auparavant | ||||
| - on peut enchanter des gemmes exactement comme des potions | ||||
|  | ||||
| ## 12.0.36 - L'alchimie d'Astrobazzarh | ||||
|  | ||||
| - Nouveautés | ||||
|   - ajout d'un bouton pour enchanter les potions | ||||
|   - standardisation des boutons d'actions sur les items | ||||
| @@ -33,9 +61,11 @@ | ||||
|   - Corrections de descriptions pour proposer les jet de dés | ||||
|  | ||||
| ## 12.0.35 - La Solution d'Astrobazzarh | ||||
|  | ||||
| - Fix problème d'initialisation des feuilles d'items | ||||
|  | ||||
| ## 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: | ||||
| @@ -50,21 +80,26 @@ | ||||
| - 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 | ||||
|  | ||||
| ## 12.0.31 - le mausolée d'Astrobazzarh | ||||
|  | ||||
| - Correction: les automatisation de combat jouer-MJ fonctionnentde nouveau | ||||
|  | ||||
| ## 12.0.30 - le cauchemar d'Astrobazzarh | ||||
|  | ||||
| - calcul automatique du niveau des entités selon leur rêve | ||||
| - la description des créatures venimeuses contient un lien vers leur venin | ||||
| - Correction: les messages de combats ne marchaient plus (Changement combiné Foundry + rêve de Dragon) | ||||
|  | ||||
| ## 12.0.29 - L'indexation d'Astrobazzarh | ||||
|  | ||||
| - les liens dans la descriptions des sorts pointent vers les sorts du compendium | ||||
| - la description du chrasme contient le lien vers son venin plutôt qu'un tableau | ||||
|  | ||||
|   | ||||
| @@ -237,7 +237,11 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|  | ||||
|     this.html.find('.carac-xp-augmenter').click(async event => await this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", ""))) | ||||
|     this.html.find('.competence-xp-augmenter').click(async event => await this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.competence-stress-augmenter').click(async event => await this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.competence-stress-augmenter').click(async event =>{ | ||||
|       await this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)) | ||||
|       this.render(true) | ||||
|     }  | ||||
|   ) | ||||
|  | ||||
|     if (this.options.vueDetaillee) { | ||||
|       // On carac change | ||||
|   | ||||
							
								
								
									
										103
									
								
								module/actor.js
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								module/actor.js
									
									
									
									
									
								
							| @@ -243,7 +243,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|     await this.resetInfoSommeil() | ||||
|     ChatMessage.create(message); | ||||
|     this.sheet.render(true); | ||||
|     setTimeout(() => this.sheet.render(), 20) | ||||
|   } | ||||
|  | ||||
|   async _recuperationSante(message) { | ||||
| @@ -299,7 +299,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         ChatMessage.create(message); | ||||
|       } | ||||
|       await this.resetInfoSommeil(); | ||||
|       this.sheet.render(true); | ||||
|       setTimeout(() => this.sheet.render(), 20) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -442,10 +442,9 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       message.content += 'Vous ne trouvez pas le sommeil'; | ||||
|     } | ||||
|     else { | ||||
|       let jetsReve = []; | ||||
|       let dormi = await this.dormirDesHeures(jetsReve, message, heures, options); | ||||
|       if (jetsReve.length > 0) { | ||||
|         message.content += `Vous récupérez ${jetsReve.map(it => it < 0 ? '0 (réveil)' : it).reduce(Misc.joining("+"))} Points de rêve. `; | ||||
|       let dormi = await this.$dormirDesHeures(message, heures, options); | ||||
|       if (dormi.jetsReve.length > 0) { | ||||
|         message.content += `Vous récupérez ${dormi.jetsReve.map(it => it < 0 ? '0 (réveil)' : it).reduce(Misc.joining("+"))} Points de rêve. `; | ||||
|       } | ||||
|       if (dormi.etat == 'eveil') { | ||||
|         await this.reveilReveDeDragon(message, dormi.heures); | ||||
| @@ -461,7 +460,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       await this.dormirChateauDormant(); | ||||
|     } | ||||
|     else { | ||||
|       this.sheet.render(true); | ||||
|       setTimeout(() => this.sheet.render(), 20) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -472,18 +471,18 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async dormirDesHeures(jetsReve, message, heures, options) { | ||||
|     const dormi = { heures: 0, etat: 'dort' }; | ||||
|   async $dormirDesHeures(message, heures, options) { | ||||
|     const dormi = { heures: 0, etat: 'dort', jetsReve: [] }; | ||||
|     for (; dormi.heures < heures && dormi.etat == 'dort'; dormi.heures++) { | ||||
|       await this._recupererEthylisme(message); | ||||
|       await this.$recupererEthylisme(message); | ||||
|       if (options.grisReve) { | ||||
|         await this.recupererFatigue(message); | ||||
|         await this.$recupererFatigue(message); | ||||
|       } | ||||
|       else if (!this.system.sommeil?.insomnie) { | ||||
|         await this.recupererFatigue(message); | ||||
|         dormi.etat = await this.jetRecuperationReve(jetsReve, message); | ||||
|         await this.$recupererFatigue(message); | ||||
|         await this.$jetRecuperationReve(dormi, message); | ||||
|         if (dormi.etat == 'dort' && EffetsDraconiques.isDonDoubleReve(this)) { | ||||
|           dormi.etat = await this.jetRecuperationReve(jetsReve, message); | ||||
|           dormi.etat = await this.$jetRecuperationReve(dormi, message); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| @@ -491,35 +490,36 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async jetRecuperationReve(jetsReve, message) { | ||||
|   async $jetRecuperationReve(dormi, message) { | ||||
|     if (this.getReveActuel() < this.system.reve.seuil.value) { | ||||
|       let reve = await RdDDice.rollTotal("1dr"); | ||||
|       const reve = await RdDDice.rollTotal("1dr") | ||||
|       if (reve >= 7) { | ||||
|         // Rêve de Dragon ! | ||||
|         message.content += `Vous faites un <strong>Rêve de Dragon</strong> de ${reve} Points de rêve qui vous réveille! `; | ||||
|         await this.combattreReveDeDragon(reve); | ||||
|         jetsReve.push(-1); | ||||
|         return 'eveil'; | ||||
|         dormi.jetsReve.push(-1); | ||||
|         dormi.etat = 'eveil' | ||||
|         return | ||||
|       } | ||||
|       else { | ||||
|         if (!ReglesOptionnelles.isUsing("recuperation-reve")) { | ||||
|           ChatMessage.create({ | ||||
|             whisper: ChatUtility.getOwners(this), | ||||
|             content: `Pas de récupération de rêve (${reve} points ignorés)` | ||||
|           }); | ||||
|           jetsReve.push(0); | ||||
|           }) | ||||
|           dormi.jetsReve.push(0) | ||||
|         } | ||||
|         else { | ||||
|           await this.reveActuelIncDec(reve); | ||||
|           jetsReve.push(reve); | ||||
|           await this.reveActuelIncDec(reve) | ||||
|           dormi.jetsReve.push(reve) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return 'dort'; | ||||
|     dormi.etat = 'dort' | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _recupererEthylisme(message) { | ||||
|   async $recupererEthylisme(message) { | ||||
|     if (!ReglesOptionnelles.isUsing("recuperation-ethylisme")) { return; } | ||||
|     let value = Math.min(Number.parseInt(this.system.compteurs.ethylisme.value) + 1, 1); | ||||
|     if (value <= 0) { | ||||
| @@ -549,15 +549,16 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async recupererFatigue(message) { | ||||
|   async $recupererFatigue(message) { | ||||
|     if (ReglesOptionnelles.isUsing("appliquer-fatigue")) { | ||||
|       let fatigue = this.system.sante.fatigue.value; | ||||
|       const fatigueMin = this.getFatigueMin(); | ||||
|       let fatigue = this.system.sante.fatigue.value | ||||
|       const fatigueMin = this.getFatigueMin() | ||||
|       if (fatigue <= fatigueMin) { | ||||
|         return; | ||||
|         return | ||||
|       } | ||||
|       fatigue = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue)); | ||||
|       await this.update({ "system.sante.fatigue.value": fatigue }); | ||||
|       fatigue = Math.max(fatigueMin, this._calculRecuperationSegment(fatigue)) | ||||
|       await this.update({ 'system.sante.fatigue.value': fatigue }); | ||||
|       await new Promise(resolve => setTimeout(resolve, 200));  | ||||
|       if (fatigue == 0) { | ||||
|         message.content += "Vous êtes complêtement reposé. "; | ||||
|       } | ||||
| @@ -736,7 +737,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       await competence.update({ | ||||
|         "system.xp": toXp, | ||||
|         "system.niveau": toNiveau, | ||||
|       }); | ||||
|       }, { render: false }) | ||||
|       await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name); | ||||
|       await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name); | ||||
|     } | ||||
| @@ -767,7 +768,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     await competence.update({ | ||||
|       "system.xp": newXp, | ||||
|       "system.niveau": toNiveau, | ||||
|     }); | ||||
|     }, { render: false }) | ||||
|     const toXpStress = Math.max(0, fromXpStress - xpUtilise); | ||||
|     await this.update({ "system.compteurs.experience.value": toXpStress }); | ||||
|  | ||||
| @@ -783,7 +784,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       const toNiveau = compValue ?? RdDItemCompetence.getNiveauBase(competence.system.categorie, competence.getCategories()); | ||||
|       this.notifyCompetencesTronc(competence, toNiveau); | ||||
|       const fromNiveau = competence.system.niveau; | ||||
|       await competence.update({ 'system.niveau': toNiveau }); | ||||
|       await competence.update({ 'system.niveau': toNiveau }, { render: false }) | ||||
|       await ExperienceLog.add(this, XP_TOPIC.NIVEAU, fromNiveau, toNiveau, competence.name, true); | ||||
|     } | ||||
|   } | ||||
| @@ -808,7 +809,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       if (isNaN(toXp) || typeof (toXp) != 'number') toXp = 0; | ||||
|       const fromXp = competence.system.xp; | ||||
|       this.checkCompetenceXP(idOrName, toXp); | ||||
|       await competence.update({ 'system.xp': toXp }); | ||||
|       await competence.update({ 'system.xp': toXp }, { render: false }) | ||||
|       await ExperienceLog.add(this, XP_TOPIC.XP, fromXp, toXp, competence.name, true); | ||||
|       if (toXp > fromXp) { | ||||
|         RdDUtility.checkThanatosXP(competence) | ||||
| @@ -822,7 +823,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     if (competence) { | ||||
|       if (isNaN(toXpSort) || typeof (toXpSort) != 'number') toXpSort = 0; | ||||
|       const fromXpSort = competence.system.xp_sort; | ||||
|       await competence.update({ 'system.xp_sort': toXpSort }); | ||||
|       await competence.update({ 'system.xp_sort': toXpSort }, { render: false }) | ||||
|       await ExperienceLog.add(this, XP_TOPIC.XPSORT, fromXpSort, toXpSort, competence.name, true); | ||||
|       if (toXpSort > fromXpSort) { | ||||
|         RdDUtility.checkThanatosXP(competence) | ||||
| @@ -834,7 +835,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   async updateCompetenceArchetype(idOrName, compValue) { | ||||
|     let competence = this.getCompetence(idOrName) | ||||
|     if (competence) { | ||||
|       await competence.update({ 'system.niveau_archetype': Math.max(compValue ?? 0, 0) }); | ||||
|       await competence.update({ 'system.niveau_archetype': Math.max(compValue ?? 0, 0) }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -1560,7 +1561,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     if (!rollData.rolled.isPart || | ||||
|       rollData.finalLevel >= 0 || | ||||
|       game.settings.get("core", "rollMode") == 'selfroll' || | ||||
| 	  !Misc.hasConnectedGM()) { | ||||
|       !Misc.hasConnectedGM()) { | ||||
|       return | ||||
|     } | ||||
|     hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) | ||||
| @@ -1584,7 +1585,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _appliquerAppelMoral(rollData) { | ||||
|     if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll'){ | ||||
|     if (!rollData.use.moral || game.settings.get("core", "rollMode") == 'selfroll') { | ||||
|       return | ||||
|     } | ||||
|     if (rollData.rolled.isEchec || | ||||
| @@ -1800,8 +1801,10 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     }; | ||||
|     RollDataAjustements.calcul(rollData, this); | ||||
|     await RdDResolutionTable.rollData(rollData); | ||||
|     this.gererExperience(rollData); | ||||
|     await RdDRollResult.displayRollData(rollData, this) | ||||
|  | ||||
|     this.gererExperience(rollData); | ||||
|  | ||||
|     return rollData.rolled; | ||||
|   } | ||||
|  | ||||
| @@ -1869,7 +1872,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         competence: competence, | ||||
|         show: { title: options?.title ?? '' } | ||||
|       }, | ||||
| 	  // TODO: | ||||
|       // TODO: | ||||
|       callbacks: [{ action: r => this.$onRollCompetence(r, options) }] | ||||
|     }); | ||||
|   } | ||||
| @@ -1882,7 +1885,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     compData.system.defaut_carac = tacheData.system.carac; // Patch ! | ||||
|  | ||||
|     await this.openRollDialog({ | ||||
|           name: 'jet-competence', | ||||
|       name: 'jet-competence', | ||||
|       label: 'Jet de Tâche ' + tacheData.name, | ||||
|       template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.hbs', | ||||
|       rollData: { | ||||
| @@ -1945,9 +1948,9 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|  | ||||
|     await this.openRollDialog({ | ||||
|           name: `jet-${artData.art}`, | ||||
|       name: `jet-${artData.art}`, | ||||
|       label: `${artData.verbe} ${oeuvre.name}`, | ||||
|           template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`, | ||||
|       template: `systems/foundryvtt-reve-de-dragon/templates/dialog-roll-${oeuvre.type}.hbs`, | ||||
|       rollData: artData, | ||||
|       callbacks: [{ action: callbackAction }], | ||||
|     }) | ||||
| @@ -2527,7 +2530,6 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       }) | ||||
|     } | ||||
|     const blessure = this.getItem(blessureId, 'blessure') | ||||
|     console.log('TODO update blessure', this, blessureId, rollData, rollData.tache); | ||||
|     if (blessure && !blessure.system.premierssoins.done) { | ||||
|       const tache = rollData.tache; | ||||
|       if (rollData.rolled.isETotal) { | ||||
| @@ -2644,12 +2646,13 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async incDecItemUse(itemId, inc = 1) { | ||||
|     const currentItemUse = this.getFlag(SYSTEM_RDD, 'itemUse'); | ||||
|     let itemUse = currentItemUse ? foundry.utils.duplicate(currentItemUse) : {}; | ||||
|     itemUse[itemId] = (itemUse[itemId] ?? 0) + inc; | ||||
|     await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse); | ||||
|     console.log("ITEM USE INC", inc, itemUse); | ||||
|   async incDecItemUse(itemId, shouldIncrease = true) { | ||||
|     if (shouldIncrease) { | ||||
|       const currentItemUse = this.getFlag(SYSTEM_RDD, 'itemUse'); | ||||
|       let itemUse = currentItemUse ? foundry.utils.duplicate(currentItemUse) : {}; | ||||
|       itemUse[itemId] = (itemUse[itemId] ?? 0) + 1; | ||||
|       await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   | ||||
| @@ -277,14 +277,9 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|     return dialog | ||||
|   } | ||||
|  | ||||
|   createEmptyCallback() { | ||||
|     return { | ||||
|       condition: r => false, | ||||
|       action: r => { } | ||||
|     }; | ||||
|   } | ||||
|   createCallbackExperience() { return this.createEmptyCallback(); } | ||||
|   createCallbackAppelAuMoral() { return this.createEmptyCallback(); } | ||||
|   createCallbackExperience() { return { action: r => { } } } | ||||
|   createCallbackAppelAuMoral() { return { action: r => { } } } | ||||
|  | ||||
|   async _onCloseRollDialog(html) { } | ||||
|  | ||||
|   async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) { | ||||
|   | ||||
| @@ -244,16 +244,19 @@ export class RdDBaseActor extends Actor { | ||||
|   async onUpdateActor(update, options, actorId) { } | ||||
|   async onDeleteItem(item, options, id) { | ||||
|     if (item.isInventaire()) { | ||||
|       this._removeItemFromConteneur(item) | ||||
|       await this._removeItemFromConteneur(item) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   _removeItemFromConteneur(item) { | ||||
|     this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id)) | ||||
|       .forEach(conteneur => { | ||||
|         const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id); | ||||
|         conteneur.update({ 'system.contenu': nouveauContenu }); | ||||
|       }); | ||||
|   async _removeItemFromConteneur(item) { | ||||
|     const updates = this.items.filter(it => it.isConteneur() && it.system.contenu.includes(item.id)) | ||||
|       .map(conteneur => { | ||||
|         const nouveauContenu = conteneur.system.contenu.filter(id => id != item.id) | ||||
|         return { _id: conteneur.id, 'system.contenu': nouveauContenu } | ||||
|       }) | ||||
|     if (updates.length > 0) { | ||||
|       await this.updateEmbeddedDocuments('Item', updates) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async onTimeChanging(oldTimestamp, newTimestamp) { | ||||
| @@ -744,7 +747,7 @@ export class RdDBaseActor extends Actor { | ||||
|   async jetDeMoral() { this.actionImpossible("jet de moral") } | ||||
|  | ||||
|   async resetItemUse() { } | ||||
|   async incDecItemUse(itemId, inc = 1) { } | ||||
|   async incDecItemUse(itemId, shouldIncrease = true) { } | ||||
|   getItemUse(itemId) { return 0; } | ||||
|  | ||||
|   async finDeRound(options = { terminer: false }) { } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ 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-z0-9À-ÖØ-öø-ÿ -]+))?" | ||||
| const REGEXP_COMP = "(\\/(?<competence>[A-Za-zÀ-ÖØ-öø-ÿ ]+([1-2]?[A-Za-zÀ-ÖØ-öø-ÿ ]+)?))?" | ||||
| 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') | ||||
|   | ||||
| @@ -62,7 +62,6 @@ export class ChatUtility { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|  | ||||
|   static removeMessages(socketData) { | ||||
|     if (Misc.isFirstConnectedGM()) { | ||||
|       ChatUtility.onRemoveMessages(socketData); | ||||
| @@ -97,7 +96,7 @@ export class ChatUtility { | ||||
|         } | ||||
|         break | ||||
|       case "gmroll": | ||||
|         messageData.whisper = ChatUtility.getOwners(actor) | ||||
|         messageData.whisper = actor ? ChatUtility.getOwners(actor) : ChatUtility.getUserAndGMs() | ||||
|         break | ||||
|       case "selfroll": | ||||
|         messageData.whisper = [game.user] | ||||
| @@ -108,7 +107,7 @@ export class ChatUtility { | ||||
|   } | ||||
|  | ||||
|   static getOwners(document) { | ||||
|     return game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) | ||||
|     return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user] | ||||
|   } | ||||
|  | ||||
|   static getUserAndGMs() { | ||||
| @@ -199,7 +198,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}) }) | ||||
|       await chatMessage.update({ content: await RdDTextEditor.enrichHTML(chatMessage.content, undefined, { showLink: false }) }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -56,6 +56,10 @@ export class RdDItemSort extends Item { | ||||
|     return voies.map(voie => RdDItemCompetence.getVoieDraconic(competencesDraconic, voie)) | ||||
|   } | ||||
|  | ||||
|   static getBestDraconicSort(competencesDraconic, sort) { | ||||
|     return  RdDItemSort.getDraconicsSort(competencesDraconic, sort).sort(Misc.descending(it => it.system.niveau)).find(it=>true) | ||||
|   } | ||||
|  | ||||
|   static getOrdreCode(code) { | ||||
|     return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?') | ||||
|   } | ||||
| @@ -92,7 +96,7 @@ export class RdDItemSort extends Item { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isCoutVariable(sort) { | ||||
|     return sort && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0); | ||||
|     return sort && !Number.isInteger(sort.system.ptreve) && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   | ||||
| @@ -19,10 +19,12 @@ export class RdDItemRace extends RdDItem { | ||||
|         return false | ||||
|       } | ||||
|     } | ||||
|     const carac = RdDCarac.carac(code) | ||||
|     if (race.isMax(actor, code, value - 1)) { | ||||
|       ui.notifications.warn(`${value} est supérieure au maximum de ${carac.label}`) | ||||
|       return false | ||||
|     if (code == LIST_CARAC_PERSONNAGE.taille.code) { | ||||
|       const carac = RdDCarac.carac(code) | ||||
|       if (race.isMax(actor, code, value - 1)) { | ||||
|         ui.notifications.warn(`${value} est supérieure au maximum de ${carac.label}`) | ||||
|         return false | ||||
|       } | ||||
|     } | ||||
|     return true | ||||
|   } | ||||
| @@ -59,7 +61,8 @@ export class RdDItemRace extends RdDItem { | ||||
|     if (code == LIST_CARAC_PERSONNAGE.force.code) { | ||||
|       return value >= this.getForceMax(actor) | ||||
|     } | ||||
|     const max = foundry.utils.getProperty(this, path) ?? -1 | ||||
|     const pathMax = path.replace(".value", ".max"); | ||||
|     const max = foundry.utils.getProperty(this, pathMax) ?? -1 | ||||
|     return (max > 0 && value >= max) | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -265,7 +265,7 @@ export class Misc { | ||||
|     const subset = elements.filter(options.preFilter) | ||||
|       .filter(it => Grammar.toLowerCaseNoAccent(options.mapper(it))?.includes(value)) | ||||
|       .sort(Misc.ascending(it => options.mapper(it))) | ||||
|     if (subset.length == 0) { | ||||
|     if (subset.length == 0 && options?.onMessage) { | ||||
|       options.onMessage(`Pas de ${options.description} correspondant à ${value}`); | ||||
|     } | ||||
|     return subset; | ||||
|   | ||||
| @@ -743,23 +743,13 @@ export class RdDCombat { | ||||
|           this.attacker.createCallbackExperience(), | ||||
|           this.attacker.createCallbackAppelAuMoral(), | ||||
|           { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, | ||||
|           { action: r => this._increaseItemUse(r, arme) }, | ||||
|           { action: r => this._onAttaqueNormale(r) }, | ||||
|           { action: r => this._onAttaqueParticuliere(r) }, | ||||
|           { action: r => this._onAttaqueEchec(r) }, | ||||
|           { action: r => this._onAttaqueEchecTotal(r) }, | ||||
|           { action: async r => await this.attacker.incDecItemUse(arme._id, arme && !RdDCombat.isParticuliere(r)) }, | ||||
|           { action: r => this._onAttaque(r) }, | ||||
|         ] | ||||
|       }); | ||||
|     dialog.render(true); | ||||
|   } | ||||
|  | ||||
|   _increaseItemUse(rollData, arme) { | ||||
|     if (!arme || RdDCombat.isParticuliere(rollData)) { | ||||
|       return | ||||
|     } | ||||
|     this.attacker.incDecItemUse(arme._id) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _prepareAttaque(competence, arme) { | ||||
|     let rollData = { | ||||
| @@ -776,7 +766,7 @@ export class RdDCombat { | ||||
|  | ||||
|     if (this.attacker.isCreatureEntite()) { | ||||
|       RdDItemCompetenceCreature.setRollDataCreature(rollData); | ||||
|   } | ||||
|     } | ||||
|     else if (arme) { | ||||
|       // Usual competence | ||||
|       rollData.arme = RdDItemArme.armeUneOuDeuxMains(arme, RdDItemCompetence.isArmeUneMain(competence)); | ||||
| @@ -790,11 +780,23 @@ export class RdDCombat { | ||||
|     return rollData; | ||||
|   } | ||||
|  | ||||
|   async _onAttaque(attackerRoll) { | ||||
|     if (RdDCombat.isParticuliere(attackerRoll)) { | ||||
|       return await this._onAttaqueParticuliere(attackerRoll) | ||||
|     } | ||||
|     if (RdDCombat.isReussite(attackerRoll)) { | ||||
|       return await this._onAttaqueNormale(attackerRoll) | ||||
|     } | ||||
|     // if (RdDCombat.isParticuliere(attackerRoll) && attackerRoll.particuliere == undefined) { | ||||
|     //   return | ||||
|     // } | ||||
|     if (RdDCombat.isEchecTotal(attackerRoll)) { | ||||
|       return await this._onAttaqueEchecTotal(attackerRoll) | ||||
|     } | ||||
|     return await this._onAttaqueEchec(attackerRoll) | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onAttaqueParticuliere(rollData) { | ||||
|     if (!RdDCombat.isParticuliere(rollData)) { | ||||
|       return | ||||
|     } | ||||
|     const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0; | ||||
|     // force toujours, sauf empoignade | ||||
|     // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum | ||||
| @@ -832,9 +834,6 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onAttaqueNormale(attackerRoll) { | ||||
|     if (!RdDCombat.isReussite(attackerRoll) || RdDCombat.isParticuliere(attackerRoll)) { | ||||
|       return | ||||
|     } | ||||
|     console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll); | ||||
|  | ||||
|     attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite()); | ||||
| @@ -849,7 +848,7 @@ export class RdDCombat { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     if (this.target) { | ||||
|     if (this.defender) { | ||||
|       await this._sendMessageDefense(attackerRoll, defenderRoll); | ||||
|     } | ||||
|   } | ||||
| @@ -951,9 +950,6 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onAttaqueEchecTotal(attackerRoll) { | ||||
|     if (!RdDCombat.isEchecTotal(attackerRoll)) { | ||||
|       return | ||||
|     } | ||||
|     const choixEchecTotal = await ChatMessage.create({ | ||||
|       whisper: ChatUtility.getOwners(this.attacker), | ||||
|       content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.hbs', { | ||||
| @@ -980,26 +976,20 @@ export class RdDCombat { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onAttaqueEchec(rollData) { | ||||
|     if (!RdDCombat.isEchec(rollData)) { | ||||
|       return | ||||
|     } | ||||
|     console.log("RdDCombat.onAttaqueEchec >>>", rollData); | ||||
|     await RdDRollResult.displayRollData(rollData, this.attacker, 'chat-resultat-attaque.hbs'); | ||||
|  | ||||
|   async _onAttaqueEchec(attackerRoll) { | ||||
|     console.log("RdDCombat.onAttaqueEchec >>>", attackerRoll); | ||||
|     await RdDRollResult.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.hbs'); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async choixParticuliere(rollData, choix) { | ||||
|     console.log("RdDCombat.choixParticuliere >>>", rollData, choix); | ||||
|  | ||||
|     if (choix != "rapidite") { | ||||
|       this.attacker.incDecItemUse(rollData.arme.id); | ||||
|     } | ||||
|     await this.attacker.incDecItemUse(rollData.arme.id, choix != "rapidite") | ||||
|  | ||||
|     this.removeChatMessageActionsPasseArme(rollData.passeArme); | ||||
|     rollData.particuliere = choix; | ||||
|     await this._onAttaqueNormale(rollData); | ||||
|     await this._onAttaqueNormale(rollData) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -1023,10 +1013,8 @@ export class RdDCombat { | ||||
|           this.defender.createCallbackExperience(), | ||||
|           this.defender.createCallbackAppelAuMoral(), | ||||
|           { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, | ||||
|           { condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(armeParadeId) }, | ||||
|           { condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) }, | ||||
|           { condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) }, | ||||
|           { condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) }, | ||||
|           { action: async r => await this.defender.incDecItemUse(armeParadeId, !RdDCombat.isParticuliere(r)) }, | ||||
|           { action: r => this._onParade(r) }, | ||||
|         ] | ||||
|       }); | ||||
|     dialog.render(true); | ||||
| @@ -1057,8 +1045,19 @@ export class RdDCombat { | ||||
|     return defenderRoll; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   async _onParade(defenderRoll) { | ||||
|     if (RdDCombat.isParticuliere(defenderRoll)) { | ||||
|       return await this._onParadeParticuliere(defenderRoll) | ||||
|     } | ||||
|     if (RdDCombat.isReussite(defenderRoll)) { | ||||
|       return await this._onParadeNormale(defenderRoll) | ||||
|     } | ||||
|     await this._onParadeEchec(defenderRoll) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _onParadeParticuliere(defenderRoll) { | ||||
|   async _onParadeParticuliere(defenderRoll) { | ||||
|     console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll); | ||||
|     if (!defenderRoll.attackerRoll.isPart) { | ||||
|       // TODO: attaquant doit jouer résistance et peut être désarmé p132 | ||||
| @@ -1067,7 +1066,6 @@ export class RdDCombat { | ||||
|         this.defender) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async _onParadeNormale(defenderRoll) { | ||||
|     console.log("RdDCombat._onParadeNormale >>>", defenderRoll); | ||||
| @@ -1106,11 +1104,9 @@ export class RdDCombat { | ||||
|         callbacks: [ | ||||
|           this.defender.createCallbackExperience(), | ||||
|           this.defender.createCallbackAppelAuMoral(), | ||||
|           { condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(esquive._id) }, | ||||
|           { action: async r => await this.defender.incDecItemUse(esquive._id, !RdDCombat.isParticuliere(r)) }, | ||||
|           { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, | ||||
|           { condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) }, | ||||
|           { condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) }, | ||||
|           { condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) }, | ||||
|           { action: r => this._onEsquive(r) }, | ||||
|         ] | ||||
|       }); | ||||
|     dialog.render(true); | ||||
| @@ -1138,9 +1134,18 @@ export class RdDCombat { | ||||
|     return rollData; | ||||
|   } | ||||
|  | ||||
|   async _onEsquive(defenderRoll) { | ||||
|     if (RdDCombat.isParticuliere(defenderRoll)) { | ||||
|       return await this._onEsquiveParticuliere(defenderRoll) | ||||
|     } | ||||
|     if (RdDCombat.isReussite(defenderRoll)) { | ||||
|       return await this._onEsquiveNormale(defenderRoll) | ||||
|     } | ||||
|     return await this._onEsquiveEchec(defenderRoll) | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   _onEsquiveParticuliere(rollData) { | ||||
|     console.log("RdDCombat._onEsquiveParticuliere >>>", rollData); | ||||
|   async _onEsquiveParticuliere(defenderRoll) { | ||||
|     console.log("RdDCombat._onEsquiveParticuliere >>>", defenderRoll); | ||||
|     ChatUtility.createChatWithRollMode( | ||||
|       { content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" }, | ||||
|       this.defender); | ||||
|   | ||||
| @@ -104,8 +104,8 @@ export class RdDPossession { | ||||
|       rollData.selectedCarac = carac.reve | ||||
|     } | ||||
|     else { | ||||
|       rollData.selectedCarac = rollingActor.system.carac.reve | ||||
|       rollData.forceCarac = { 'reve-actuel': { label: "Rêve Actuel", value: rollingActor.getReveActuel() } } | ||||
|       rollData.selectedCarac = rollData.forceCarac['reve-actuel'] | ||||
|       rollData.competence.system.defaut_carac = 'reve-actuel' | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -1,4 +1,3 @@ | ||||
| import { ChatUtility } from "./chat-utility.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
| import { RdDDice } from "./rdd-dice.js"; | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; | ||||
|   | ||||
| @@ -279,7 +279,7 @@ export class RdDRoll extends Dialog { | ||||
|  | ||||
|   async setSelectedSort(sort) { | ||||
|     this.rollData.selectedSort = sort; // Update the selectedCarac | ||||
|     this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.system.draconic); | ||||
|     this.rollData.competence = RdDItemSort.getBestDraconicSort(this.rollData.draconicList, sort) | ||||
|     this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord); | ||||
|     this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7); | ||||
|     RdDItemSort.setCoutReveReel(sort); | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| { | ||||
|   "scripts": { | ||||
|     "build": "npx vite build", | ||||
|     "run": "npx vite serve", | ||||
|     "packCompendiumsToDist": "node ./tools/packCompendiumsToDist.mjs", | ||||
|     "packCompendiumsToPublic": "node ./tools/packCompendiumsToPublic.mjs", | ||||
|     "unpackCompendiumsFromPublic": "node ./tools/unpackCompendiumsFromPublic.mjs" | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| { | ||||
|   "id": "foundryvtt-reve-de-dragon", | ||||
|   "title": "Rêve de Dragon", | ||||
|   "version": "12.0.38", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.38/rddsystem.zip", | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.38/system.json", | ||||
|   "version": "12.0.44", | ||||
|   "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.44/rddsystem.zip", | ||||
|   "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/releases/download/12.0.44/system.json", | ||||
|   "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", | ||||
|   "compatibility": { | ||||
|     "minimum": "11", | ||||
|   | ||||
| @@ -1,15 +1,18 @@ | ||||
| <div> | ||||
|   <ul class="item-list"> | ||||
|     <li class="item flexrow"> | ||||
|     <li class="flexrow"> | ||||
|       <label class="derivee-label" for="system.compteurs.experience.value">Stress transformé</label> | ||||
|       {{#if options.vueDetaillee}} | ||||
|       <input class="derivee-value" type="number" name="system.compteurs.experience.value" value="{{system.compteurs.experience.value}}" data-dtype="number" size="3"/> | ||||
|       <input class="resource-content" | ||||
|         type="text" data-dtype="Number" size="3" | ||||
|         name="system.compteurs.experience.value" | ||||
|         value="{{system.compteurs.experience.value}}"/> | ||||
|       {{else}} | ||||
|       <label name="system.compteurs.experience.value">{{system.compteurs.experience.value}}</label> | ||||
|       {{/if}} | ||||
|     </li> | ||||
|     {{#if options.vueDetaillee}} | ||||
|     <li class="item flexrow"> | ||||
|     <li class="flexrow"> | ||||
|       <span class="generic-label">Total XP compétences</span> | ||||
|       <span class="competence-value">{{calc.competenceXPTotal}}</span> | ||||
|     </li> | ||||
|   | ||||
| @@ -2,19 +2,22 @@ | ||||
|   <h4 class="rdd-roll-part">{{alias}} réussit une attaque particulière!</strong></h4> | ||||
|   {{#if isForce}} | ||||
|   <br> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="force" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="force" data-attackerId="{{attackerId}}" | ||||
|     data-defenderTokenId="{{defenderToken.id}}" data-attackerTokenId="{{attackerToken.id}}"> | ||||
|     Attaquer en Force | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   {{#if isRapide}} | ||||
|   <br> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="rapidite" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="rapidite" data-attackerId="{{attackerId}}" | ||||
|     data-defenderTokenId="{{defenderToken.id}}" data-attackerTokenId="{{attackerToken.id}}"> | ||||
|     Attaquer en Rapidité | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   {{#if isFinesse}} | ||||
|   <br> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="finesse" data-attackerId="{{attackerId}}"> | ||||
|   <a class="chat-card-button particuliere-attaque" data-mode="finesse" data-attackerId="{{attackerId}}" | ||||
|     data-defenderTokenId="{{defenderToken.id}}" data-attackerTokenId="{{attackerToken.id}}"> | ||||
|     Attaquer en Finesse | ||||
|   </a> | ||||
|   {{/if}} | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
| <hr> | ||||
| <div> | ||||
|   {{#if rolled.isSuccess}} | ||||
|   {{alias}} a gagné {{xpSort}} points d'expérience en sorts dans la {{competence.name}}. | ||||
|   {{alias}} a gagné {{xpSort}} points d'expérience en sorts en {{competence.name}}. | ||||
|   {{else}} | ||||
|   {{alias}} n'a pas pu interpréter le signe draconique. | ||||
|   {{/if}} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user