forked from public/foundryvtt-reve-de-dragon
		
	Compare commits
	
		
			49 Commits
		
	
	
		
			10971e9e7b
			...
			12.0.37
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 24518642a7 | |||
| d917f80e88 | |||
| b29027c61a | |||
| 6083dd41fa | |||
| 8969d5e0ed | |||
| 7d135a214f | |||
| 9d66a479c4 | |||
| 800b4a2f32 | |||
| 9fc21e6d97 | |||
| ce7f5381ca | |||
| 48acdaaca6 | |||
| 425c6af672 | |||
| 4281f76dfb | |||
| 8ebd6ec771 | |||
| 14391daa0b | |||
| ac29e1410e | |||
| 442ffe9b3a | |||
| d922e4fdd5 | |||
| a8dc07b4db | |||
| 40a47ee8a2 | |||
| c5633a9fc5 | |||
| 7e8da49912 | |||
| b524716ede | |||
| 72a9752820 | |||
| 8e578c6566 | |||
| 5ac9c682d9 | |||
| 6de19eb357 | |||
| 90d096a6df | |||
| c733644f3a | |||
| de9d3bbb48 | |||
| efdffd171c | |||
| 8406c8434a | |||
| a4b474970c | |||
| 135e5e46a0 | |||
| 969bc3b573 | |||
| a9eb101c9d | |||
| d53da1f011 | |||
| ab0f7e563f | |||
| 57c41a0218 | |||
| 1b75decb18 | |||
| 551438f514 | |||
| 792558ac84 | |||
| 06aff9a3c0 | |||
| 7e736a00d7 | |||
| b87f406093 | |||
| 785bd4b9ce | |||
| daca86b1df | |||
| aa52e26e1a | |||
| f956da1fc0 | 
							
								
								
									
										41
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,4 +1,45 @@ | ||||
| # 12.0 | ||||
| ## 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 | ||||
|   - utilisations d'icones pour les actions de l'inventaire | ||||
| - Corrections: | ||||
|   - la commande /tmra sans paramètres fonctionne | ||||
|   - les jets d'encaissement depuis le tchat fonctionnent | ||||
|   - affichage de la vie/endurance en cas de blessures et remise à neuf | ||||
|   - les queues durant 12 heures ajoutées début Vaisseau ne durent plus 24 heures | ||||
| - Compendiums | ||||
|   - Corrections des remedes enchantables | ||||
|   - 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: | ||||
|     - 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 | ||||
|  | ||||
|   | ||||
| @@ -12,13 +12,14 @@ import { RdDSheetUtility } from "./rdd-sheet-utility.js"; | ||||
| import { STATUSES } from "./settings/status-effects.js"; | ||||
| import { MAINS_DIRECTRICES } from "./actor.js"; | ||||
| import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js"; | ||||
| import { ITEM_TYPES, RdDItem } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { RdDItem } from "./item.js"; | ||||
| import { RdDItemBlessure } from "./item/blessure.js"; | ||||
| import { RdDEmpoignade } from "./rdd-empoignade.js"; | ||||
| 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(), | ||||
| @@ -183,22 +184,19 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|       await blessure?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } }) | ||||
|     }); | ||||
|  | ||||
|     // Equip Inventory Item | ||||
|     this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.roll-chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle')) | ||||
|  | ||||
|     this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance()) | ||||
|  | ||||
|     this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux()) | ||||
|     this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-tache').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.meditation-label a').click(async event => this.actor.rollMeditation(RdDSheetUtility.getItemId(event))) | ||||
|  | ||||
|     this.html.find('.chant-label a').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.danse-label a').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.musique-label a').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.oeuvre-label a').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-chant').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-danse').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-musique').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-oeuvre').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-jeu').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event))) | ||||
|     this.html.find('.action-recettecuisine').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event))) | ||||
|  | ||||
|     this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true)) | ||||
|     if (game.user.isGM) { | ||||
| @@ -216,13 +214,12 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|       // Boutons spéciaux MJs | ||||
|       this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ")) | ||||
|       this.html.find('.don-de-haut-reve').click(async event => this.actor.addDonDeHautReve()) | ||||
|       this.html.find('.sortreserve-add').click(async event => this.actor.addSortReserve(RdDSheetUtility.getItemId(event))) | ||||
|       this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible()) | ||||
|     } | ||||
|  | ||||
|     // Points de reve actuel | ||||
|     this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true)) | ||||
|     this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) | ||||
|     this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', {resistance:true})) | ||||
|     this.html.find('.action-empoignade').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')) | ||||
|  | ||||
| @@ -326,7 +323,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|   /* -------------------------------------------- */ | ||||
|   async selectTypeOeuvreToCreate() { | ||||
|     let types = RdDItem.getTypesOeuvres(); | ||||
|     let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`; | ||||
|     let content = `<span class="generic-label">Selectionnez le type d'oeuvre</span><select class="item-type">`; | ||||
|     for (let typeName of types) { | ||||
|       content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>` | ||||
|     } | ||||
|   | ||||
							
								
								
									
										243
									
								
								module/actor.js
									
									
									
									
									
								
							
							
						
						
									
										243
									
								
								module/actor.js
									
									
									
									
									
								
							| @@ -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"; | ||||
| @@ -32,7 +32,7 @@ import { RdDItemBlessure } from "./item/blessure.js"; | ||||
| import { AppAstrologie } from "./sommeil/app-astrologie.js"; | ||||
| import { RdDEmpoignade } from "./rdd-empoignade.js"; | ||||
| import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { RdDBaseActorSang } from "./actor/base-actor-sang.js"; | ||||
| import { RdDCoeur } from "./coeur/rdd-coeur.js"; | ||||
| import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js"; | ||||
| @@ -166,29 +166,30 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async $perteRevePotionsEnchantees() { | ||||
|     let potions = this.itemTypes[ITEM_TYPES.potion] | ||||
|       .filter(it => Grammar.includesLowerCaseNoAccent(it.system.categorie, 'enchanté') && !it.system.prpermanent) | ||||
|   async $perteReveEnchantementsChateauDormants() { | ||||
|     const toUpdate = this.items.filter(it => [ITEM_TYPES.potion, ITEM_TYPES.gemme].includes(it.type)) | ||||
|       .map(it => it.perteReveChateauDormant()) | ||||
|       .filter(it => it != undefined) | ||||
|  | ||||
|     const potionUpdates = await Promise.all(potions.map(async it => { | ||||
|       const nouveauReve = Math.max(it.system.pr - 1, 0) | ||||
|     if (toUpdate.length > 0) { | ||||
|       console.log('perte de rêve des enchantements', toUpdate) | ||||
|       const messageUpdates = await Promise.all( | ||||
|         toUpdate.map(async it => await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-pertereve-enchantement-chateaudormant.hbs`, it))) | ||||
|       ChatMessage.create({ | ||||
|         whisper: ChatUtility.getOwners(this), | ||||
|         content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, { | ||||
|           pr: nouveauReve, | ||||
|           alias: this.getAlias(), | ||||
|           potionName: it.name, | ||||
|           potionImg: it.img | ||||
|         }) | ||||
|         content: messageUpdates.reduce(Misc.joining('<br>')) | ||||
|       }) | ||||
|       return { | ||||
|         _id: it._id, | ||||
|         'system.pr': nouveauReve, | ||||
|         'system.quantite': nouveauReve > 0 ? it.system.quantite : 0 | ||||
|       } | ||||
|     })) | ||||
|       await this.updateEmbeddedDocuments('Item', toUpdate.map(it => it.update)); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|     await this.updateEmbeddedDocuments('Item', potionUpdates); | ||||
|   async $suppressionLancementsSort() { | ||||
|     const updates = this.itemTypes[ITEM_TYPES.sort] | ||||
|       .filter(it => it.system.lancements.length > 0) | ||||
|       .map(it => { return { _id: it.id, 'system.lancements': [] } }) | ||||
|     if (updates.length > 0) { | ||||
|       await this.updateEmbeddedDocuments('Item', updates) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** -------------------------------------------- | ||||
| @@ -245,7 +246,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   async _recuperationSante(message) { | ||||
|     const maladiesPoisons = this.getMaladiePoisons(); | ||||
|     const maladiesPoisons = this.getMaladiesPoisons(); | ||||
|     const isMaladeEmpoisonne = maladiesPoisons.length > 0; | ||||
|     this._messageRecuperationMaladiePoisons(maladiesPoisons, message); | ||||
|  | ||||
| @@ -253,7 +254,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     await this._recupererVie(message, isMaladeEmpoisonne); | ||||
|   } | ||||
|  | ||||
|   getMaladiePoisons() { | ||||
|   getMaladiesPoisons() { | ||||
|     return this.items.filter(item => item.type == 'maladie' || (item.type == 'poison' && item.system.active)); | ||||
|   } | ||||
|  | ||||
| @@ -283,13 +284,14 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       }; | ||||
|  | ||||
|       await this._recuperationSante(message) | ||||
|       await this._recupereMoralChateauDormant(message); | ||||
|       await this._recupereChance(); | ||||
|       await this.transformerStress(); | ||||
|       await this.retourSeuilDeReve(message); | ||||
|       await this.setBonusPotionSoin(0); | ||||
|       await this.retourSust(message); | ||||
|       await this.$perteRevePotionsEnchantees(); | ||||
|       await this._recupereMoralChateauDormant(message) | ||||
|       await this._recupereChance() | ||||
|       await this.transformerStress() | ||||
|       await this.retourSeuilDeReve(message) | ||||
|       await this.setBonusPotionSoin(0) | ||||
|       await this.retourSust(message) | ||||
|       await this.$perteReveEnchantementsChateauDormants() | ||||
|       await this.$suppressionLancementsSort() | ||||
|       await RdDCoeur.applyCoeurChateauDormant(this, message) | ||||
|       if (message.content != "") { | ||||
|         message.content = `A la fin Chateau Dormant, ${message.content}<br>Un nouveau jour se lève`; | ||||
| @@ -413,19 +415,18 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async remiseANeuf() { | ||||
|     ChatMessage.create({ | ||||
|       whisper: ChatUtility.getOwners(this), | ||||
|       content: 'Remise à neuf de ' + this.name | ||||
|     }); | ||||
|     await this.supprimerBlessures(it => true); | ||||
|     await this.removeEffects(e => e.id != STATUSES.StatusDemiReve); | ||||
|     const updates = { | ||||
|     await this.update({ | ||||
|       'system.sante.endurance.value': this.system.sante.endurance.max, | ||||
|       'system.sante.vie.value': this.system.sante.vie.max, | ||||
|       'system.sante.fatigue.value': 0, | ||||
|       'system.compteurs.ethylisme': { value: 1, nb_doses: 0, jet_moral: false } | ||||
|     }; | ||||
|     await this.update(updates); | ||||
|     }) | ||||
|     await this.removeEffects(e => e.id != STATUSES.StatusDemiReve); | ||||
|     await this.supprimerBlessures(it => true); | ||||
|     await ChatMessage.create({ | ||||
|       whisper: ChatUtility.getOwners(this), | ||||
|       content: 'Remise à neuf de ' + this.name | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -529,7 +530,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         jet_moral: false, | ||||
|         value: value | ||||
|       } | ||||
|     }); | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -662,15 +663,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); | ||||
|       } | ||||
| @@ -993,13 +994,10 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async addSortReserve(itemId) { | ||||
|     if (itemId) { | ||||
|       const item = this.items.get(itemId) | ||||
|       if (item.type == ITEM_TYPES.sort && !item.system.isrituel) { | ||||
|         this.$createSortReserve(item) | ||||
|         return | ||||
|       } | ||||
|   async addSortReserve(item) { | ||||
|     if (item?.type == ITEM_TYPES.sort && !item.system.isrituel) { | ||||
|       this.$createSortReserve(item) | ||||
|       return | ||||
|     } | ||||
|     const selectSortReserve = { | ||||
|       title: "Créer un sort en réserve", | ||||
| @@ -1203,42 +1201,6 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     new RdDRollDialogEthylisme(html, rollData, this, r => this.saouler(r.forceAlcool)).render(true); | ||||
|   } | ||||
|  | ||||
|   async actionPrincipale(item, onActionItem = async () => { }) { | ||||
|     let result = await super.actionPrincipale(item, onActionItem) | ||||
|     if (result) { return result } | ||||
|  | ||||
|     result = await this.actionNourritureboisson(item, onActionItem) | ||||
|     if (result) { return result } | ||||
|  | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.potion: return await this.consommerPotion(item, onActionItem); | ||||
|       case ITEM_TYPES.livre: return await this.actionLire(item); | ||||
|       case ITEM_TYPES.conteneur: return await item.sheet.render(true); | ||||
|       case ITEM_TYPES.herbe: return await this.actionHerbe(item, onActionItem); | ||||
|       case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return await this.actionRefoulement(item); | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
|   async actionNourritureboisson(item, onActionItem) { | ||||
|     switch (item.getUtilisationCuisine()) { | ||||
|       case 'brut': { | ||||
|         const utilisation = new Dialog({ | ||||
|           title: "Nourriture brute", | ||||
|           content: `Que faire de votre ${item.name}`, | ||||
|           buttons: { | ||||
|             'cuisiner': { icon: '<i class="fa-solid fa-utensils"></i>', label: 'Cuisiner', callback: async () => await this.preparerNourriture(item) }, | ||||
|             'manger': { icon: '<i class="fa-solid fa-drumstick-bite"></i>', label: 'Manger cru', callback: async () => await this.mangerNourriture(item, onActionItem) } | ||||
|           } | ||||
|         }); | ||||
|         return utilisation.render(true); | ||||
|       } | ||||
|       case 'pret': | ||||
|         return await this.mangerNourriture(item, onActionItem); | ||||
|     } | ||||
|     return undefined; | ||||
|   } | ||||
|  | ||||
|   async mangerNourriture(item, onActionItem) { | ||||
|     return (await DialogConsommer.create(this, item, onActionItem)).render(true); | ||||
|   } | ||||
| @@ -1250,9 +1212,9 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async actionHerbe(item, onActionItem = async () => { }) { | ||||
|   async fabriquerDecoctionHerbe(item) { | ||||
|     if (item.isHerbeAPotion()) { | ||||
|       return DialogFabriquerPotion.create(this, item, onActionItem); | ||||
|       return DialogFabriquerPotion.create(this, item); | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
| @@ -1387,7 +1349,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 +1381,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 +1558,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) | ||||
| @@ -1772,6 +1734,17 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         if (rollData.isSortReserve) { | ||||
|           await this.sortMisEnReserve(selectedSort, rollData.competence, rollData.tmr.coord, Number(selectedSort.system.ptreve_reel)); | ||||
|         } | ||||
|         else { | ||||
|           console.log('lancement de sort', rollData.selectedSort) | ||||
|           const precedents = rollData.selectedSort.system.lancements ?? [] | ||||
|           const lancements = [...precedents, { | ||||
|             timestamp: game.system.rdd.calendrier.getTimestamp(), | ||||
|             reve: rollData.selectedSort.system.ptreve_reel | ||||
|           }] | ||||
|           await this.updateEmbeddedDocuments('Item', | ||||
|             [{ _id: rollData.selectedSort._id, 'system.lancements': lancements }] | ||||
|           ) | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|         rollData.depenseReve = 0; | ||||
| @@ -1799,38 +1772,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 +1823,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) | ||||
| @@ -1941,8 +1864,8 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|     rollData.tache.system.tentatives = rollData.tache.system.nb_jet_succes + rollData.tache.system.nb_jet_echec; | ||||
|  | ||||
|     this.updateEmbeddedDocuments('Item', [rollData.tache]); | ||||
|     this.santeIncDec("fatigue", rollData.tache.system.fatigue); | ||||
|     await this.updateEmbeddedDocuments('Item', [rollData.tache]); | ||||
|     await this.santeIncDec("fatigue", rollData.tache.system.fatigue); | ||||
|  | ||||
|     await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-tache.html'); | ||||
|     if (options?.onRollAutomate) { | ||||
| @@ -2620,8 +2543,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async equiperObjet(itemID) { | ||||
|     let item = this.getEmbeddedDocument('Item', itemID); | ||||
|   async equiperObjet(item) { | ||||
|     if (item?.isEquipable()) { | ||||
|       const isEquipe = !item.system.equipe; | ||||
|       await item.update({ "system.equipe": isEquipe }); | ||||
| @@ -2640,7 +2562,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     for (const armure of armures) { | ||||
|       protection += await RdDDice.rollTotal(armure.system.protection.toString()); | ||||
|       if (dmg > 0 && attackerRoll.dmg.encaisserSpecial != "noarmure") { | ||||
|         armure.deteriorerArmure(dmg); | ||||
|         await armure.deteriorerArmure(dmg) | ||||
|         dmg = 0; | ||||
|       } | ||||
|     } | ||||
| @@ -2946,12 +2868,13 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async fabriquerPotion(herbeData) { | ||||
|     let newPotion = { | ||||
|     const newPotion = { | ||||
|       name: `Potion de ${herbeData.system.categorie} (${herbeData.name})`, type: 'potion', | ||||
|       img: "systems/foundryvtt-reve-de-dragon/icons/objets/fiole_verre.webp", | ||||
|       system: { | ||||
|         quantite: 1, cout: 0, encombrement: 0.1, | ||||
|         categorie: herbeData.system.categorie, | ||||
|         etat: 'Liquide', | ||||
|         herbe: herbeData.name, | ||||
|         rarete: herbeData.system.rarete, | ||||
|         herbebrins: herbeData.nbBrins, | ||||
| @@ -2959,29 +2882,23 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         description: "" | ||||
|       } | ||||
|     } | ||||
|     await this.createEmbeddedDocuments('Item', [newPotion], { renderSheet: true }); | ||||
|  | ||||
|     let newQuantite = herbeData.system.quantite - herbeData.nbBrins; | ||||
|     let messageData = { | ||||
|       alias: this.getAlias(), | ||||
|       nbBrinsReste: newQuantite, | ||||
|       potion: newPotion, | ||||
|       herbe: herbeData | ||||
|     } | ||||
|     this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins); | ||||
|     await this.createEmbeddedDocuments('Item', [newPotion]) | ||||
|     await this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins) | ||||
|  | ||||
|     ChatMessage.create({ | ||||
|       whisper: ChatUtility.getOwners(this), | ||||
|       content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html`, messageData) | ||||
|     }); | ||||
|       content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html`, { | ||||
|         alias: this.getAlias(), | ||||
|         nbBrinsReste: herbeData.system.quantite - herbeData.nbBrins, | ||||
|         potion: newPotion, | ||||
|         herbe: herbeData | ||||
|       }) | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async diminuerQuantiteObjet(id, nb, options = { supprimerSiZero: false }) { | ||||
|     const item = this.getItem(id); | ||||
|     if (item) { | ||||
|       await item.diminuerQuantite(nb, options); | ||||
|     } | ||||
|     await this.getItem(id)?.diminuerQuantite(nb, options); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDSheetUtility } from "../rdd-sheet-utility.js"; | ||||
| import { RdDBaseActorSheet } from "./base-actor-sheet.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 | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import { RdDRoll } from "../rdd-roll.js"; | ||||
| import { RdDUtility } from "../rdd-utility.js"; | ||||
| import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; | ||||
| import { RdDBaseActor } from "./base-actor.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDItemCompetence } from "../item-competence.js"; | ||||
| import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; | ||||
| import { RdDItemArme } from "../item-arme.js"; | ||||
| @@ -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) | ||||
|     }); | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { RdDUtility } from "../rdd-utility.js"; | ||||
| import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; | ||||
| import { STATUSES } from "../settings/status-effects.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDBaseActorReve } from "./base-actor-reve.js"; | ||||
| import { RdDDice } from "../rdd-dice.js"; | ||||
| import { RdDItemBlessure } from "../item/blessure.js"; | ||||
|   | ||||
| @@ -3,8 +3,11 @@ import { Misc } from "../misc.js"; | ||||
| import { DialogSplitItem } from "../dialog-split-item.js"; | ||||
| import { RdDSheetUtility } from "../rdd-sheet-utility.js"; | ||||
| import { Monnaie } from "../item-monnaie.js"; | ||||
| import { RdDItem, ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"; | ||||
| import { ItemAction } from "../item/item-actions.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| /** | ||||
| @@ -25,7 +28,7 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async getData() { | ||||
|     Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']); | ||||
|     Monnaie.validerMonnaies(this.actor) | ||||
|  | ||||
|     this.actor.computeEtatGeneral(); | ||||
|     let formData = { | ||||
| @@ -35,13 +38,13 @@ 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 | ||||
|     } | ||||
|  | ||||
|     RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); | ||||
|     RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); | ||||
|     formData.calc = { | ||||
|       fortune: Monnaie.toSolsDeniers(this.actor.getFortune()), | ||||
|       prixTotalEquipement: this.actor.computePrixTotalEquipement(), | ||||
| @@ -53,6 +56,7 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|     formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs); | ||||
|     formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature) | ||||
|       .forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it)) | ||||
|  | ||||
|     return formData; | ||||
|   } | ||||
|  | ||||
| @@ -76,95 +80,36 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static filterItemsPerTypeForSheet(formData, itemTypes) { | ||||
|     formData.blessures = Misc.arrayOrEmpty(itemTypes['blessure']); | ||||
|     formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']); | ||||
|     formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']); | ||||
|     formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']); | ||||
|     formData.poisons = Misc.arrayOrEmpty(itemTypes['poison']); | ||||
|     formData.possessions = Misc.arrayOrEmpty(itemTypes['possession']); | ||||
|     formData.maladiesPoisons = formData.maladies.concat(formData.poisons); | ||||
|     formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []); | ||||
|     formData.sortsReserve = Misc.arrayOrEmpty(itemTypes['sortreserve']); | ||||
|  | ||||
|     formData.sorts = Misc.arrayOrEmpty(itemTypes['sort']); | ||||
|     formData.rencontres = Misc.arrayOrEmpty(itemTypes['rencontre']); | ||||
|     formData.casestmr = Misc.arrayOrEmpty(itemTypes['casetmr']); | ||||
|     formData.signesdraconiques = Misc.arrayOrEmpty(itemTypes['signedraconique']); | ||||
|     formData.queues = Misc.arrayOrEmpty(itemTypes['queue']); | ||||
|     formData.souffles = Misc.arrayOrEmpty(itemTypes['souffle']); | ||||
|     formData.ombres = Misc.arrayOrEmpty(itemTypes['ombre']); | ||||
|     formData.tetes = Misc.arrayOrEmpty(itemTypes['tete']); | ||||
|     formData.taches = Misc.arrayOrEmpty(itemTypes['tache']); | ||||
|     formData.meditations = Misc.arrayOrEmpty(itemTypes['meditation']); | ||||
|     formData.chants = Misc.arrayOrEmpty(itemTypes['chant']); | ||||
|     formData.danses = Misc.arrayOrEmpty(itemTypes['danse']); | ||||
|     formData.musiques = Misc.arrayOrEmpty(itemTypes['musique']); | ||||
|     formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']); | ||||
|     formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']); | ||||
|  | ||||
|     formData.services = Misc.arrayOrEmpty(itemTypes['service']); | ||||
|     formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']); | ||||
|     formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']); | ||||
|     formData.armes = Misc.arrayOrEmpty(itemTypes['arme']); | ||||
|     formData.armures = Misc.arrayOrEmpty(itemTypes['armure']); | ||||
|     formData.munitions = Misc.arrayOrEmpty(itemTypes['munition']); | ||||
|     formData.livres = Misc.arrayOrEmpty(itemTypes['livre']); | ||||
|     formData.potions = Misc.arrayOrEmpty(itemTypes['potion']); | ||||
|     formData.plantes = Misc.arrayOrEmpty(itemTypes['plante']); | ||||
|     formData.ingredients = Misc.arrayOrEmpty(itemTypes['ingredient']); | ||||
|     formData.faunes = Misc.arrayOrEmpty(itemTypes['faune']); | ||||
|     formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']); | ||||
|     formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']); | ||||
|     formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']); | ||||
|     formData.monnaies = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere()); | ||||
|     formData.objets = Misc.arrayOrEmpty(itemTypes['objet']) | ||||
|  | ||||
|     formData.inventaires = RdDItem.getItemTypesInventaire('all') | ||||
|       .map(t => Misc.arrayOrEmpty(itemTypes[t])) | ||||
|       .reduce((a, b) => a.concat(b), []) | ||||
|       .sort(Misc.ascending(it => it.name)); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */  /** @override */ | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     this.html = html; | ||||
|  | ||||
|     this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options)) | ||||
|     this.html.find('.item-edit').click(async event => this.itemActionEdit(event)) | ||||
|     this.html.find('.conteneur-name a').click(async event => { | ||||
|       RdDUtility.toggleAfficheContenu(this.getItemId(event)); | ||||
|       this.render(true); | ||||
|     }); | ||||
|       RdDUtility.toggleAfficheContenu(this.getItemId(event)) | ||||
|       this.render(true) | ||||
|     }) | ||||
|  | ||||
|     this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat()); | ||||
|     this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true)) | ||||
|     this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat()); | ||||
|  | ||||
|     this.html.find('.recherche') | ||||
|       .each((index, field) => { | ||||
|         this._rechercheSelectArea(field); | ||||
|       }) | ||||
|       .keyup(async event => this._rechercherKeyup(event)) | ||||
|       .change(async event => this._rechercherKeyup(event)); | ||||
|     this.html.find('.recherche').prop("disabled", false); | ||||
|       .change(async event => this._rechercherKeyup(event)) | ||||
|  | ||||
|     this.html.find('.recherche').prop("disabled", false) | ||||
|  | ||||
|     // Everything below here is only needed if the sheet is editable | ||||
|     if (!this.options.editable) return; | ||||
|  | ||||
|     this.html.find('.item-action').click(async event => { | ||||
|       const item = RdDSheetUtility.getItem(event, this.actor); | ||||
|       item?.actionPrincipale(this.actor, async () => this.render()) | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     this.html.find('.item-split').click(async event => { | ||||
|       const item = this.getItem(event); | ||||
|       RdDSheetUtility.splitItem(item, this.actor); | ||||
|     }); | ||||
|     this.html.find('.item-equip-armure').click(async event => this.actor.equiperObjet(this.getItem(event))) | ||||
|     this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this.getItem(event), this.actor)); | ||||
|     this.html.find('.item-quantite-plus').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), 1)); | ||||
|     this.html.find('.item-quantite-moins').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), -1)); | ||||
|     this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event))); | ||||
|     this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event))); | ||||
|  | ||||
|     this.html.find('.creer-un-objet').click(async event => { | ||||
|       this.selectObjetTypeToCreate(); | ||||
| @@ -179,6 +124,11 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   itemActionEdit(event) { | ||||
|     const item = this.getItem(event); | ||||
|     return item?.sheet.render(true); | ||||
|   } | ||||
|  | ||||
|   _rechercherKeyup(event) { | ||||
|     const currentTarget = event.currentTarget; | ||||
|     const nouvelleRecherche = this._optionRecherche(currentTarget); | ||||
| @@ -245,7 +195,7 @@ export class RdDBaseActorSheet extends ActorSheet { | ||||
|   /* -------------------------------------------- */ | ||||
|   async selectObjetTypeToCreate() { | ||||
|     let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type))); | ||||
|     let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`; | ||||
|     let content = `<span class="generic-label">Selectionnez le type d'équipement</span><select class="item-type">`; | ||||
|     for (let typeName of types) { | ||||
|       content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>` | ||||
|     } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import { ChatUtility } from "../chat-utility.js"; | ||||
| import { SYSTEM_SOCKET_ID } from "../constants.js"; | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { Monnaie } from "../item-monnaie.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
| import { RdDAudio } from "../rdd-audio.js"; | ||||
| import { RdDConfirm } from "../rdd-confirm.js"; | ||||
| @@ -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': | ||||
| @@ -735,25 +737,20 @@ export class RdDBaseActor extends Actor { | ||||
|  | ||||
|   actionImpossible(action) { | ||||
|     ui.notifications.info(`${this.getAlias()} ne peut pas faire cette action: ${action}`) | ||||
|  | ||||
|   } | ||||
|  | ||||
|   async jetEthylisme() { this.actionImpossible("jet d'éthylisme") } | ||||
|   async rollAppelChance() { this.actionImpossible("appel à la chance") } | ||||
|   async jetDeMoral() { this.actionImpossible("jet de moral") } | ||||
|  | ||||
|   async actionPrincipale(item, onActionItem = async () => { }) { | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.conteneur: return await item.sheet.render(true); | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|   async resetItemUse() { } | ||||
|   async incDecItemUse(itemId, inc = 1) { } | ||||
|   getItemUse(itemId) { return 0; } | ||||
|  | ||||
|   async finDeRound(options = { terminer: false }) { } | ||||
|   isActorCombat() { return false } | ||||
|   getCaracInit(competence) { return 0 } | ||||
|  | ||||
|   listActionsCombat() { return [] } | ||||
|   listActionsPossessions() { | ||||
|     return this.itemTypes[ITEM_TYPES.possession] | ||||
|   | ||||
| @@ -45,6 +45,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet { | ||||
|     super.activateListeners(html); | ||||
|  | ||||
|     this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event))); | ||||
|     this.html.find('.service-acheter').click(async event => await this.vente(this.getItem(event))); | ||||
|  | ||||
|     if (!this.options.editable) return; | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,6 @@ | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { ITEM_TYPES } from "../constants.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 | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
| import { RdDCarac } from "../rdd-carac.js"; | ||||
| import { RdDEncaisser } from "../rdd-roll-encaisser.js"; | ||||
| @@ -117,4 +117,14 @@ export class RdDEntite extends RdDBaseActorReve { | ||||
|       super.setEntiteReveAccordee(actor) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   mapCarac(caracCode) { | ||||
|     switch (caracCode) { | ||||
|       case 'taille': | ||||
|       case 'reve': | ||||
|         return caracCode | ||||
|     } | ||||
|     return 'reve' | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -6,8 +6,8 @@ import { ExportScriptarium } from "./export-scriptarium.js"; | ||||
| import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js"; | ||||
|  | ||||
| export class RdDActorExportSheet extends RdDActorSheet { | ||||
|   static async init() { | ||||
|     await loadTemplates([ | ||||
|   static init() { | ||||
|     loadTemplates([ | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs", | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs", | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs", | ||||
| @@ -23,6 +23,7 @@ export class RdDActorExportSheet extends RdDActorSheet { | ||||
|     ]) | ||||
|     Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille simplifiée" }) | ||||
|   } | ||||
|  | ||||
|   static get defaultOptions() { | ||||
|     return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, { | ||||
|       template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs", | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { ACTOR_TYPES } from "../../item.js" | ||||
| import { ACTOR_TYPES } from "../../constants.js" | ||||
| import { Misc } from "../../misc.js" | ||||
| import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js" | ||||
| import { Mapping } from "./mapping.js" | ||||
|   | ||||
| @@ -2,7 +2,7 @@ import { Grammar } from "../../grammar.js" | ||||
| import { RdDItemArme } from "../../item-arme.js" | ||||
| import { RdDItemCompetence } from "../../item-competence.js" | ||||
| import { RdDItemSort } from "../../item-sort.js" | ||||
| import { ITEM_TYPES } from "../../item.js" | ||||
| import { ITEM_TYPES } from "../../constants.js" | ||||
| import { Misc } from "../../misc.js" | ||||
| import { RdDTimestamp } from "../../time/rdd-timestamp.js" | ||||
| import { RdDBonus } from "../../rdd-bonus.js" | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import { Grammar } from "../grammar.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
| import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js"; | ||||
| import { RdDItemTete } from "../item/tete.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
|  | ||||
| const WHITESPACES = "\\s+" | ||||
| const NUMERIC = "[\\+\\-]?\\d+" | ||||
| @@ -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 "../constants.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 "../../constants.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('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 : [ | ||||
| @@ -50,4 +50,59 @@ export const RDD_CONFIG = { | ||||
|     {value: "Rare", label: "Rare"}, | ||||
|     {value: "Rarissime", label: "Rarissime"} | ||||
|   ] | ||||
| } | ||||
| } | ||||
|  | ||||
| export const ACTOR_TYPES = { | ||||
|   personnage: 'personnage', | ||||
|   creature: 'creature', | ||||
|   entite: 'entite', | ||||
|   commerce: 'commerce', | ||||
|   vehicule: 'vehicule' | ||||
| } | ||||
|  | ||||
| export const ITEM_TYPES = { | ||||
|   competence: 'competence', | ||||
|   competencecreature: 'competencecreature', | ||||
|   empoignade: 'empoignade', | ||||
|   possession: 'possession', | ||||
|   blessure: 'blessure', | ||||
|   maladie: 'maladie', | ||||
|   poison: 'poison', | ||||
|   arme: 'arme', | ||||
|   armure: 'armure', | ||||
|   conteneur: 'conteneur', | ||||
|   objet: 'objet', | ||||
|   monnaie: 'monnaie', | ||||
|   gemme: 'gemme', | ||||
|   munition: 'munition', | ||||
|   nourritureboisson: 'nourritureboisson', | ||||
|   herbe: 'herbe', | ||||
|   plante: 'plante', | ||||
|   ingredient: 'ingredient', | ||||
|   faune: 'faune', | ||||
|   livre: 'livre', | ||||
|   potion: 'potion', | ||||
|   service: 'service', | ||||
|   musique: 'musique', | ||||
|   danse: 'danse', | ||||
|   chant: 'chant', | ||||
|   jeu: 'jeu', | ||||
|   race: 'race', | ||||
|   recettecuisine: 'recettecuisine', | ||||
|   oeuvre: 'oeuvre', | ||||
|   recettealchimique: 'recettealchimique', | ||||
|   tache: 'tache', | ||||
|   sort: 'sort', | ||||
|   sortreserve: 'sortreserve', | ||||
|   rencontre: 'rencontre', | ||||
|   queue: 'queue', | ||||
|   ombre: 'ombre', | ||||
|   souffle: 'souffle', | ||||
|   tete: 'tete', | ||||
|   casetmr: 'casetmr', | ||||
|   meditation: 'meditation', | ||||
|   signedraconique: 'signedraconique', | ||||
|   tarot: 'tarot', | ||||
|   nombreastral: 'nombreastral', | ||||
|   extraitpoetique: 'extraitpoetique', | ||||
| } | ||||
|   | ||||
| @@ -1,88 +1,79 @@ | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
| import { RdDUtility } from "./rdd-utility.js"; | ||||
|  | ||||
| export class DialogFabriquerPotion extends Dialog { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async create(actor, item, onActionItem) { | ||||
|     const min = DialogFabriquerPotion.nombreBrinsMinimum(item); | ||||
|     if (item.system.quantite < min) { | ||||
|       ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${min} pour faire une potion!`); | ||||
|       return; | ||||
|   static async create(actor, item) { | ||||
|     const brinsMinimum = DialogFabriquerPotion.nombreBrinsMinimum(item) | ||||
|     if (item.system.quantite < brinsMinimum) { | ||||
|       ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${brinsMinimum} pour faire une potion!`) | ||||
|       return | ||||
|     } | ||||
|     let potionData = DialogFabriquerPotion.prepareData(actor, item); | ||||
|     const potionData = DialogFabriquerPotion.prepareData(item, brinsMinimum) | ||||
|     const options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 } | ||||
|     const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData) | ||||
|  | ||||
|     const html = await renderTemplate( 'systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData); | ||||
|  | ||||
|     let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 }; | ||||
|     new DialogFabriquerPotion(actor, potionData, onActionItem, html, options).render(true); | ||||
|     new DialogFabriquerPotion(actor, potionData, html, options).render(true) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static prepareData(actor, item) { | ||||
|     let potionData = foundry.utils.duplicate(item) | ||||
|     potionData.nbBrinsSelect = RdDUtility.buildListOptions( | ||||
|       DialogFabriquerPotion.nombreBrinsMinimum(item), | ||||
|       DialogFabriquerPotion.nombreBrinsOptimal(item)); | ||||
|     potionData.nbBrins = Math.min(potionData.system.quantite, DialogFabriquerPotion.nombreBrinsOptimal(potionData)); | ||||
|     potionData.herbebonus = item.system.niveau; | ||||
|     potionData.buttonName = "Fabriquer"; | ||||
|     return potionData; | ||||
|   static prepareData(item, brinsMinimum) { | ||||
|     const brinsOptimal = DialogFabriquerPotion.nombreBrinsOptimal(item) | ||||
|     return foundry.utils.mergeObject(foundry.utils.duplicate(item), { | ||||
|       nbBrinsSelect: RdDUtility.buildListOptions(brinsMinimum, brinsOptimal), | ||||
|       nbBrins: Math.min(item.system.quantite, brinsOptimal), | ||||
|       herbebonus: item.system.niveau | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   constructor(actor, potionData, onActionItem, html, options) { | ||||
|   constructor(actor, potionData, html, options) { | ||||
|     const conf = { | ||||
|       title: `Fabriquer une potion de ${potionData.system.categorie}`, | ||||
|       content: html, | ||||
|       default: 'fabriquer', | ||||
|       buttons: { | ||||
|         'fabriquer': { | ||||
|           label: potionData.buttonName, callback: it => this.onFabriquer() | ||||
|         } | ||||
|         'fabriquer': { label: "Fabriquer", callback: it => this.onFabriquer() } | ||||
|       } | ||||
|     }; | ||||
|     } | ||||
|     super(conf, options) | ||||
|  | ||||
|     super(conf, options); | ||||
|  | ||||
|     this.actor = actor; | ||||
|     this.potionData = potionData; | ||||
|     this.onActionItem = onActionItem; | ||||
|     this.actor = actor | ||||
|     this.potionData = potionData | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     this.html = html; | ||||
|     super.activateListeners(html) | ||||
|     this.html = html | ||||
|     this.html.find("[name='nbBrins']").change(event => { | ||||
|       this.potionData.nbBrins = Misc.toInt(event.currentTarget.value); | ||||
|       const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins); | ||||
|       this.potionData.nbBrins = Misc.toInt(event.currentTarget.value) | ||||
|       const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins) | ||||
|       this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants) | ||||
|     }); | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async onFabriquer() { | ||||
|     await this.html.find("[name='nbBrins']").change(); | ||||
|     await this.actor.fabriquerPotion(this.potionData); | ||||
|     this.close(); | ||||
|     await this.onActionItem() | ||||
|     await this.html.find("[name='nbBrins']").change() | ||||
|     await this.actor.fabriquerPotion(this.potionData) | ||||
|     this.close() | ||||
|   } | ||||
|  | ||||
|   static nombreBrinsMinimum(herbeData) { | ||||
|     switch (herbeData.system.categorie ?? '') { | ||||
|       case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau); | ||||
|       case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau); | ||||
|       case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau) | ||||
|       case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau) | ||||
|     } | ||||
|     return 1; | ||||
|     return 1 | ||||
|   } | ||||
|  | ||||
|   static nombreBrinsOptimal(herbeData) { | ||||
|     switch (herbeData.system.categorie ?? '') { | ||||
|       case "Soin": return 12 - herbeData.system.niveau; | ||||
|       case "Repos": return 7 - herbeData.system.niveau; | ||||
|       case "Soin": return 12 - herbeData.system.niveau | ||||
|       case "Repos": return 7 - herbeData.system.niveau | ||||
|     } | ||||
|     return 1; | ||||
|     return 1 | ||||
|   } | ||||
| } | ||||
							
								
								
									
										177
									
								
								module/enchantement/dialog-enchanter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								module/enchantement/dialog-enchanter.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| import { ITEM_TYPES } from "../constants.js" | ||||
| import { RdDItemSort } from "../item-sort.js" | ||||
| import { Misc } from "../misc.js" | ||||
|  | ||||
| export const ACTION_ITEM_ENCHANTER =  { | ||||
|   code: 'item-enchanter', label: 'Enchanter', icon: it => 'fa-solid fa-sparkles', | ||||
|   filter: it => game.user.isGM || DialogEnchanter.isEnchantable(it), | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => DialogEnchanter.enchanter(item) | ||||
| } | ||||
|  | ||||
| export class DialogEnchanter extends Dialog { | ||||
|  | ||||
|   static isEnchantable(item) { | ||||
|     if (!item.isEnchantementPossible) { | ||||
|       return false | ||||
|     } | ||||
|     if (game.user.isGM) { | ||||
|       return true | ||||
|     } | ||||
|     if (item.system.prpermanent) { | ||||
|       return false | ||||
|     } | ||||
|     if (!item.parent?.isHautRevant()) { | ||||
|       return false | ||||
|     } | ||||
|     return RdDItemSort.lancements(RdDItemSort.findEnchantement(item.parent)) > 0 | ||||
|       || RdDItemSort.lancements(RdDItemSort.findPurification(item.parent)) > 0 | ||||
|       || RdDItemSort.lancements(RdDItemSort.findPermanence(item.parent)) > 0 | ||||
|   } | ||||
|  | ||||
|   static dateEnchantement() { | ||||
|     return game.system.rdd.calendrier.getTimestamp().debutJournee().indexDate | ||||
|   } | ||||
|  | ||||
|   static async enchanter(item) { | ||||
|     const actor = item.parent | ||||
|     const sorts = { | ||||
|       enchantement: RdDItemSort.findEnchantement(actor), | ||||
|       purification: RdDItemSort.findPurification(actor), | ||||
|       permanence: RdDItemSort.findPermanence(actor) | ||||
|     } | ||||
|     const nouveauxpr = (sorts.enchantement?.system.lancements ?? []).map(it => it.reve) | ||||
|     const purification = (sorts.purification?.system.lancements ?? []).find(it => true) | ||||
|     const permanence = (sorts.permanence?.system.lancements ?? []).find(it => true) | ||||
|  | ||||
|     const enchanter = { | ||||
|       type: item.type == ITEM_TYPES.potion ? 'potion' : Misc.typeName('Item', item.type), | ||||
|       actor: actor, | ||||
|       item: item, | ||||
|       reve: item.system.pr, | ||||
|       sorts: sorts, | ||||
|       nouveauxpr: nouveauxpr, | ||||
|       purification: purification != undefined, | ||||
|       permanence: permanence != undefined, | ||||
|       options: { isGM: game.user.isGM } | ||||
|     } | ||||
|     if (!item.isEnchantementPossible) { | ||||
|       ui.notifications.info("Seuls les liquides et les gemmes sont enchantables") | ||||
|       return | ||||
|     } | ||||
|     if (item.system.prpermanent) { | ||||
|       ui.notifications.info(`La ${enchanter.type} est permanente`) | ||||
|       return | ||||
|     } | ||||
|     if (!game.user.isGM) { | ||||
|       if (!(actor?.isPersonnage() || actor?.isHautRevant())) { | ||||
|         ui.notifications.info(`Seul un haut rêvant peut enchanter une ${enchanter.type}`) | ||||
|         return | ||||
|       } | ||||
|       if (item.system.quantite != 1) { | ||||
|         ui.notifications.info(`Impossible d'enchanter ${item.system.quantite} ${enchanter.type}s ${item.system.quantite > 1 ? 'en une seule fois' : ''}`) | ||||
|         return | ||||
|       } | ||||
|       if (!(nouveauxpr.length > 0 || purification || permanence)) { | ||||
|         ui.notifications.info("Le haut-rêvant n'a lancé de rituel d'enchantement") | ||||
|         return | ||||
|       } | ||||
|       if (item.system.magique && item.system.purifie && !purification && !permanence) { | ||||
|         ui.notifications.info(`La ${enchanter.type} est déjà enchantée et doit être purifiée`) | ||||
|         return | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/enchantement/dialog-enchanter.hbs`, enchanter) | ||||
|     const dialog = new DialogEnchanter(enchanter, html) | ||||
|     dialog.render(true) | ||||
|   } | ||||
|  | ||||
|   constructor(enchanter, html) { | ||||
|     let options = { classes: ["dialog-enchanter"], width: 400, height: 'fit-content', 'z-index': 99999 } | ||||
|     let conf = { | ||||
|       title: `Enchanter une ${enchanter.type}`, | ||||
|       content: html, | ||||
|       default: "enchanter", | ||||
|       buttons: { | ||||
|         "enchanter": { label: "Enchanter", callback: it => this.onEnchanter() } | ||||
|       } | ||||
|     }; | ||||
|     super(conf, options) | ||||
|     this.html = html | ||||
|     this.enchanter = enchanter | ||||
|     this.item = enchanter.item | ||||
|   } | ||||
|  | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html) | ||||
|     this.html = html | ||||
|     this.html.find("input.enchantement").change(event => this.$onSelectEnchantement(event)) | ||||
|     this.html.find("input.reve").change(event => this.$onForceReve(event)) | ||||
|   } | ||||
|  | ||||
|   $onSelectEnchantement(event) { | ||||
|     const addReve = $(event.currentTarget).data('reve') | ||||
|     this.enchanter.idx = $(event.currentTarget).data('idx') | ||||
|     this.enchanter.reve = this.item.system.pr + Number(addReve) | ||||
|     this.html.find("input.reve").val(this.enchanter.reve) | ||||
|     for (let idx = 0; idx < this.enchanter.nouveauxpr.length; idx++) { | ||||
|       if (idx != this.enchanter.idx) { | ||||
|         this.html.find(`.enchantement[data-idx='${idx}']`).prop("checked", false) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   $onForceReve(event) { | ||||
|     const newReve = Number(event.currentTarget.value) | ||||
|     if (this.enchanter.reve != newReve) { | ||||
|       this.enchanter.idx = undefined | ||||
|     } | ||||
|     this.enchanter.reve = newReve | ||||
|   } | ||||
|  | ||||
|   async onEnchanter() { | ||||
|     foundry.utils.mergeObject(this.enchanter, | ||||
|       { | ||||
|         rendrepurifie: this.html.find("input.rendrepurifie").prop("checked"), | ||||
|         rendrepermanent: this.html.find("input.rendrepermanent").prop("checked"), | ||||
|         addreve: this.enchanter.reve != this.item.system.pr | ||||
|       }, | ||||
|       { inplace: true }) | ||||
|     const item = this.enchanter.item | ||||
|     const actor = this.enchanter.actor | ||||
|  | ||||
|     if (this.enchanter.reve == 0) { | ||||
|       await item.update({ | ||||
|         'system.pr': 0, | ||||
|         'system.magique': false, | ||||
|         'system.purifie': false, | ||||
|         'system.prpermanent': false, | ||||
|         'system.prdate': 0 | ||||
|       }) | ||||
|     } | ||||
|     else { | ||||
|       const isPurifiee = this.enchanter.addreve | ||||
|         ? (this.enchanter.rendrepurifie && (item.item.system.pr == 0 ? true : item.system.purifie)) | ||||
|         : (this.enchanter.rendrepurifie || item.system.purifie) | ||||
|       await item.update({ | ||||
|         'system.pr': this.enchanter.reve, | ||||
|         'system.magique': true, | ||||
|         'system.purifie': isPurifiee, | ||||
|         'system.prpermanent': item.system.prpermanent || this.enchanter.rendrepermanent, | ||||
|         'system.prdate': DialogEnchanter.dateEnchantement() | ||||
|       }) | ||||
|       if (actor) { | ||||
|         if (this.enchanter.rendrepurifie) { | ||||
|           await RdDItemSort.changeLancementsSort(this.enchanter.sorts.purification, it => it.slice(1)); | ||||
|         } | ||||
|         if (this.enchanter.rendrepermanent) { | ||||
|           await RdDItemSort.changeLancementsSort(this.enchanter.sorts.permanence, it => it.slice(1)); | ||||
|         } | ||||
|         if (this.enchanter.addreve && this.enchanter.idx != undefined) { | ||||
|           await RdDItemSort.changeLancementsSort(RdDItemSort.findEnchantement(actor), it => it.toSpliced(this.enchanter.idx, 1)) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { RdDItemCompetenceCreature } from "./item-competencecreature.js" | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { BASE_CORPS_A_CORPS } from "./item/base-items.js"; | ||||
| import { RdDCombatManager } from "./rdd-combat.js"; | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
|  | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { RdDCombatManager } from "./rdd-combat.js"; | ||||
|  | ||||
| export const CATEGORIES_COMPETENCES_CREATURES = { | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { Misc } from "./misc.js"; | ||||
| import { LOG_HEAD } from "./constants.js"; | ||||
| import { ITEM_TYPES, LOG_HEAD } from "./constants.js"; | ||||
|  | ||||
| const MONNAIE_ETAIN = { | ||||
|   name: "Denier (étain)", type: 'monnaie', | ||||
| @@ -70,18 +70,17 @@ export class Monnaie { | ||||
|   } | ||||
|  | ||||
|   static getFortune(monnaies) { | ||||
|     return (monnaies??[]) | ||||
|     return (monnaies ?? []) | ||||
|       .map(m => Number(m.system.cout) * Number(m.system.quantite)) | ||||
|       .reduce(Misc.sum(), 0); | ||||
|   } | ||||
|  | ||||
|   static async optimiserFortune(actor, fortune) { | ||||
|     Monnaie.validerMonnaies(actor) | ||||
|     let resteEnDeniers = Math.round(fortune * 100); | ||||
|     let monnaies = actor.itemTypes['monnaie']; | ||||
|     let updates = []; | ||||
|     Monnaie.validerMonnaies(monnaies, actor); | ||||
|     const updates = [] | ||||
|  | ||||
|     let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout)); | ||||
|     const  parValeur = Misc.classifyFirst(actor.itemTypes[ITEM_TYPES.monnaie], it => VALEUR_DENIERS(it.system.cout)); | ||||
|     for (let valeurDeniers of [1000, 100, 10, 1]) { | ||||
|       const itemPiece = parValeur[valeurDeniers]; | ||||
|       if (itemPiece) { | ||||
| @@ -102,8 +101,11 @@ export class Monnaie { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static validerMonnaies(monnaies, actor = undefined) { | ||||
|     monnaies.filter(it => VALEUR_DENIERS(it.system.cout) == 0) | ||||
|   static validerMonnaies(actor) { | ||||
|     if (!actor) { | ||||
|       return | ||||
|      } | ||||
|     actor.itemTypes[ITEM_TYPES.monnaie]?.filter(it => VALEUR_DENIERS(it.system.cout) == 0) | ||||
|       .map(it => `La  monnaie ${it.name} de l'acteur ${actor?.name ?? 'sélectionné'} a une valeur de 0!`) | ||||
|       .forEach(message => { | ||||
|         ui.notifications.warn(message); | ||||
|   | ||||
| @@ -1,9 +1,7 @@ | ||||
| import { ACTOR_TYPES, ITEM_TYPES } from "./constants.js"; | ||||
| 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"; | ||||
| import { HtmlUtility } from "./html-utility.js"; | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; | ||||
| import { SYSTEM_RDD } from "./constants.js"; | ||||
| @@ -12,8 +10,11 @@ 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 { RdDItem } from "./item.js"; | ||||
| import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; | ||||
| import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; | ||||
| import { ItemAction } from "./item/item-actions.js"; | ||||
| import { RdDItemGemme } from "./item/gemme.js"; | ||||
|  | ||||
| /** | ||||
|  * Extend the basic ItemSheet for RdD specific items | ||||
| @@ -26,8 +27,8 @@ export class RdDItemSheet extends ItemSheet { | ||||
|  | ||||
|   static defaultTemplate(type) { | ||||
|     return type ? | ||||
|       `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` : | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html"; | ||||
|       `systems/foundryvtt-reve-de-dragon/templates/item/${type}-sheet.hbs` : | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/item/item-sheet.hbs"; | ||||
|   } | ||||
|  | ||||
|   static register(sheetClass) { | ||||
| @@ -97,11 +98,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,26 +121,19 @@ 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 }) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.gemme) { | ||||
|       formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); | ||||
|       RdDGemme.calculDataDerivees(this.item) | ||||
|     } | ||||
|     if (this.item.type == ITEM_TYPES.potion) { | ||||
|       RdDHerbes.calculFormData(formData, this.item) | ||||
|       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.herbe) { | ||||
|       if (formData.options.isOwned && ['Soin', 'Repos'].includes(formData.system.categorie)) { | ||||
|         formData.isIngredientPotionBase = true; | ||||
| @@ -166,7 +160,7 @@ export class RdDItemSheet extends ItemSheet { | ||||
|     HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionnelles.isUsing('afficher-prix-joueurs') | ||||
|       || game.user.isGM | ||||
|       || !this.item.isOwned); | ||||
|     HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique()); | ||||
|     HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique); | ||||
|  | ||||
|     // Everything below here is only needed if the sheet is editable | ||||
|     if (!this.options.editable) return; | ||||
| @@ -194,47 +188,27 @@ export class RdDItemSheet extends ItemSheet { | ||||
|       this.supprimerBonusCase(event.currentTarget.attributes['data-deleteCoord'].value) | ||||
|     }) | ||||
|  | ||||
|     this.html.find('.date-enchantement').change((event) => { | ||||
|       const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val()); | ||||
|       const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val()); | ||||
|       const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure); | ||||
|       this.item.update({ 'system.prdate': indexDate }); | ||||
|       console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`) | ||||
|     }); | ||||
|  | ||||
|     this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item)); | ||||
|     this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem())); | ||||
|     this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item)); | ||||
|     this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).fabriquerDecoctionHerbe(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())); | ||||
|       this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true)); | ||||
|       this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor))); | ||||
|       this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente()); | ||||
|       this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat()); | ||||
|       this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem())); | ||||
|       this.html.find('.actionItem').click(event => ItemAction.onActionItem(event, this.actor, this.options)) | ||||
|        | ||||
|       // TODO: utiliser un itemAction? | ||||
|       this.html.find('.item-potion-consommer').click(event => this.itemActionConsommer(event)) | ||||
|  | ||||
|       this.html.find('.item-quantite-plus').click(async event => { | ||||
|         await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1) | ||||
|         this.render(); | ||||
|       }); | ||||
|         this.render() | ||||
|       }) | ||||
|       this.html.find('.item-quantite-moins').click(async event => { | ||||
|         await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1) | ||||
|         this.render(); | ||||
|       }); | ||||
|         this.render() | ||||
|       }) | ||||
|     } | ||||
|  | ||||
|     const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: foundry.utils.duplicate(timestamp) }) | ||||
| @@ -243,13 +217,24 @@ export class RdDItemSheet extends ItemSheet { | ||||
|     RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp); | ||||
|   } | ||||
|  | ||||
|   getActionRenderItem() { | ||||
|     return async () => { | ||||
|       let item = this.item; | ||||
|       while (item) { | ||||
|         await item.sheet?.render() | ||||
|         item = this.actor.getContenant(item) | ||||
|       } | ||||
|   itemActionDelete(event) { | ||||
|     const item = RdDSheetUtility.getItem(event, this.actor) | ||||
|     return RdDUtility.confirmActorItemDelete(item, this.actor) | ||||
|   } | ||||
|  | ||||
|   async itemActionConsommer(event) { | ||||
|     const item = RdDSheetUtility.getItem(event, this.actor) | ||||
|     if (item) { | ||||
|       await actor.consommerPotion(item) | ||||
|       await RdDSheetUtility.renderItemBranch(this.actor, item) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async itemActionSplit(event) { | ||||
|     const item = RdDSheetUtility.getItem(event, this.actor) | ||||
|     if (item) { | ||||
|       await RdDSheetUtility.splitItem(item, this.actor) | ||||
|       await RdDSheetUtility.renderItemBranch(this.actor, item) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -272,7 +257,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 { Grammar } from "./grammar.js"; | ||||
| import { RdDItemCompetence } from "./item-competence.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
| import { FLEUVE_COORD, TMRUtility } from "./tmr-utility.js"; | ||||
|  | ||||
| @@ -22,7 +22,21 @@ export class RdDItemSort extends Item { | ||||
|   } | ||||
|  | ||||
|   static addSpaceToNonNumeric(value) { | ||||
|     return Number.isNumeric(value) || ['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes( String(value).charAt[0]) ? value : ' ' + RdDItemSort.toVar(value) | ||||
|     return Number.isNumeric(value) || ['-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(String(value).charAt[0]) ? value : ' ' + RdDItemSort.toVar(value) | ||||
|   } | ||||
|  | ||||
|   static lancements(sort) { return sort?.system.lancements.length ?? 0 } | ||||
|  | ||||
|   static findEnchantement(actor) { return RdDItemSort.findSort(actor, 'Enchantement', ['Narcos', 'N']) } | ||||
|   static findPermanence(actor) { return RdDItemSort.findSort(actor, 'Permanence', ['Narcos', 'N']) } | ||||
|   static findPurification(actor) { return RdDItemSort.findSort(actor, 'Purification', ['Narcos', 'N']) } | ||||
|  | ||||
|   static findSort(actor, name, draconics) { | ||||
|     return actor.itemTypes[ITEM_TYPES.sort].find(it => Grammar.includesLowerCaseNoAccent(it.name, name) | ||||
|       && (draconics == undefined || draconics.includes(it.system.draconic))) | ||||
|   } | ||||
|   static async changeLancementsSort(sort, changement) { | ||||
|     await sort?.update({ 'system.lancements': changement(sort.system.lancements) }); | ||||
|   } | ||||
|  | ||||
|   static toVar(value) { | ||||
| @@ -151,5 +165,4 @@ export class RdDItemSort extends Item { | ||||
|       .map(it => it.split(':')) | ||||
|       .map(it => { return { case: it[0], bonus: it[1] } }); | ||||
|   } | ||||
|  | ||||
| } | ||||
							
								
								
									
										216
									
								
								module/item.js
									
									
									
									
									
								
							
							
						
						
									
										216
									
								
								module/item.js
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { DialogItemVente } from "./achat-vente/dialog-item-vente.js"; | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
| import { RdDHerbes } from "./rdd-herbes.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
| import { RdDUtility } from "./rdd-utility.js"; | ||||
| import { SystemCompendiums } from "./settings/system-compendiums.js"; | ||||
| @@ -9,61 +9,7 @@ import { RdDRaretes } from "./item/raretes.js"; | ||||
| import { CATEGORIES_COMPETENCES } from "./item-competence.js"; | ||||
| import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js"; | ||||
| import { BASE_CORPS_A_CORPS, BASE_ESQUIVE } from "./item/base-items.js"; | ||||
|  | ||||
| export const ACTOR_TYPES = { | ||||
|   personnage: 'personnage', | ||||
|   creature: 'creature', | ||||
|   entite: 'entite', | ||||
|   commerce: 'commerce', | ||||
|   vehicule: 'vehicule' | ||||
| } | ||||
|  | ||||
| export const ITEM_TYPES = { | ||||
|   competence: 'competence', | ||||
|   competencecreature: 'competencecreature', | ||||
|   empoignade: 'empoignade', | ||||
|   possession: 'possession', | ||||
|   blessure: 'blessure', | ||||
|   maladie: 'maladie', | ||||
|   poison: 'poison', | ||||
|   arme: 'arme', | ||||
|   armure: 'armure', | ||||
|   conteneur: 'conteneur', | ||||
|   objet: 'objet', | ||||
|   monnaie: 'monnaie', | ||||
|   gemme: 'gemme', | ||||
|   munition: 'munition', | ||||
|   nourritureboisson: 'nourritureboisson', | ||||
|   herbe: 'herbe', | ||||
|   plante: 'plante', | ||||
|   ingredient: 'ingredient', | ||||
|   faune: 'faune', | ||||
|   livre: 'livre', | ||||
|   potion: 'potion', | ||||
|   service: 'service', | ||||
|   musique: 'musique', | ||||
|   danse: 'danse', | ||||
|   chant: 'chant', | ||||
|   jeu: 'jeu', | ||||
|   race: 'race', | ||||
|   recettecuisine: 'recettecuisine', | ||||
|   oeuvre: 'oeuvre', | ||||
|   recettealchimique: 'recettealchimique', | ||||
|   tache: 'tache', | ||||
|   sort: 'sort', | ||||
|   sortreserve: 'sortreserve', | ||||
|   rencontre: 'rencontre', | ||||
|   queue: 'queue', | ||||
|   ombre: 'ombre', | ||||
|   souffle: 'souffle', | ||||
|   tete: 'tete', | ||||
|   casetmr: 'casetmr', | ||||
|   meditation: 'meditation', | ||||
|   signedraconique: 'signedraconique', | ||||
|   tarot: 'tarot', | ||||
|   nombreastral: 'nombreastral', | ||||
|   extraitpoetique: 'extraitpoetique', | ||||
| } | ||||
| import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js"; | ||||
|  | ||||
| const typesInventaireMateriel = [ | ||||
|   ITEM_TYPES.arme, | ||||
| @@ -95,51 +41,47 @@ const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES | ||||
| const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet]; | ||||
| const typesEnvironnement = typesInventaireMateriel; | ||||
| const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc | ||||
| const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc | ||||
| densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/  | ||||
|    */ | ||||
|  | ||||
| export const defaultItemImg = { | ||||
|   competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", | ||||
|   competencecreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", | ||||
|   arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp", | ||||
|   armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp", | ||||
|   conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp", | ||||
|   sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", | ||||
|   herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp", | ||||
|   faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp", | ||||
|   ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp", | ||||
|   livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp", | ||||
|   potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp", | ||||
|   rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp", | ||||
|   queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", | ||||
|   ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", | ||||
|   souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp", | ||||
|   tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp", | ||||
|   meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp", | ||||
|   recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp", | ||||
|   chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp", | ||||
|   competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", | ||||
|   competencecreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp", | ||||
|   conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp", | ||||
|   danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp", | ||||
|   empoignade: "systems/foundryvtt-reve-de-dragon/icons/empoignade.webp", | ||||
|   extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp", | ||||
|   faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp", | ||||
|   gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp", | ||||
|   herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp", | ||||
|   ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp", | ||||
|   jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp", | ||||
|   recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp", | ||||
|   musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp", | ||||
|   livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp", | ||||
|   maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp", | ||||
|   poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp", | ||||
|   oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp", | ||||
|   meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp", | ||||
|   musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp", | ||||
|   nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp", | ||||
|   oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp", | ||||
|   ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", | ||||
|   poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp", | ||||
|   possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", | ||||
|   potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp", | ||||
|   queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", | ||||
|   recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp", | ||||
|   recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp", | ||||
|   rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp", | ||||
|   service: "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp", | ||||
|   signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp", | ||||
|   gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp", | ||||
|   possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", | ||||
|   sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", | ||||
|   sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", | ||||
|   extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp", | ||||
|   souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp", | ||||
|   tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp", | ||||
|   empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp" | ||||
|   tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp", | ||||
| } | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| export class RdDItem extends Item { | ||||
|  | ||||
|   static get defaultIcon() { | ||||
|     return undefined; | ||||
|   } | ||||
| @@ -238,7 +180,6 @@ export class RdDItem extends Item { | ||||
|   isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature } | ||||
|   isConteneur() { return this.type == ITEM_TYPES.conteneur; } | ||||
|   isMonnaie() { return this.type == ITEM_TYPES.monnaie; } | ||||
|   isPotion() { return this.type == ITEM_TYPES.potion; } | ||||
|   isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; } | ||||
|   isService() { return this.type == ITEM_TYPES.service; } | ||||
|  | ||||
| @@ -277,6 +218,12 @@ export class RdDItem extends Item { | ||||
|     return this.getEnvironnements(milieux).length > 0 | ||||
|   } | ||||
|  | ||||
|   get nameDisplay() { | ||||
|     return this.isMagique ? (this.name + ' <i class="fa-solid fa-sparkles"></i>') : this.name | ||||
|   } | ||||
|  | ||||
|   get isEnchantementPossible() { return false } | ||||
|  | ||||
|   getEnvironnements(milieux = undefined) { | ||||
|     const environnements = this.isInventaire() ? this.system.environnement : undefined; | ||||
|     if (milieux == undefined || !environnements) { | ||||
| @@ -356,13 +303,6 @@ export class RdDItem extends Item { | ||||
|  | ||||
|   getUtilisation() { | ||||
|     switch (this.type) { | ||||
|       case ITEM_TYPES.potion: | ||||
|         switch (this.system.categorie) { | ||||
|           case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie' | ||||
|           case 'Cuisine': return 'cuisine' | ||||
|           case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins' | ||||
|         } | ||||
|         return ''; | ||||
|       case ITEM_TYPES.nourritureboisson: return 'cuisine'; | ||||
|       case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante: | ||||
|         switch (this.system.categorie) { | ||||
| @@ -392,7 +332,7 @@ export class RdDItem extends Item { | ||||
|     return this.type == ITEM_TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0; | ||||
|   } | ||||
|  | ||||
|   isMagique() { | ||||
|   get isMagique() { | ||||
|     return this.system.magique | ||||
|   } | ||||
|  | ||||
| @@ -403,6 +343,7 @@ export class RdDItem extends Item { | ||||
|   isNomLike(texte) { | ||||
|     return Grammar.includesLowerCaseNoAccent(this.name, texte) | ||||
|   } | ||||
|  | ||||
|   isNomTypeLike(texte) { | ||||
|     return this.isNomLike(texte) || Grammar.includesLowerCaseNoAccent(Misc.typeName(this.type, 'Item'), texte) | ||||
|   } | ||||
| @@ -421,8 +362,6 @@ export class RdDItem extends Item { | ||||
|         return 0; | ||||
|       case ITEM_TYPES.herbe: | ||||
|         return this.getEncHerbe(); | ||||
|       case ITEM_TYPES.gemme: | ||||
|         return encPepin * this.system.taille; | ||||
|     } | ||||
|     return Math.max(this.system.encombrement ?? 0, 0); | ||||
|   } | ||||
| @@ -471,68 +410,47 @@ export class RdDItem extends Item { | ||||
|       // appliquer le pourcentage | ||||
|       return this.parent.calculerPrix(this); | ||||
|     } | ||||
|     return this.system.cout; | ||||
|     return this.system.cout | ||||
|   } | ||||
|  | ||||
|   prepareDerivedData() { | ||||
|     super.prepareDerivedData(); | ||||
|     if (this.isInventaire()) { | ||||
|       this.system.encTotal = this.getEncTotal(); | ||||
|       if (this.isPotion()) { | ||||
|         this.prepareDataPotion() | ||||
|       } | ||||
|       this.system.actionPrincipale = this.getActionPrincipale({ warnIfNot: false }); | ||||
|       this.system.encTotal = this.getEncTotal() | ||||
|     } | ||||
|     this.equipable = this.isEquipable(); | ||||
|     this.equipable = this.isEquipable() | ||||
|   } | ||||
|  | ||||
|   prepareDataPotion() { | ||||
|     const categorie = Grammar.toLowerCaseNoAccent(this.system.categorie); | ||||
|     this.system.magique = categorie.includes('enchante'); | ||||
|     if (this.system.magique) { | ||||
|       if (categorie.includes('soin') || categorie.includes('repos')) { | ||||
|         // TODO: utiliser calculPointsRepos / calculPointsGuerison | ||||
|         this.system.puissance = RdDHerbes.calculPuissancePotion(this); | ||||
|       } | ||||
|     } | ||||
|   itemActions() { | ||||
|     return COMMON_ACTIONS.concat(this.itemSpecificActions()).concat(DEFAULT_ACTIONS) | ||||
|   } | ||||
|  | ||||
|   getActionPrincipale(options = { warnIfNot: true }) { | ||||
|   itemSpecificActions() { | ||||
|     const actions = ITEM_ACTIONS[this.type] ?? [] | ||||
|     return actions | ||||
|   } | ||||
|  | ||||
|   isActionAllowed(code) { | ||||
|     switch (this.type) { | ||||
|       case ITEM_TYPES.conteneur: return 'Ouvrir'; | ||||
|     } | ||||
|     if (this.actor?.isPersonnage()) { | ||||
|       const warn = options.warnIfNot; | ||||
|       if (this.getUtilisationCuisine() == 'brut') { | ||||
|         return 'Cuisiner'; | ||||
|       } | ||||
|       switch (this.type) { | ||||
|         case ITEM_TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn); | ||||
|         case ITEM_TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn); | ||||
|         case ITEM_TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn); | ||||
|         case ITEM_TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined; | ||||
|         case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined; | ||||
|       } | ||||
|     } | ||||
|     return undefined; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async actionPrincipale(actor, onActionItem = async () => { }) { | ||||
|     if (!this.getActionPrincipale()) { return } | ||||
|     await actor?.actionPrincipale(this, onActionItem); | ||||
|   } | ||||
|  | ||||
|   _actionOrWarnQuantiteZero(actionName, warn) { | ||||
|     if ((this.system.quantite ?? 0) <= 0) { | ||||
|       if (warn) { | ||||
|         ui.notifications.warn(`Vous n'avez plus de ${this.name}.`); | ||||
|       } | ||||
|       return undefined; | ||||
|     } | ||||
|     else { | ||||
|       return actionName; | ||||
|       case ITEM_TYPES.possession: | ||||
|       case ITEM_TYPES.empoignade: | ||||
|       case ITEM_TYPES.rencontre: | ||||
|       case ITEM_TYPES.signedraconique: | ||||
|         switch (code) { | ||||
|           case 'item-edit': | ||||
|           case 'item-delete': | ||||
|             return game.user.isGM | ||||
|         } | ||||
|       case ITEM_TYPES.maladie: | ||||
|       case ITEM_TYPES.poison: | ||||
|         return game.user.isGM | ||||
|       case ITEM_TYPES.casetmr: | ||||
|         switch (code) { | ||||
|           case 'item-delete': | ||||
|             return game.user.isGM | ||||
|         } | ||||
|     } | ||||
|     return true | ||||
|   } | ||||
|  | ||||
|   async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { | ||||
| @@ -805,14 +723,6 @@ export class RdDItem extends Item { | ||||
|     ] | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   _potionChatData() { | ||||
|     return [ | ||||
|       `<b>Rareté</b>: ${this.system.rarete}`, | ||||
|       `<b>Catégorie</b>: ${this.system.categorie}`, | ||||
|       ...this._inventaireTemplateChatData() | ||||
|     ] | ||||
|   } | ||||
|   /* -------------------------------------------- */ | ||||
|   _queueChatData() { | ||||
|     function label(categorie) { | ||||
|       switch (categorie) { | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { ITEM_TYPES, RdDItem } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { Misc } from "../misc.js"; | ||||
| import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; | ||||
|  | ||||
| @@ -10,7 +11,7 @@ export class RdDItemArmure extends RdDItem { | ||||
|     return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp"; | ||||
|   } | ||||
|  | ||||
|   deteriorerArmure(dmg) { | ||||
|   async deteriorerArmure(dmg) { | ||||
|     if (!ReglesOptionnelles.isUsing('deteriorationArmure') || this.system.protection == '0') { | ||||
|       return; | ||||
|     } | ||||
| @@ -22,12 +23,10 @@ export class RdDItemArmure extends RdDItem { | ||||
|       protection = this.calculProtectionDeterioree(); | ||||
|       ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` }); | ||||
|     } | ||||
|     this.update({ | ||||
|       system: { | ||||
|         deterioration: deterioration, | ||||
|         protection: protection | ||||
|       } | ||||
|     }); | ||||
|     await this.update({ | ||||
|       'system.deterioration': deterioration, | ||||
|       'system.protection': protection | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   calculProtectionDeterioree() { | ||||
|   | ||||
| @@ -30,7 +30,7 @@ export class RdDItemBlessure extends RdDItem { | ||||
|  | ||||
|   prepareDerivedData() { | ||||
|     super.prepareDerivedData(); | ||||
|     this.system.label = this.getLabelGravite() | ||||
|     this.system.label = RdDItemBlessure.getLabelGravite(this.system.gravite) | ||||
|   } | ||||
|  | ||||
|   static prepareTacheSoin(gravite) { | ||||
| @@ -43,29 +43,32 @@ export class RdDItemBlessure extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   static async applyFullBlessure(actor, gravite) { | ||||
|     const definition = RdDItemBlessure.getDefinition(gravite) | ||||
|      | ||||
|     let lostEndurance = 0 | ||||
|     let lostVie = 0 | ||||
|     if (definition.endurance) { | ||||
|       lostEndurance = new Roll(definition.endurance) | ||||
|       await lostEndurance.roll(); | ||||
|       actor.santeIncDec("endurance", -Number(lostEndurance.total)); | ||||
|     } | ||||
|     const definition = foundry.utils.duplicate(RdDItemBlessure.getDefinition(gravite)) | ||||
|  | ||||
|     if (definition.vie) { | ||||
|       lostVie = definition.vie | ||||
|       actor.santeIncDec("vie", definition.vie) | ||||
|       await actor.santeIncDec("vie", definition.vie) | ||||
|     } | ||||
|     const lostEndurance = await RdDItemBlessure.rollLostEndurance(definition.endurance) | ||||
|     if (lostEndurance) { | ||||
|       await actor.santeIncDec("endurance", -Number(lostEndurance)); | ||||
|     } | ||||
|      | ||||
|     await this.createBlessure(actor, gravite) | ||||
|  | ||||
|     ChatMessage.create({ | ||||
|       content: `Blessure ${definition.label} appliquée à ${actor.name}`+ | ||||
|         `<br>Perte d'endurance : ${lostEndurance}`+ | ||||
|         `<br>Perte de Vie : ${lostVie}`, | ||||
|       //TODO: hbs | ||||
|       content: `Blessure ${definition.label} appliquée à ${actor.name}<br>Perte d'endurance : ${lostEndurance} (${definition.endurance})<br>Perte de Vie : ${definition.vie}`, | ||||
|       whisper: ChatUtility.getOwners(actor) | ||||
|     }); | ||||
|     actor.sheet?.render() | ||||
|   } | ||||
|  | ||||
|   static async rollLostEndurance(formula) { | ||||
|     if (formula) { | ||||
|       const roll = new Roll(formula) | ||||
|       await roll.evaluate() | ||||
|       return roll.total | ||||
|     } | ||||
|     return 0 | ||||
|   } | ||||
|  | ||||
|   static async createBlessure(actor, gravite, localisation = '', attackerToken) { | ||||
| @@ -125,10 +128,10 @@ export class RdDItemBlessure extends RdDItem { | ||||
|     } | ||||
|     if (this.system.gravite > 0) { | ||||
|       const update = { system: { premierssoins: { bonus: 0 }, soinscomplets: { bonus: 0 } } } | ||||
|       const gravite = this.system.gravite; | ||||
|       const graviteMoindre = gravite - 2; | ||||
|       const gravite = this.system.gravite | ||||
|       const graviteMoindre = gravite - 2 | ||||
|       const moindres = blessures.filter(it => it.system.gravite == graviteMoindre, 'blessures').length | ||||
|       const label = this.getLabelGravite(); | ||||
|       const label = RdDItemBlessure.getLabelGravite(this.system.gravite) | ||||
|  | ||||
|       let rolled = await actor.jetRecuperationConstitution(this.system.soinscomplets.bonus, message); | ||||
|  | ||||
| @@ -158,11 +161,11 @@ export class RdDItemBlessure extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   peutRetrograder(graviteMoindre, moindres) { | ||||
|     return moindres < RdDItemBlessure.getDefinition(graviteMoindre).max | ||||
|     return moindres < RdDItemBlessure.maxBlessures(graviteMoindre) | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|     return await debut.nouveauJour().addJours(this.system.gravite); | ||||
|     return debut.nouveauJour().addJours(this.system.gravite); | ||||
|   } | ||||
|  | ||||
|   async onFinPeriode(oldTimestamp, newTimestamp) { | ||||
| @@ -182,16 +185,16 @@ export class RdDItemBlessure extends RdDItem { | ||||
|     return `systems/foundryvtt-reve-de-dragon/icons/sante/${soins ? 'blessure-soins' : img}.webp` | ||||
|   } | ||||
|  | ||||
|   getLabelGravite() { | ||||
|     return RdDItemBlessure.getDefinition(this.system.gravite).label | ||||
|   static getLabelGravite(gravite) { | ||||
|     return definitionsBlessures.find(it => it.gravite >= gravite).label | ||||
|   } | ||||
|  | ||||
|   static getDefinition(gravite) { | ||||
|     return definitionsBlessures.sort(Misc.ascending(it => it.gravite)) | ||||
|       .find(it => it.gravite >= gravite); | ||||
|     return definitionsBlessures.find(it => it.gravite >= gravite) | ||||
|   } | ||||
|  | ||||
|   static maxBlessures(gravite) { | ||||
|     return RdDItemBlessure.getDefinition(gravite).max | ||||
|     return definitionsBlessures.find(it => it.gravite >= gravite).max | ||||
|   } | ||||
|  | ||||
|   isContusion() { | ||||
| @@ -216,7 +219,7 @@ export class RdDItemBlessure extends RdDItem { | ||||
|       `<b>Heure et Date</b>: ${new RdDTimestamp(this.system.temporel.debut).formatDateHeure()}`, | ||||
|       RdDItem.propertyIfDefined('Blessé', this.parent?.name, this.parent), | ||||
|       `<b>Localisation</b>: ${this.system.localisation}`, | ||||
|       `<b>Gravité</b>: ${RdDItemBlessure.getDefinition(this.system.gravite).label}`, | ||||
|       `<b>Gravité</b>: ${this.system.label}`, | ||||
|       `<b>Difficulté des soins</b>: ${this.system.difficulte}`, | ||||
|       (this.system.soinscomplets.done ? | ||||
|         `<b>Bonus soins complets</b>: ${this.system.soinscomplets.bonus}` : | ||||
|   | ||||
							
								
								
									
										112
									
								
								module/item/gemme.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								module/item/gemme.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { ACTION_ITEM_ENCHANTER } from "../enchantement/dialog-enchanter.js"; | ||||
|  | ||||
| const tableGemmes = { | ||||
|   "almaze": { label: "Almaze", couleur: "Blanc" }, | ||||
|   "aquafane": { label: "Aquafane", couleur: "Vert Profond" }, | ||||
|   "asterite": { label: "Astérite", couleur: "Bleu, Violet ou Blanc" }, | ||||
|   "cyanolithe": { label: "Cyanolithe", couleur: "Bleu Intense" }, | ||||
|   "larmededragon": { label: "Larme de Dragon", couleur: "Rouge Intense" }, | ||||
|   "muska": { label: "Muska", couleur: "Violet Profond" }, | ||||
|   "nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense" }, | ||||
|   "nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense, Rose, Vert ou Bleu Pâle" }, | ||||
|   "oeildetigre": { label: "Oeil de Tigre", couleur: "Jaune" }, | ||||
|   "scarlatine": { label: "Scarlatine", couleur: "Rouge Clair ou Orangé" }, | ||||
|   "seliphane": { label: "Séliphane", couleur: "Vert Lumineux" }, | ||||
|   "tournelune": { label: "Tournelune", couleur: "Violet ou Bleu" }, | ||||
|   "zebraide": { label: "Zebraïde", couleur: "Bandes Bicolores, toutes couleurs" } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc | ||||
|  * densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/  | ||||
|  */ | ||||
| const encPepin = 0.0007; | ||||
|  | ||||
| /** | ||||
|  * Item pour gérer les gemmes | ||||
|  */ | ||||
| export class RdDItemGemme extends RdDItem { | ||||
|  | ||||
|   static getGemmeTypeOptionList() { | ||||
|     // TODO: look how to map object key-value pairs | ||||
|     let options = "" | ||||
|     for (let gemmeKey in tableGemmes) { | ||||
|       options += `<option value="${gemmeKey}">${tableGemmes[gemmeKey].label}</option>` | ||||
|     } | ||||
|     return options; | ||||
|   } | ||||
|  | ||||
|   static get defaultIcon() { | ||||
|     return "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp" | ||||
|   } | ||||
|  | ||||
|   get isEnchantementPossible() { | ||||
|     return this.enchantabilite > 0 | ||||
|   } | ||||
|  | ||||
|   get inertie() { return 7 - Number(this.system.purete) } | ||||
|   get enchantabilite() { return this.system.taille - this.inertie } | ||||
|  | ||||
|   getEnc() { | ||||
|     return encPepin * this.system.taille; | ||||
|   } | ||||
|  | ||||
|   itemSpecificActions() { | ||||
|     return [ACTION_ITEM_ENCHANTER] | ||||
|   } | ||||
|  | ||||
|   prepareDerivedData() { | ||||
|     super.prepareDerivedData() | ||||
|     this.system.cout = (this.system.taille * this.system.purete) + this.system.qualite | ||||
|     this.system.inertie = this.inertie | ||||
|     this.system.enchantabilite = this.enchantabilite | ||||
|   } | ||||
|  | ||||
|   getUtilisation() { | ||||
|     switch (this.system.categorie) { | ||||
|       case 'Alchimie': case 'Autre': case 'AlchimieAutre': | ||||
|         // TODO: distinguer les remèdes alchimiques enchantables/non | ||||
|         return 'alchimie' | ||||
|       case 'Cuisine': | ||||
|         return 'cuisine' | ||||
|       case 'Remede': case 'Repos': case 'Soin': | ||||
|         return 'soins' | ||||
|     } | ||||
|     return '' | ||||
|   } | ||||
|  | ||||
|   getProprietes() { | ||||
|     const proprietes = [ | ||||
|       `<b>Taille</b>: ${this.system.taille}`, | ||||
|       `<b>Pureté</b>: ${this.system.purete}`, | ||||
|       `<b>Inertie</b>: ${this.system.inertie}`, | ||||
|       `<b>Enchantabilité</b>: ${this.system.enchantabilite}` | ||||
|     ] | ||||
|     const proprietesMagiques = this.system.magique ? [ | ||||
|       `<b>Enchantée</b> <i class="fa-solid fa-sparkles"></i> ${this.system.purifie ? ', purifiée' : ''} ${this.system.prpermanent ? 'permanente' : ''} `, | ||||
|       `<b>Points de rêve</b>: ${this.system.pr}`, | ||||
|       `<b>Puissance</b>: ${this.system.puissance}`, | ||||
|     ] : [] | ||||
|     return proprietes | ||||
|       .concat(proprietesMagiques) | ||||
|       .concat(this._inventaireTemplateChatData()) | ||||
|       .filter(it => it != undefined) | ||||
|   } | ||||
|  | ||||
|   perteReveChateauDormant() { | ||||
|     if (this.system.magique && !this.system.prpermanent && this.system.pr > 0) { | ||||
|       const nouveauReve = Math.max(this.system.pr - 1, 0) | ||||
|       return { | ||||
|         alias: this.parent.getAlias(), | ||||
|         item: this, | ||||
|         update: { | ||||
|           _id: this.id, | ||||
|           'system.pr': nouveauReve, | ||||
|           'system.magique': nouveauReve > 0 | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
| } | ||||
							
								
								
									
										146
									
								
								module/item/item-actions.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								module/item/item-actions.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| import { Misc } from "../misc.js" | ||||
| import { RdDSheetUtility } from "../rdd-sheet-utility.js" | ||||
| import { RdDUtility } from "../rdd-utility.js" | ||||
|  | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * TODO: | ||||
|  * options.editable ? | ||||
|  *  | ||||
|  */ | ||||
| const _SPACEHOLDER = { placeholder: true } | ||||
|  | ||||
| const _VENDRE = { | ||||
|   code: 'item-vendre', label: 'Vendre ou donner', icon: it => 'fa-solid fa-comments-dollar', | ||||
|   filter: it => Misc.toInt(it.system.quantite) > 0, | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => item.proposerVente() | ||||
| } | ||||
| const _ACHAT_SERVICE = { | ||||
|   code: 'item-service-acheter', label: 'Acheter', icon: it => 'fa-regular fa-coins', | ||||
|   //filter: it => Misc.toInt(it.system.quantite) > 0, | ||||
|   //optionsFilter: options => options.editable, | ||||
|   //action: (item, actor) => item.proposerVente() | ||||
| } | ||||
| const _MONTRER = { | ||||
|   code: 'item-montrer', label: 'Montrer', icon: it => 'fa-solid fa-comment', | ||||
|   action: (item, actor) => item.postItemToChat() | ||||
| } | ||||
| const _SPLIT = { | ||||
|   code: 'item-split', label: 'Séparer le goupe', icon: it => 'fa-solid fa-unlink', | ||||
|   filter: it => Misc.toInt(it.system.quantite) > 1, | ||||
|   action: (item, actor) => RdDSheetUtility.splitItem(item, actor) | ||||
| } | ||||
|  | ||||
| const _EDIT = { | ||||
|   code: 'item-edit', label: 'Editer', icon: it => 'fa-solid fa-edit', | ||||
|   action: (item, actor) => item.sheet.render(true) | ||||
| } | ||||
| const _DELETE = { | ||||
|   code: 'item-delete', label: 'Supprimer', icon: it => 'fa-solid fa-trash', | ||||
|   optionsFilter: options => options.editable && options.isOwner, | ||||
|   action: (item, actor) => RdDUtility.confirmActorItemDelete(item, actor) | ||||
| } | ||||
| const _EQUIPER = { | ||||
|   code: 'item-equip', label: 'Equiper', icon: it => it.system.equipe ? 'fa-solid fa-hand-rock' : 'fa-regular fa-hand-paper', | ||||
|   filter: it => !it.estContenu && it.isEquipable(), | ||||
|   action: (item, actor) => actor.equiperObjet(item) | ||||
| } | ||||
|  | ||||
| const _CUISINER = { | ||||
|   code: 'item-cuisiner', label: 'Cuisiner', icon: it => 'fa-solid fa-utensils', | ||||
|   filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0, | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.preparerNourriture(item) | ||||
| } | ||||
| const _MANGER_CRU = { | ||||
|   code: 'item-manger-cru', label: 'Manger cru', icon: it => 'fa-solid fa-drumstick-bite', | ||||
|   filter: it => it.getUtilisation() == 'cuisine' && it.system.sust > 0, | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.mangerNourriture(item) | ||||
| } | ||||
| const _MANGER = { | ||||
|   code: 'item-manger', label: 'Manger', icon: it => 'fa-solid fa-utensils', | ||||
|   filter: it => !(it.system.boisson), | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.mangerNourriture(item) | ||||
| } | ||||
| const _BOIRE = { | ||||
|   code: 'item-boire', label: 'Boire', icon: it => 'fa-solid fa-glass-water', | ||||
|   filter: it => it.system.boisson, | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.mangerNourriture(item) | ||||
| } | ||||
| const _DECOCTION = { | ||||
|   code: 'item-decoction', label: 'Décoction', icon: it => 'fa-solid fa-flask-vial', | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.fabriquerDecoctionHerbe(item) | ||||
| } | ||||
| const _OUVRIR = { | ||||
|   code: 'item-edit', label: 'Ouvrir', icon: it => 'fa-solid fa-eye', | ||||
|   action: (item, actor) => item.sheet.render(true) | ||||
| } | ||||
|  | ||||
| const _LIRE = { | ||||
|   code: 'item-lire', label: 'Lire', icon: it => 'fa-solid fa-book-open', | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.actionLire(item) | ||||
| } | ||||
|  | ||||
| const _REFOULER = { | ||||
|   code: 'item-refouler', label: 'Refouler', icon: it => 'fa-solid fa-burst', | ||||
|   filter: it => it.system.refoulement > 0, | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.actionRefoulement(item) | ||||
| } | ||||
|  | ||||
| const _SORT_RESERVE = { | ||||
|   code: 'item-sortreserve-add', label: 'Ajouter en réserve', icon: it => 'fa-solid fa-sparkles', | ||||
|   filter: it => game.user.isGM && !it.system.isrituel, | ||||
|   action: (item, actor) => actor.addSortReserve(item) | ||||
| } | ||||
|  | ||||
| export const COMMON_ACTIONS = [_EQUIPER] | ||||
| export const DEFAULT_ACTIONS = [_SPACEHOLDER, _SPLIT, _VENDRE, _MONTRER, _EDIT, _DELETE] | ||||
|  | ||||
| export const ITEM_ACTIONS = { | ||||
|   faune: [_CUISINER, _MANGER_CRU], | ||||
|   ingredient: [_CUISINER, _MANGER_CRU], | ||||
|   conteneur: [_OUVRIR], | ||||
|   herbe: [_DECOCTION, _CUISINER, _MANGER_CRU], | ||||
|   livre: [_LIRE], | ||||
|   nourritureboisson: [_MANGER, _BOIRE], | ||||
|   ombre: [_REFOULER], | ||||
|   plante: [_CUISINER, _MANGER_CRU], | ||||
|   queue: [_REFOULER], | ||||
|   sort: [_SORT_RESERVE], | ||||
|   service: [_ACHAT_SERVICE] | ||||
| } | ||||
|  | ||||
|  | ||||
| export class ItemAction { | ||||
|  | ||||
|   static applies(action, item, options) { | ||||
|     return action && item | ||||
|       && item.isActionAllowed(action.code) | ||||
|       && (!action.filter || action.filter(item)) | ||||
|       && (!action.optionsFilter || action.optionsFilter(options)) | ||||
|   } | ||||
|  | ||||
|   static icon(action, item) { | ||||
|     if (action && action.icon) { | ||||
|       return action.icon(item) | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
|   static onActionItem(event, actor, options) { | ||||
|     const item = RdDSheetUtility.getItem(event, actor) | ||||
|     const code = $(event.currentTarget).data('code') | ||||
|     const action = item?.itemActions().find(it => it.code == code) | ||||
|     if (action && (!action.optionsFilter || action.optionsFilter(options))) { | ||||
|       action.action(item, actor) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -10,7 +10,7 @@ export class RdDItemMaladie extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|     return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite); | ||||
|     return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite); | ||||
|   } | ||||
|  | ||||
|   async onFinPeriode(oldTimestamp, newTimestamp) { | ||||
|   | ||||
| @@ -1,11 +1,8 @@ | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { RdDItemQueue } from "./queue.js"; | ||||
|  | ||||
| export class RdDItemOmbre extends RdDItemQueue { | ||||
|  | ||||
| export class RdDItemOmbre extends RdDItem { | ||||
|   static get defaultIcon() { | ||||
|     return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp"; | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|     return await debut.appliquerDuree(this.system.duree, this.parent); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ export class RdDItemPoison extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|     return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ; | ||||
|     return debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ; | ||||
|   } | ||||
|  | ||||
|   async onFinPeriode(oldTimestamp, newTimestamp) { | ||||
|   | ||||
							
								
								
									
										105
									
								
								module/item/potion.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								module/item/potion.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { SystemCompendiums } from "../settings/system-compendiums.js"; | ||||
| import { ACTION_ITEM_ENCHANTER } from "../enchantement/dialog-enchanter.js"; | ||||
|  | ||||
| // --- Actions sur les "potions" | ||||
| const _CONSOMMER_POTION = { | ||||
|   code: 'item-potion-consommer', label: 'Consommer', icon: it => 'fa-solid fa-vial', | ||||
|   optionsFilter: options => options.editable, | ||||
|   action: (item, actor) => actor.consommerPotion(item) | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Item pour gérer les potions | ||||
|  */ | ||||
| export class RdDItemPotion extends RdDItem { | ||||
|  | ||||
|   static async herbesSoins() { | ||||
|     return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Soin') && it.system.niveau > 0) | ||||
|   } | ||||
|   static async herbesRepos() { | ||||
|     return await RdDItemPotion.$listHerbes(it => Grammar.equalsInsensitive(it.system.categorie, 'Repos') && it.system.niveau > 0) | ||||
|   } | ||||
|  | ||||
|   static async $listHerbes(filter) { | ||||
|     const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux'); | ||||
|     return herbes.filter(filter) | ||||
|   } | ||||
|  | ||||
|   static get defaultIcon() { | ||||
|     return "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp" | ||||
|   } | ||||
|  | ||||
|   get isEnchantementPossible() { | ||||
|     return this.system.etat == 'Liquide' | ||||
|   } | ||||
|  | ||||
|   itemSpecificActions() { | ||||
|     return [_CONSOMMER_POTION, ACTION_ITEM_ENCHANTER] | ||||
|   } | ||||
|  | ||||
|   prepareDerivedData() { | ||||
|     super.prepareDerivedData() | ||||
|     this.system.puissance = this.system.magique ? this.calculPuissance() : 0 | ||||
|   } | ||||
|  | ||||
|   getUtilisation() { | ||||
|     switch (this.system.categorie) { | ||||
|       case 'Alchimie': case 'Autre': case 'AlchimieAutre': | ||||
|         // TODO: distinguer les remèdes alchimiques enchantables/non | ||||
|         return 'alchimie' | ||||
|       case 'Cuisine': | ||||
|         return 'cuisine' | ||||
|       case 'Remede': case 'Repos': case 'Soin': | ||||
|         return 'soins' | ||||
|     } | ||||
|     return '' | ||||
|   } | ||||
|  | ||||
|   getProprietes() { | ||||
|     const proprietes = [ | ||||
|       `<b>Rareté</b>: ${this.system.rarete} `, | ||||
|       `<b>Catégorie</b>: ${this.system.categorie}`, | ||||
|       `<b>Etat</b>: ${this.system.etat}` | ||||
|     ] | ||||
|     const proprietesMagiques = this.system.magique ? [ | ||||
|       `<b>Enchantée</b> <i class="fa-solid fa-sparkles"></i> ${this.system.purifie ? ', purifiée' : ''} ${this.system.prpermanent ? 'permanente' : ''} `, | ||||
|       `<b>Points de rêve</b>: ${this.system.pr}`, | ||||
|     ] : [] | ||||
|     return proprietes | ||||
|       .concat(proprietesMagiques) | ||||
|       .concat(this._inventaireTemplateChatData()) | ||||
|       .filter(it => it != undefined) | ||||
|   } | ||||
|  | ||||
|   perteReveChateauDormant() { | ||||
|     if (this.system.magique && !this.system.prpermanent && this.system.pr > 0) { | ||||
|       const nouveaupr = Math.max(this.system.pr - 1, 0) | ||||
|       return { | ||||
|         alias: this.parent.getAlias(), | ||||
|         item: this, | ||||
|         nouveaupr: nouveaupr, | ||||
|         update: { | ||||
|           _id: this.id, | ||||
|           'system.pr': nouveaupr, | ||||
|           'system.magique': nouveaupr > 0 | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
|   calculPuissance() { return this.system.herbebonus * this.system.pr } | ||||
|  | ||||
|   static buildHerbesList(listeHerbes, max) { | ||||
|     let list = {} | ||||
|     for (let herbe of listeHerbes) { | ||||
|       let brins = max - herbe.system.niveau; | ||||
|       list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`; | ||||
|     } | ||||
|     list['Autre'] = 'Autre (Bonus: variable, Brins: variable)' | ||||
|     return list; | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -6,8 +6,9 @@ export class RdDItemQueue extends RdDItem { | ||||
|     return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp"; | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|   async calculerFinPeriodeTemporel(timestamp) { | ||||
|     // décaller le début pour calcul correct si la queue dure 12h | ||||
|     const debut = timestamp.addMinutes(timestamp.indexMinute == 0 ? -1 : 0); | ||||
|     return await debut.appliquerDuree(this.system.duree, this.parent); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| import { ITEM_TYPES, RdDItem } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { 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 +13,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 +56,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 | ||||
|   | ||||
| @@ -74,7 +74,7 @@ export class RdDRencontre extends RdDItem { | ||||
|   } | ||||
|  | ||||
|   async calculerFinPeriodeTemporel(debut) { | ||||
|     return await debut.nouvelleHeure().addHeures(12); | ||||
|     return debut.nouvelleHeure().addHeures(12); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { RdDBaseActorSheet } from "../actor/base-actor-sheet.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDSheetUtility } from "../rdd-sheet-utility.js"; | ||||
| import { RdDUtility } from "../rdd-utility.js"; | ||||
| import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js"; | ||||
| @@ -29,9 +29,10 @@ export class RdDConteneurItemSheet extends RdDItemInventaireSheet { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   prepareConteneurData(formData) { | ||||
|     RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); | ||||
|     RdDUtility.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); | ||||
|     this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires); | ||||
|     formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems; | ||||
|     const subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems; | ||||
|     formData.subItems = subItems | ||||
|   } | ||||
|  | ||||
|   async _onDragStart(event) { | ||||
|   | ||||
							
								
								
									
										38
									
								
								module/item/sheet-gemme.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								module/item/sheet-gemme.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { DialogEnchanter } from "../enchantement/dialog-enchanter.js"; | ||||
| import { RdDTimestamp } from "../time/rdd-timestamp.js"; | ||||
| import { RdDItemGemme } from "./gemme.js"; | ||||
| import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js"; | ||||
|  | ||||
| export class RdDGemmeItemSheet extends RdDItemInventaireSheet { | ||||
|  | ||||
|   static get ITEM_TYPE() { return ITEM_TYPES.gemme }; | ||||
|  | ||||
|   async getData() { | ||||
|     const formData = foundry.utils.mergeObject(await super.getData(), | ||||
|       { | ||||
|         inertie: this.item.inertie, | ||||
|         enchantabilite: this.item.enchantabilite, | ||||
|         isEnchantementPossible: this.item.isEnchantementPossible, | ||||
|         gemmeTypeList: RdDItemGemme.getGemmeTypeOptionList(), | ||||
|         dateActuelle: game.system.rdd.calendrier.dateCourante(), | ||||
|         enchantement: RdDTimestamp.splitIndexDate(this.item.system.prdate) | ||||
|       }) | ||||
|     return formData | ||||
|   } | ||||
|  | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|  | ||||
|     this.html.find('.item-enchanter').click((event) => DialogEnchanter.enchanter(this.item)) | ||||
|  | ||||
|     this.html.find('.date-enchantement').change((event) => { | ||||
|       const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val()) | ||||
|       const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val()) | ||||
|       const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure) | ||||
|       this.item.update({ 'system.prdate': indexDate }) | ||||
|       console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`) | ||||
|     }); | ||||
|  | ||||
|   } | ||||
| } | ||||
							
								
								
									
										57
									
								
								module/item/sheet-potion.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								module/item/sheet-potion.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { DialogEnchanter } from "../enchantement/dialog-enchanter.js"; | ||||
| import { RdDTimestamp } from "../time/rdd-timestamp.js"; | ||||
| import { RdDItemPotion } from "./potion.js"; | ||||
| import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js"; | ||||
|  | ||||
|  | ||||
| export class RdDPotionItemSheet extends RdDItemInventaireSheet { | ||||
|  | ||||
|   static get ITEM_TYPE() { return ITEM_TYPES.potion }; | ||||
|  | ||||
|   static $calculBonusHerbe(formData, herbesList, max) { | ||||
|     if (Number(formData.system.herbebrins)) { | ||||
|       let herbe = herbesList.find(h => h.name.toLowerCase() == formData.system.herbe.toLowerCase()); | ||||
|       if (herbe) { | ||||
|         const brinsRequis = max - herbe.system.niveau; | ||||
|         const brinsManquants = Math.max(brinsRequis - formData.system.herbebrins, 0); | ||||
|         formData.system.herbebonus = Math.max(herbe.system.niveau - brinsManquants, 0); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async getData() { | ||||
|     const formData = await super.getData() | ||||
|     formData.isEnchantementPossible = this.item.isEnchantementPossible | ||||
|     formData.isSoins = this.item.categorie == 'Soin' | ||||
|     formData.isRepos = this.item.categorie == 'Repos' | ||||
|     if (formData.isSoins) { | ||||
|       const herbesSoins = await RdDItemPotion.herbesSoins() | ||||
|       RdDPotionItemSheet.$calculBonusHerbe(formData, herbesSoins, 12); | ||||
|       formData.herbesSoins = RdDItemPotion.buildHerbesList(herbesSoins, 12) | ||||
|     } | ||||
|     if (formData.isRepos) { | ||||
|       const herbesRepos = await RdDItemPotion.herbesRepos() | ||||
|       RdDPotionItemSheet.$calculBonusHerbe(formData, herbesRepos, 7); | ||||
|       formData.herbesRepos = RdDItemPotion.buildHerbesList(herbesRepos, 7) | ||||
|     } | ||||
|     formData.dateActuelle = game.system.rdd.calendrier.dateCourante() | ||||
|     formData.enchantement = RdDTimestamp.splitIndexDate(this.item.system.prdate) | ||||
|     return formData | ||||
|   } | ||||
|  | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|  | ||||
|     this.html.find('.item-enchanter').click((event) => DialogEnchanter.enchanter(this.item)) | ||||
|  | ||||
|     this.html.find('.date-enchantement').change((event) => { | ||||
|       const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val()) | ||||
|       const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val()) | ||||
|       const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure) | ||||
|       this.item.update({ 'system.prdate': indexDate }) | ||||
|       console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`) | ||||
|     }); | ||||
|  | ||||
|   } | ||||
| } | ||||
| @@ -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}); | ||||
|    } | ||||
|  | ||||
| } | ||||
| @@ -1,5 +1,6 @@ | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { RdDItem } from "../item.js"; | ||||
| import { Grammar } from "../grammar.js" | ||||
| import { ITEM_TYPES, RdDItem } from "../item.js" | ||||
| import { SystemCompendiums } from "../settings/system-compendiums.js" | ||||
|  | ||||
| const DON_HAUT_REVE = "Don de Haut-Rêve" | ||||
|   | ||||
							
								
								
									
										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)) | ||||
|   } | ||||
| } | ||||
| @@ -2,7 +2,8 @@ import { RdDBaseActor } from "./actor/base-actor.js"; | ||||
| import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { Monnaie } from "./item-monnaie.js"; | ||||
| import { RdDItem, ITEM_TYPES, ACTOR_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES, ACTOR_TYPES } from "./constants.js"; | ||||
| import { RdDItem } from "./item.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
| import { RdDRaretes } from "./item/raretes.js"; | ||||
| import { VOIES_DRACONIC } from "./item-sort.js"; | ||||
| @@ -588,6 +589,42 @@ class _12_0_32_MigrationRaces extends Migration { | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _12_0_37_MigrationAlchimieEtat extends Migration { | ||||
|   get code() { return "migration-alchimie-etat" } | ||||
|   get version() { return "12.0.37" } | ||||
|  | ||||
|   async migrate() { | ||||
|     await this.applyItemsUpdates(items => items | ||||
|       .filter(it => [ITEM_TYPES.potion].includes(it.type)) | ||||
|       .map(it => this.migratePotion(it)) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   mappingCategorie(categorie) { | ||||
|     switch (categorie) { | ||||
|       case 'AlchimieEnchante': return 'Alchimie' | ||||
|       case 'ReposEnchante': return 'Repos' | ||||
|       case 'SoinEnchante': return 'Soin' | ||||
|       case 'AutreEnchante': return 'Autre' | ||||
|     } | ||||
|     return categorie | ||||
|   } | ||||
|  | ||||
|   mappingEtat(categorie) { | ||||
|     return ['Alchimie', 'Repos', 'Soin', 'Autre'].includes(categorie) ? 'Liquide' : 'Autre' | ||||
|   } | ||||
|  | ||||
|   async migratePotion(potion) { | ||||
|     const newCategorie = this.mappingCategorie(potion.system.categorie) | ||||
|     return { | ||||
|       _id: potion.id, | ||||
|       'system.etat': this.mappingEtat(potion.system.categorie), | ||||
|       'system.magique': potion.system.pr > 0, | ||||
|       'system.categorie': newCategorie | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| export class Migrations { | ||||
|   static getMigrations() { | ||||
|     return [ | ||||
| @@ -609,6 +646,7 @@ export class Migrations { | ||||
|       new _11_2_20_MigrationAstrologie(), | ||||
|       new _12_0_26_MigrationVoieSorts(), | ||||
|       new _12_0_32_MigrationRaces(), | ||||
|       new _12_0_37_MigrationAlchimieEtat(), | ||||
|     ]; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -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 '.encaisser-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'); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   | ||||
| @@ -361,13 +361,14 @@ export class RdDCommands { | ||||
|   async getTMRAleatoire(msg, params) { | ||||
|     if (params.length < 2) { | ||||
|       let type = params[0] | ||||
|       const solvedTerrain = TMRUtility.findTMRLike(type)?.type | ||||
|       if (solvedTerrain){ | ||||
|         const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == solvedTerrain) : (it => true)) | ||||
|       const solvedTerrain = type ? TMRUtility.findTMRLike(type)?.type : undefined | ||||
|       const filter = solvedTerrain ? (it => it.type == solvedTerrain) : (it => true) | ||||
|       if (type == undefined || solvedTerrain != undefined) { | ||||
|         const tmr = await TMRUtility.getTMRAleatoire(filter) | ||||
|         return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`) | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|     return false | ||||
|   } | ||||
|  | ||||
|   async findTMR(msg, params) { | ||||
|   | ||||
| @@ -4,8 +4,7 @@ import { RdDRoll } from "./rdd-roll.js"; | ||||
| import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; | ||||
| import { ChatUtility } from "./chat-utility.js"; | ||||
| import { STATUSES } from "./settings/status-effects.js"; | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
|  | ||||
| @@ -429,7 +428,6 @@ export class RdDEmpoignade { | ||||
|     return await Item.create({ | ||||
|       name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name, | ||||
|       type: 'empoignade', | ||||
|       img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", | ||||
|       system: { description: "", empoignadeid: foundry.utils.randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name } | ||||
|     }, | ||||
|       { | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
|  | ||||
| const tableGemmes = { | ||||
|   "almaze": { label: "Almaze", couleur: "Blanc"}, | ||||
|   "aquafane": { label: "Aquafane", couleur: "Vert Profond"}, | ||||
|   "asterite": { label: "Astérite", couleur: "Bleu, Violet ou Blanc"}, | ||||
|   "cyanolithe": { label: "Cyanolithe", couleur: "Bleu Intense"}, | ||||
|   "larmededragon": { label: "Larme de Dragon", couleur: "Rouge Intense"}, | ||||
|   "muska": { label: "Muska", couleur: "Violet Profond"}, | ||||
|   "nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense"}, | ||||
|   "nebuleuse": { label: "Nébuleuse", couleur: "Brouillard Intense, Rose, Vert ou Bleu Pâle"}, | ||||
|   "oeildetigre": { label: "Oeil de Tigre", couleur: "Jaune"}, | ||||
|   "scarlatine": { label: "Scarlatine", couleur: "Rouge Clair ou Orangé"}, | ||||
|   "seliphane": { label: "Séliphane", couleur: "Vert Lumineux"}, | ||||
|   "tournelune": { label: "Tournelune", couleur: "Violet ou Bleu"}, | ||||
|   "zebraide": { label: "Zebraïde", couleur: "Bandes Bicolores, toutes couleurs"} | ||||
| } | ||||
|  | ||||
| export class RdDGemme extends Item { | ||||
|  | ||||
|   static getGemmeTypeOptionList() { | ||||
|     // TODO: look how to map object key-value pairs | ||||
|     let options = "" | ||||
|     for (let gemmeKey in tableGemmes) { | ||||
|       options += `<option value="${gemmeKey}">${tableGemmes[gemmeKey].label}</option>` | ||||
|     } | ||||
|     return options; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   static calculDataDerivees(gemme) { | ||||
|     gemme.system.cout = (gemme.system.taille * gemme.system.purete) + gemme.system.qualite; | ||||
|     gemme.system.inertie = 7 - gemme.system.purete; | ||||
|     gemme.system.enchantabilite = gemme.system.taille - gemme.system.inertie; | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| import { Grammar } from "./grammar.js"; | ||||
| import { SystemCompendiums } from "./settings/system-compendiums.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| export class RdDHerbes extends Item { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async onReady() { | ||||
|     this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin'); | ||||
|     this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos'); | ||||
|   } | ||||
|  | ||||
|   static async listCategorieHerbes(categorie) { | ||||
|     const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux'); | ||||
|     return herbes.filter(it => Grammar.equalsInsensitive(it.system.categorie, categorie)); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static buildHerbesList(listeHerbes, max) { | ||||
|     let list = {} | ||||
|     for (let herbe of listeHerbes) { | ||||
|       let brins = max - herbe.system.niveau; | ||||
|       list[herbe.name] = `${herbe.name} (Bonus: ${herbe.system.niveau}, Brins: ${brins})`; | ||||
|     } | ||||
|     list['Autre'] = 'Autre (Bonus: variable, Brins: variable)' | ||||
|     return list; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static calculFormData(formData, item) { | ||||
|     formData.isSoins = item.system.categorie.includes('Soin'); | ||||
|     formData.isRepos = item.system.categorie.includes('Repos'); | ||||
|     if (formData.isSoins) { | ||||
|       RdDHerbes.calculBonusHerbe(formData, this.herbesSoins, 12); | ||||
|     } | ||||
|     if (formData.isRepos) { | ||||
|       RdDHerbes.calculBonusHerbe(formData, this.herbesRepos, 7); | ||||
|     } | ||||
|     formData.herbesSoins = RdDHerbes.buildHerbesList(this.herbesSoins, 12); | ||||
|     formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7); | ||||
|     formData.dateActuelle = game.system.rdd.calendrier.dateCourante(); | ||||
|     formData.enchantement = RdDTimestamp.splitIndexDate(item.system.prdate); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static calculPuissancePotion(potion) { | ||||
|     return potion.system.herbebonus * potion.system.pr; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static calculPointsRepos(potion) { | ||||
|     return potion.system.herbebonus * potion.system.pr; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static calculPointsGuerison(potion) { | ||||
|     return potion.system.herbebonus * potion.system.pr; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static calculBonusHerbe(formData, herbesList, max) { | ||||
|     if (Number(formData.system.herbebrins)) { | ||||
|       let herbe = herbesList.find(item => item.name.toLowerCase() == formData.system.herbe.toLowerCase()); | ||||
|       if (herbe) { | ||||
|         const brinsRequis = max - herbe.system.niveau; | ||||
|         const brinsManquants = Math.max(brinsRequis - formData.system.herbebrins, 0); | ||||
|         formData.system.herbebonus = Math.max(herbe.system.niveau - brinsManquants, 0); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| }   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import { RdDItemArme } from "./item-arme.js"; | ||||
| import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
|  | ||||
| export class RdDHotbar { | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js" | ||||
| import { ReglesOptionnelles } from "./settings/regles-optionnelles.js" | ||||
| import { RdDHotbar } from "./rdd-hotbar-drop.js" | ||||
| import { EffetsDraconiques } from "./tmr/effets-draconiques.js" | ||||
| import { RdDHerbes } from "./rdd-herbes.js" | ||||
| import { RdDDice } from "./rdd-dice.js" | ||||
| import { RdDPossession } from "./rdd-possession.js" | ||||
| import { Misc } from "./misc.js" | ||||
| @@ -75,6 +74,11 @@ 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 { RdDPotionItemSheet } from "./item/sheet-potion.js" | ||||
| import { RdDItemPotion } from "./item/potion.js" | ||||
| import { RdDItemGemme } from "./item/gemme.js" | ||||
| import { RdDGemmeItemSheet } from "./item/sheet-gemme.js" | ||||
|  | ||||
| /** | ||||
|  * RdD system | ||||
| @@ -85,9 +89,9 @@ export class SystemReveDeDragon { | ||||
|  | ||||
|   static start() { | ||||
|     const system = new SystemReveDeDragon() | ||||
|     Hooks.once('init', async () => await system.onInit()) | ||||
|     Hooks.once('init', () => system.onInit()) | ||||
|     Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)) | ||||
|     Hooks.once('ready', async () => await system.onReady()) | ||||
|     Hooks.once('ready', () => system.onReady()) | ||||
|   } | ||||
|  | ||||
|   constructor() { | ||||
| @@ -98,16 +102,18 @@ export class SystemReveDeDragon { | ||||
|     this.itemClasses = { | ||||
|       armure: RdDItemArmure, | ||||
|       blessure: RdDItemBlessure, | ||||
|       gemme: RdDItemGemme, | ||||
|       maladie: RdDItemMaladie, | ||||
|       ombre: RdDItemOmbre, | ||||
|       poison: RdDItemPoison, | ||||
|       potion: RdDItemPotion, | ||||
|       queue: RdDItemQueue, | ||||
|       tete: RdDItemTete, | ||||
|       race: RdDItemRace, | ||||
|       rencontre: RdDRencontre, | ||||
|       service: RdDItemService, | ||||
|       signedraconique: RdDItemSigneDraconique, | ||||
|       souffle: RdDItemSouffle, | ||||
|       tete: RdDItemTete, | ||||
|     } | ||||
|     this.actorClasses = { | ||||
|       commerce: RdDCommerce, | ||||
| @@ -121,7 +127,7 @@ export class SystemReveDeDragon { | ||||
|   /* -------------------------------------------- */ | ||||
|   /*  Foundry VTT Initialization                  */ | ||||
|   /* -------------------------------------------- */ | ||||
|   async onInit() { | ||||
|   onInit() { | ||||
|     game.system.rdd = this | ||||
|     this.AppAstrologie = AppAstrologie | ||||
|  | ||||
| @@ -185,23 +191,14 @@ export class SystemReveDeDragon { | ||||
|     Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }) | ||||
|     Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }) | ||||
|     Items.unregisterSheet("core", ItemSheet) | ||||
|     await RdDActorExportSheet.init() | ||||
|  | ||||
|     RdDItemSheet.register(RdDSigneDraconiqueItemSheet) | ||||
|     RdDItemSheet.register(RdDRencontreItemSheet) | ||||
|     RdDItemSheet.register(RdDConteneurItemSheet) | ||||
|     RdDItemSheet.register(RdDHerbeItemSheet) | ||||
|     RdDItemSheet.register(RdDFauneItemSheet) | ||||
|     RdDItemSheet.register(RdDPlanteItemSheet) | ||||
|     RdDItemSheet.register(RdDIngredientItemSheet) | ||||
|     RdDItemSheet.register(RdDServiceItemSheet) | ||||
|     RdDItemSheet.register(RdDBlessureItemSheet) | ||||
|     RdDActorExportSheet.init() | ||||
|  | ||||
|     Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, { | ||||
|       types: [ | ||||
|         "objet", "arme", "armure", "livre", "potion", "munition", | ||||
|         "monnaie", "nourritureboisson", "gemme", | ||||
|       ], makeDefault: true | ||||
|         "objet", "arme", "armure", "livre", "munition", | ||||
|         "monnaie", "nourritureboisson", | ||||
|       ], | ||||
|       makeDefault: true | ||||
|     }) | ||||
|     Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { | ||||
|       types: [ | ||||
| @@ -211,8 +208,22 @@ export class SystemReveDeDragon { | ||||
|         "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve", | ||||
|         "nombreastral", "tache", "maladie", "poison", "possession", | ||||
|         "tarot", "extraitpoetique", "empoignade" | ||||
|       ], makeDefault: true | ||||
|       ], | ||||
|       makeDefault: true | ||||
|     }) | ||||
|      | ||||
|     RdDItemSheet.register(RdDBlessureItemSheet) | ||||
|     RdDItemSheet.register(RdDConteneurItemSheet) | ||||
|     RdDItemSheet.register(RdDFauneItemSheet) | ||||
|     RdDItemSheet.register(RdDGemmeItemSheet) | ||||
|     RdDItemSheet.register(RdDHerbeItemSheet) | ||||
|     RdDItemSheet.register(RdDIngredientItemSheet) | ||||
|     RdDItemSheet.register(RdDPlanteItemSheet) | ||||
|     RdDItemSheet.register(RdDPotionItemSheet) | ||||
|     RdDItemSheet.register(RdDRencontreItemSheet) | ||||
|     RdDItemSheet.register(RdDServiceItemSheet) | ||||
|     RdDItemSheet.register(RdDSigneDraconiqueItemSheet) | ||||
|     RdDJournalSheet.register() | ||||
|  | ||||
|     // préparation des différents modules | ||||
|     console.log(`Initializing Reve de Dragon Hooks and handlers`) | ||||
| @@ -313,7 +324,6 @@ export class SystemReveDeDragon { | ||||
|     } | ||||
|  | ||||
|     StatusEffects.onReady() | ||||
|     RdDHerbes.onReady() | ||||
|     RdDDice.onReady() | ||||
|  | ||||
|     RdDStatBlockParser.parseStatBlock() | ||||
|   | ||||
| @@ -3,7 +3,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js"; | ||||
| import { RdDRoll } from "./rdd-roll.js"; | ||||
| import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; | ||||
| import { Targets } from "./targets.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| /* On part du principe qu'une entité démarre tjs  | ||||
| @@ -174,7 +174,7 @@ export class RdDPossession { | ||||
|     await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html') | ||||
|     if (rollData.possession.isPosseder || rollData.possession.isConjurer) { | ||||
|       // conjuration | ||||
|       victime.deleteEmbeddedDocuments("Item", [rollData.possession._id]) | ||||
|       await victime.deleteEmbeddedDocuments("Item", [rollData.possession._id]) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -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 "./constants.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,16 @@ 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( | ||||
|         this.actor?.type == ACTOR_TYPES.personnage | ||||
|           ? RdDCarac.caracDetails(this.rollData.selectedCarac.label).code | ||||
|           : this.rollData.selectedCarac.label | ||||
|       ) | ||||
|     } | ||||
|     if (this.rollData.selectedSort) { | ||||
|       this.setSelectedSort(this.rollData.selectedSort); | ||||
| @@ -173,7 +179,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); | ||||
|   | ||||
| @@ -28,8 +28,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 +103,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) | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -66,11 +66,13 @@ export class RdDSheetUtility { | ||||
|   } | ||||
|  | ||||
|   static async splitItem(item, actor, onSplit = () => { }) { | ||||
|     const dialog = await DialogSplitItem.create(item, async (item, split) => { | ||||
|     const _onSplit = async (item, split) => { | ||||
|       await RdDSheetUtility._onSplitItem(item, split, actor); | ||||
|       onSplit(); | ||||
|     }); | ||||
|     dialog.render(true); | ||||
|       await RdDSheetUtility.renderItemBranch(actor, item) | ||||
|     } | ||||
|     const dialog = await DialogSplitItem.create(item, _onSplit) | ||||
|     dialog.render(true) | ||||
|   } | ||||
|  | ||||
|   static async _onSplitItem(item, split, actor) { | ||||
| @@ -82,4 +84,11 @@ export class RdDSheetUtility { | ||||
|       await actor.createEmbeddedDocuments('Item', [splitItem]) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static async renderItemBranch(actor, item) { | ||||
|     while (item) { | ||||
|       await item.sheet?.render() | ||||
|       item = actor.getContenant(item) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -16,7 +16,7 @@ import { RdDDice } from "./rdd-dice.js"; | ||||
| import { STATUSES } from "./settings/status-effects.js"; | ||||
| import { RdDRencontre } from "./item/rencontre.js"; | ||||
| import { RdDTimestamp } from "./time/rdd-timestamp.js"; | ||||
| import { ITEM_TYPES } from "./item.js"; | ||||
| import { ITEM_TYPES } from "./constants.js"; | ||||
| import { Misc } from "./misc.js"; | ||||
|  | ||||
| const TMR_DISPLAY_SIZE = { | ||||
| @@ -212,7 +212,7 @@ export class RdDTMRDialog extends Dialog { | ||||
|   } | ||||
|  | ||||
|   getSortsReserve(coord) { | ||||
|     return this.actor.itemTypes[ITEM_TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale | ||||
|     return this.sortsReserve.filter(// Reserve sur une case fleuve ou normale | ||||
|       TMRUtility.getTMR(coord).type == 'fleuve' | ||||
|         ? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve' | ||||
|         : it => it.system.coord == coord | ||||
| @@ -241,7 +241,7 @@ export class RdDTMRDialog extends Dialog { | ||||
|     this._getTokensRencontres().forEach(t => this._trackToken(t)) | ||||
|     this._getTokensSortsReserve().forEach(t => this._trackToken(t)) | ||||
|   } | ||||
|    | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   updateTokens() { | ||||
|     this._removeTokens(t => true); | ||||
| @@ -271,8 +271,7 @@ export class RdDTMRDialog extends Dialog { | ||||
|   } | ||||
|  | ||||
|   _getTokensSortsReserve() { | ||||
|     const sortsReserve = this.actor.itemTypes[ITEM_TYPES.sortreserve]; | ||||
|     return Misc.concat(sortsReserve.map(sortReserve => | ||||
|     return Misc.concat(this.sortsReserve.map(sortReserve => | ||||
|       EffetsDraconiques.sortReserve.tokens(this.pixiTMR, sortReserve, () => sortReserve.system.coord))) | ||||
|   } | ||||
|  | ||||
| @@ -908,8 +907,8 @@ export class RdDTMRDialog extends Dialog { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   lancerSortEnReserve(coord, sortId) { | ||||
|     let sorts = this.getSortsReserve(coord); | ||||
|     let sort = sorts.find(it => it.id == sortId); | ||||
|     const sort = this.getSortsReserve(coord) | ||||
|       .find(it => it.id == sortId); | ||||
|     if (sort) { | ||||
|       this.processSortReserve(sort); | ||||
|     } else { | ||||
|   | ||||
| @@ -19,9 +19,12 @@ import { RdDEmpoignade } from "./rdd-empoignade.js"; | ||||
| import { ExperienceLog } from "./actor/experience-log.js"; | ||||
| import { RdDCoeur } from "./coeur/rdd-coeur.js"; | ||||
| import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js"; | ||||
| import { RDD_CONFIG } from "./constants.js"; | ||||
| import { ITEM_TYPES, 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"; | ||||
| import { Monnaie } from "./item-monnaie.js"; | ||||
| import { ItemAction } from "./item/item-actions.js"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| // This table starts at 0 -> niveau -10 | ||||
| @@ -106,7 +109,7 @@ export class RdDUtility { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async preloadHandlebarsTemplates() { | ||||
|   static preloadHandlebarsTemplates() { | ||||
|     const templatePaths = [ | ||||
|       //Character Sheets | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html', | ||||
| @@ -114,6 +117,7 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html', | ||||
|       // sous-parties de feuilles de personnages | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/item-action-controls.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/header-buttons.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/header-etat.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/header-compteurs.html', | ||||
| @@ -128,48 +132,47 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/carac-derivee.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/carac-creature.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/carac-entitee.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/comp-creature.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/comp-possession.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/carac-total.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/competence.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/competence.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/competence-categorie.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/xp-competences.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/combat.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/blessures.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/blessure.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/maladies-poisons.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/possessions.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/resonances.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/taches.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/jeux.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/taches.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvres.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/oeuvre.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/jeus.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/alchimie.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/astrologie.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/chirurgie.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/non-haut-revant.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/haut-revant.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queues.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-tetes.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-signes-draconiques.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-rencontres.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts-reserve.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-meditations.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-casestmr.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-queue.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-souffles.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/dragon-tetes.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-signes-draconiques.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-rencontres.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-sorts-reserve.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-meditations.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/hr-casetmrs.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/xp-journal.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/editor-notes-mj.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html', | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.html", | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.hbs', | ||||
|       "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-monnaie.hbs", | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/liens-animaux.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.hbs', | ||||
|       //Items | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs', | ||||
| @@ -179,8 +182,9 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/header-item.html', | ||||
|  | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/queue-sheet.hbs', | ||||
|       // partial enums | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html', | ||||
| @@ -188,7 +192,8 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categories.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-ingredient.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/enum-categorie-alchimie.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/item/enum-etat-alchimie.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-queue.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html', | ||||
| @@ -202,6 +207,7 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-type.html', | ||||
|       // Partials | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/enchantement/partial-enchantement.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/coeur/chat-effet-tendre-moment.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/coeur/afficher-coeur.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/tirage/liste-resultats-recherche.hbs', | ||||
| @@ -258,11 +264,10 @@ export class RdDUtility { | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html' | ||||
|     ]; | ||||
|      | ||||
|  | ||||
|     // foundry et options | ||||
|     Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path]) | ||||
|     Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name)); | ||||
| @@ -277,7 +282,7 @@ export class RdDUtility { | ||||
|       const html = options.fn(this); | ||||
|       return html.replace(rgx, "$& selected"); | ||||
|     }) | ||||
|      | ||||
|  | ||||
|     // logic | ||||
|     Handlebars.registerHelper('either', (a, b) => a ?? b); | ||||
|     // string manipulation | ||||
| @@ -289,12 +294,13 @@ 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) { | ||||
|     Handlebars.registerHelper('repeat', function (n, block) { | ||||
|       let accum = ''; | ||||
|       for(let i = 0; i < n; ++i){ | ||||
|       for (let i = 0; i < n; ++i) { | ||||
|         accum += block.fn(i) | ||||
|       } | ||||
|       return accum | ||||
| @@ -332,6 +338,9 @@ export class RdDUtility { | ||||
|     Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field)); | ||||
|     // Items | ||||
|     Handlebars.registerHelper('rarete-getChamp', (rarete, field) => RdDRaretes.getChamp(rarete, field)); | ||||
|     Handlebars.registerHelper('item-action-applies', (action, item, options) => ItemAction.applies(action, item, options)) | ||||
|     Handlebars.registerHelper('item-action-icon', (action, item) => ItemAction.icon(action, item)) | ||||
|     Handlebars.registerHelper('item-name', (item) =>  item.nameDisplay) | ||||
|  | ||||
|     // TMRs | ||||
|     Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); | ||||
| @@ -339,7 +348,7 @@ export class RdDUtility { | ||||
|     Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type)); | ||||
|     Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord)); | ||||
|  | ||||
|     return loadTemplates(templatePaths); | ||||
|     loadTemplates(templatePaths); | ||||
|   } | ||||
|  | ||||
|   static getItem(itemId, actorId = undefined) { | ||||
| @@ -433,8 +442,8 @@ export class RdDUtility { | ||||
|     }; | ||||
|     if (!optionsArbre.templateItem) { | ||||
|       optionsArbre.templateItem = item.parent?.type == 'commerce' | ||||
|         ? "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.html" | ||||
|         : "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.html"; | ||||
|         ? "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-inventaire-item.hbs" | ||||
|         : "systems/foundryvtt-reve-de-dragon/templates/actor/inventaire-item.hbs"; | ||||
|     } | ||||
|     item.niveau = optionsArbre.profondeur; | ||||
|   } | ||||
| @@ -462,13 +471,38 @@ export class RdDUtility { | ||||
|     return ligneObjet; | ||||
|   } | ||||
|  | ||||
|   static filterItemsPerTypeForSheet(formData, itemTypes) { | ||||
|     Object.values(ITEM_TYPES).forEach(t => { | ||||
|       formData[t + 's'] = Misc.arrayOrEmpty(itemTypes[t]) | ||||
|       itemTypes[t].forEach(item => item.actions = item.itemActions()) | ||||
|     }) | ||||
|  | ||||
|     formData.maladiesPoisons = formData.maladies.concat(formData.poisons) | ||||
|     formData.competences = formData.competences.concat(formData.competencecreatures) | ||||
|     formData.monnaies = formData.monnaies.sort(Monnaie.triValeurEntiere()) | ||||
|  | ||||
|     formData.inventaires = RdDUtility.prepareInventaire(itemTypes) | ||||
|   } | ||||
|  | ||||
|   static buildInventaireConteneur(actorId, itemId, options) { | ||||
|     const actor = game.actors.get(actorId) | ||||
|     const item = actor?.items.get(itemId) | ||||
|     if (item) { | ||||
|       return RdDUtility.buildContenuConteneur(item, options, { ouvert: true, profondeur: 1 }); | ||||
|     if (item?.type == ITEM_TYPES.conteneur) { | ||||
|       const formData = {} | ||||
|       RdDUtility.filterItemsPerTypeForSheet(formData, actor.itemTypes); | ||||
|       RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires); | ||||
|       item.subItems = formData.conteneurs.find(it => it._id == itemId)?.subItems; | ||||
|  | ||||
|       return RdDUtility.buildContenuConteneur(item, options, { ouvert: true, profondeur: 1 }) | ||||
|     } | ||||
|     return ''; | ||||
|     return '' | ||||
|   } | ||||
|  | ||||
|   static prepareInventaire(itemTypes) { | ||||
|     return RdDItem.getItemTypesInventaire('all') | ||||
|       .map(t => Misc.arrayOrEmpty(itemTypes[t])) | ||||
|       .reduce((a, b) => a.concat(b), []) | ||||
|       .sort(Misc.ascending(it => it.name)) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -695,6 +729,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 => { | ||||
| @@ -869,7 +904,7 @@ export class RdDUtility { | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static async confirmActorItemDelete(sheet, item, htmlToDelete) { | ||||
|   static async confirmActorItemDelete(item, actor) { | ||||
|     const itemId = item.id; | ||||
|     const confirmationSuppression = { | ||||
|       settingConfirmer: "confirmation-supprimer-" + item.getItemGroup(), | ||||
| @@ -878,8 +913,7 @@ export class RdDUtility { | ||||
|       buttonLabel: "Supprimer", | ||||
|       onAction: () => { | ||||
|         console.log('Delete : ', itemId); | ||||
|         sheet.actor.deleteEmbeddedDocuments('Item', [itemId], { renderSheet: false }); | ||||
|         RdDUtility.slideOnDelete(sheet, htmlToDelete); | ||||
|         actor.deleteEmbeddedDocuments('Item', [itemId], { renderSheet: false }); | ||||
|       } | ||||
|     }; | ||||
|     if (item.isConteneurNonVide()) { | ||||
| @@ -892,8 +926,7 @@ export class RdDUtility { | ||||
|             label: "Supprimer conteneur et contenu", | ||||
|             callback: () => { | ||||
|               console.log("Delete : ", itemId); | ||||
|               sheet.actor.deleteAllConteneur(itemId, { renderSheet: false }); | ||||
|               RdDUtility.slideOnDelete(sheet, htmlToDelete); | ||||
|               actor.deleteAllConteneur(itemId, { renderSheet: false }); | ||||
|             } | ||||
|           } | ||||
|         }); | ||||
|   | ||||
| @@ -334,6 +334,10 @@ export class RdDTimestamp { | ||||
|     return this.nouvelleHeure().addHeures((12 + heure - this.heure) % 12); | ||||
|   } | ||||
|  | ||||
|   debutJournee() { | ||||
|     return RdDTimestamp.timestamp(this.annee, this.mois, this.jour) | ||||
|   } | ||||
|  | ||||
|   async appliquerDuree(duree, actor) { | ||||
|     const formule = FORMULES_DUREE.find(it => it.code == duree) ?? FORMULES_DUREE.find(it => it.code == ""); | ||||
|     return await formule.calcul(this, actor); | ||||
|   | ||||
| @@ -26,7 +26,7 @@ export class TMRRencontres { | ||||
|    * @param {*} forcedRoll  | ||||
|    */ | ||||
|   async rollRencontre(terrain, forcedRoll) { | ||||
|     const tmrType = TMRUtility.findTMRLike(terrain)?.type | ||||
|     const tmrType = TMRUtility.findTMRLike(terrain, { inclusMauvaise: true })?.type | ||||
|     if (tmrType == undefined) { | ||||
|       return undefined; | ||||
|     } | ||||
| @@ -38,7 +38,7 @@ export class TMRRencontres { | ||||
|     const frequence = it => it.system.frequence[tmrType]; | ||||
|     const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll); | ||||
|     if (row) { | ||||
|       await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', {showSource: false}); | ||||
|       await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item', { showSource: false }); | ||||
|     } | ||||
|  | ||||
|     return row?.document; | ||||
|   | ||||
| @@ -22,7 +22,7 @@ export const TMRType = { | ||||
| export const FLEUVE_COORD = 'Fleuve' | ||||
|  | ||||
| const TMRMapping = { | ||||
|   Fleuve: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli" }, | ||||
|   Fleuve: { type: TMRType.fleuve.type, label: "Fleuve de l'Oubli", generique: 'fleuve' }, | ||||
|   A1: { type: TMRType.cite.type, label: "Cité Vide" }, | ||||
|   B1: { type: TMRType.plaines.type, label: "Plaines d’Assorh" }, | ||||
|   C1: { type: TMRType.necropole.type, label: "Nécropole de Kroak" }, | ||||
| @@ -281,18 +281,18 @@ export class TMRUtility { | ||||
|     return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label; | ||||
|   } | ||||
|  | ||||
|   static findTMRLike(type, options = { inclusMauvaise: true }) { | ||||
|   static findTMRLike(type, options = { inclusMauvaise: false }) { | ||||
|     const choix = [...Object.values(TMRType)] | ||||
|     if (options.inclusMauvaise) { | ||||
|       choix.push({ name: 'Mauvaise', type: 'mauvaise'}); | ||||
|     } | ||||
|     const selection = Misc.findAllLike(type, choix) | ||||
|     if (selection.length == 0) { | ||||
|       ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix}`); | ||||
|       ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix.map(it => it.name).reduce(Misc.joining(', '))}`); | ||||
|       return undefined | ||||
|     } | ||||
|     if (selection.length > 1) { | ||||
|       ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection.map(it => it.name)}`); | ||||
|       ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection.map(it => it.name).reduce(Misc.joining(', '))}`); | ||||
|       return undefined; | ||||
|     } | ||||
|     return selection[0] | ||||
| @@ -357,7 +357,7 @@ export class TMRUtility { | ||||
|   } | ||||
|  | ||||
|   static filterTMR(filter) { | ||||
|     return Object.values(TMRMapping).filter(filter); | ||||
|     return Object.values(TMRMapping).filter(it => !it.generique && filter(it)) | ||||
|   } | ||||
|  | ||||
|   static getCasesType(type) { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { TMRUtility } from "../tmr-utility.js"; | ||||
| import { PixiTMR } from "./pixi-tmr.js"; | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,7 @@ import { Periple } from "./periple.js"; | ||||
| import { UrgenceDraconique } from "./urgence-draconique.js"; | ||||
| import { Grammar } from "../grammar.js"; | ||||
| import { AugmentationSeuil } from "./augmentation-seuil.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
|  | ||||
| export class EffetsDraconiques { | ||||
|   static carteTmr = new CarteTmr(); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { RdDRollTables } from "../rdd-rolltables.js"; | ||||
| import { TMRUtility } from "../tmr-utility.js"; | ||||
| import { tmrTokenZIndex } from "../tmr-constants.js"; | ||||
| import { Draconique } from "./draconique.js"; | ||||
| import { ITEM_TYPES } from "../item.js"; | ||||
| import { ITEM_TYPES } from "../constants.js"; | ||||
| import { TMRAnimations } from "./animation.js"; | ||||
|  | ||||
| export class UrgenceDraconique extends Draconique { | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| import { ITEM_TYPES } from "../item.js" | ||||
| import { ITEM_TYPES } from "../constants.js" | ||||
| import { RdDItemCompetence } from "../item-competence.js" | ||||
| import { ChatUtility } from "../chat-utility.js" | ||||
| import { Misc } from "../misc.js" | ||||
|   | ||||
| @@ -300,7 +300,7 @@ system: | ||||
|     déchirure. Celle-là se contente de chercher à fuir en | ||||
|     cas d’agression, ou attaque toutes griffes dehors si elle se sent | ||||
|     acculée. Pour la distinguer (visuellement) de la rieuse, | ||||
|     réussir VUE/Zoologie à -5. Les caractéristiques de | ||||
|     réussir @roll[VUE/Zoologie/-5]. Les caractéristiques de | ||||
|     combat indiquées ne s’appliquent qu’à la | ||||
|     pointue.</p> | ||||
|   race: '' | ||||
|   | ||||
| @@ -215,7 +215,7 @@ system: | ||||
|     souffrir ses premiers malus à la course et au saut. La vitesse | ||||
|     indiquée correspond à une allure plutôt lente. | ||||
|     Contrairement aux autres animaux pour qui la vitesse de base est fixe, le | ||||
|     gardien des rêves peut rajouter jusqu’à 3d6 points | ||||
|     gardien des rêves peut rajouter jusqu’à @roll[3d6] points | ||||
|     à la vitesse de course de chaque individu. Cette nouvelle vitesse de | ||||
|     course est rajoutée une fois pour toutes, mais peut être | ||||
|     modulée par un jet de course sur la table de Course animale.</p> | ||||
|   | ||||
| @@ -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é | ||||
|   | ||||
| @@ -2358,6 +2358,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Epais | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -3898,6 +3899,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -4919,6 +4921,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Epais | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -5350,6 +5353,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -5606,6 +5610,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -5766,6 +5771,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -6438,6 +6444,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -6672,6 +6679,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Solide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -7157,6 +7165,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Poudre | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -7611,6 +7620,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Liquide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -7690,6 +7700,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Solide | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -7768,6 +7779,7 @@ items: | ||||
|           indexMinute: 0 | ||||
|       rarete: '' | ||||
|       categorie: Remede | ||||
|       etat: Epais | ||||
|       herbe: '' | ||||
|       herbebrins: 0 | ||||
|       herbebonus: 0 | ||||
| @@ -8010,7 +8022,7 @@ items: | ||||
|         poussant dans les lieux frais et humides : marais ombragés, | ||||
|         certaines forêts, et parfois vallées de montagne. Un peu | ||||
|         moins rare est la fausse endebrume, qui lui ressemble physiquement, mais | ||||
|         n'a aucune vertu. <br /><em>VUE/Botanique à -1 pour savoir | ||||
|         n'a aucune vertu. <br /><em>@roll[VUE/Botanique/-1] pour savoir | ||||
|         à quelle espèce on a affaire (jet obligatoire à | ||||
|         chaque cueillette).</em></p> | ||||
|  | ||||
| @@ -8782,7 +8794,7 @@ items: | ||||
|     system: | ||||
|       description: |- | ||||
|         <p>Poudre brune apparaissant sur les parois des grottes.</p> | ||||
|         <p>VUE/Alchimie à -1.</p> | ||||
|         <p>@roll[VUE/Alchimie/-1].</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -8818,7 +8830,7 @@ items: | ||||
|         <p>Poudre blanche apparaissant sous l’écorce de nombreux | ||||
|         arbres,</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à 0.</p> | ||||
|         <p>@roll[VUE/Alchimie/0].</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -8854,7 +8866,7 @@ items: | ||||
|         <p>Poudre rouge obtenue par disruption alchimique de la | ||||
|         <em>chramaele</em>, minerai ayant l’apparence de la glaise.</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à -4</p> | ||||
|         <p>@roll[VUE/Alchimie/-4]</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -8899,7 +8911,7 @@ items: | ||||
|         <p>Poudre noire obtenue par disruption alchimique du minerai | ||||
|         appelé <em>narthalide</em>, sorte de marne.</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à -3</p> | ||||
|         <p>@roll[VUE/Alchimie/-3]</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -8941,7 +8953,7 @@ items: | ||||
|         <p>Poudre bleuâtre obtenue par disruption alchimique du minerai | ||||
|         appelé <em>obbadine</em>,  sorte de tourbe.</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à -2</p> | ||||
|         <p>@roll[VUE/Alchimie/-2]</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -8983,7 +8995,7 @@ items: | ||||
|         <p>Plus rare que le vert, poudre grisâtre apparaissant le long de | ||||
|         certaines lianes des marais.</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à -4</p> | ||||
|         <p>@roll[VUE/Alchimie/-4]</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
| @@ -9019,7 +9031,7 @@ items: | ||||
|         <p>Poudre verdâtre apparaissant sur les tiges de certains | ||||
|         roseaux.</p> | ||||
|  | ||||
|         <p>VUE/Alchimie à -2</p> | ||||
|         <p>@roll[VUE/Alchimie/-2]</p> | ||||
|       descriptionmj: '' | ||||
|       encombrement: 0.001 | ||||
|       quantite: 1 | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Epais | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -31,6 +31,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Epais | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -31,6 +31,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -31,6 +31,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -31,6 +31,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Solide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Poudre | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -31,6 +31,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Liquide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Solide | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
| @@ -29,6 +29,7 @@ system: | ||||
|       indexMinute: 0 | ||||
|   rarete: '' | ||||
|   categorie: Remede | ||||
|   etat: Epais | ||||
|   herbe: '' | ||||
|   herbebrins: 0 | ||||
|   herbebonus: 0 | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user