Compare commits
	
		
			14 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 43ecca8be1 | |||
| e21f7e398a | |||
| e16f89743a | |||
| a6c593c100 | |||
| cd8e190082 | |||
| f2106763c1 | |||
| 5da5cb0314 | |||
| 6d7f66569a | |||
| 3e8963b20b | |||
| 2cf5b06da8 | |||
| 68c01fc930 | |||
| 3bc1c4871b | |||
| 3d732e9a8a | |||
| 35f226af5c | 
							
								
								
									
										1
									
								
								assets/ui/maladresse.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								assets/ui/maladresse.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M221.313 16a23.682 23.695 0 0 0-23.688 23.688v106.406a23.682 23.695 0 0 0 2.156 9.72 23.682 23.695 0 0 0 3.157 13.81l41.75 71.626-79 55.438 6.094-48.625a23.682 23.695 0 0 0-8.186-20.97l-66.28-81.937a23.682 23.695 0 0 0-33.314-3.5l-9.188 7.438a23.682 23.695 0 0 0-3.53 33.344l59.78 73.906-11.25 89.937a23.682 23.695 0 0 0 12.47 23.876l37.468 53.47a23.695 23.682 1.57 0 0 2.344 2.812 23.682 23.695 0 0 0 13.594 20.062L262 491.53a23.682 23.695 0 0 0 9.97 2.22 23.682 23.695 0 0 0 23.53-2.063l87.156-60.937a23.682 23.695 0 0 0 5.844-33l-6.78-9.688a23.682 23.695 0 0 0-32.97-5.875l-72.406 50.657-59.063-27.625 120.595-84.626a23.695 23.682 1.57 0 0 5.53-5.5 23.682 23.695 0 0 0 14.626-13.594l37.22-91.53 87.813-44.845a23.694 23.682 1.18 0 0 10.312-31.875L488 122.687a23.694 23.682 1.18 0 0-31.875-10.343l-94.688 48.375a23.694 23.682 1.18 0 0-9.843 9.436 23.682 23.695 0 0 0-8.344 10.47l-27.375 67.31-5.22-7.436a23.682 23.695 0 0 0-3-8.844l-50.81-87.094V39.688A23.682 23.695 0 0 0 233.154 16h-11.843zM77.75 376A59.994 60 0 0 0 16 436a59.994 60 0 1 0 120 0 59.994 60 0 0 0-58.25-60z" fill="#fff" fill-opacity="1"></path></g></svg> | ||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										25
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,4 +1,29 @@ | ||||
| # 13.0 | ||||
| ## 13.0.13 - L'épanouissement d'Illysis | ||||
|  | ||||
| - Fix d'erreur au chargement de templates RollDialog | ||||
| - Nouvelle fenêtre de jets de dés | ||||
|   - Fix: affichage des points de tâche | ||||
|   - Fix: affichage des ajustements cohérent | ||||
|   - L'ouverture depuis les caractéristiques permet plusieurs types de jets | ||||
|   - On peut créer ou modifier les tâches dans la fenêtre de jets de tâches | ||||
|   - attaque/défense | ||||
|     - les maladresses sont affichées dans le résultat du jet | ||||
|     - le message au défenseur s'affiche correctement | ||||
|     - la difficulté d'attaque s'applique à la défense | ||||
|     - on peut choisir les particulières en rapidité | ||||
|  | ||||
| ## 13.0.12 - La méditation d'Illysis | ||||
|  | ||||
| - les signes draconiques éphémères de 1 round sont supprimés à la descente des TMRs | ||||
| - Générateur de description | ||||
|   - correction des termes pour les couleurs des yeux/cheveux | ||||
|   - ajout de boutons pour forcer le sexe masculin/féminin | ||||
| - Nouvelle fenêtre de jets de dés | ||||
|   - les méditations proposent un bouton pour monter dans les TMRs | ||||
|   - fenêtre de lancer de sorts | ||||
|   - Correction: les compétences de jeux ne remplacent plus les compétences en dehors des jets de jeu | ||||
|   - gestion des maladresses d'attaque et défense | ||||
|  | ||||
| ## 13.0.11 - Le gambit d'Illysis | ||||
|  | ||||
|   | ||||
| @@ -707,6 +707,10 @@ select, | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details div, | ||||
| .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-details div { | ||||
|   display: block; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions, | ||||
| .system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions { | ||||
|   grid-area: actions; | ||||
| @@ -757,7 +761,10 @@ select, | ||||
| .system-foundryvtt-reve-de-dragon .window-header { | ||||
|   background: rgba(0, 0, 0, 0.75); | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .application .window-content, | ||||
| .system-foundryvtt-reve-de-dragon .application .window-content { | ||||
|   margin: 0; | ||||
|   padding: 0.2rem; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content { | ||||
|   margin: 0.2rem; | ||||
|   padding: 0; | ||||
| @@ -924,6 +931,12 @@ select, | ||||
| .system-foundryvtt-reve-de-dragon a:hover { | ||||
|   text-shadow: 1px 0px 0px #ff6600; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .tabs .item.active img, | ||||
| .system-foundryvtt-reve-de-dragon .blessures-list li ul li:first-child:hover img, | ||||
| .system-foundryvtt-reve-de-dragon i.moral-radio-checkmark-off:hover img, | ||||
| .system-foundryvtt-reve-de-dragon a:hover img { | ||||
|   filter: drop-shadow(1px 0px 0px #ff6600); | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .rollable:hover, | ||||
| .system-foundryvtt-reve-de-dragon .rollable:focus { | ||||
|   color: #000; | ||||
| @@ -1448,12 +1461,27 @@ select, | ||||
| .system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls { | ||||
|   display: none !important; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular), | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls, | ||||
| .system-foundryvtt-reve-de-dragon .item-controls { | ||||
|   vertical-align: super; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls img, | ||||
| .system-foundryvtt-reve-de-dragon .item-controls img { | ||||
|   display: inline; | ||||
|   max-width: 1rem; | ||||
|   max-height: 1rem; | ||||
|   margin: 0 0.1rem; | ||||
|   border: none; | ||||
|   filter: invert(0.8); | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .fa, .fa-solid, .fa-regular), | ||||
| .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) { | ||||
|   font-size: 0.8em; | ||||
|   color: var(--color-controls-light); | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover, | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls img:hover, | ||||
| .system-foundryvtt-reve-de-dragon .item-controls img:hover, | ||||
| .system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover, | ||||
| .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover { | ||||
|   opacity: 0.6; | ||||
| } | ||||
| @@ -1596,6 +1624,9 @@ select, | ||||
|   color: var(--color-text-dark-primary); | ||||
|   border-radius: 0.2rem; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon form.app-personnage-aleatoire h2 { | ||||
|   min-width: 30rem; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral { | ||||
|   width: 14rem; | ||||
|   margin: 0.4rem; | ||||
| @@ -1616,8 +1647,9 @@ select, | ||||
|   height: 2rem; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .window-app .window-content, | ||||
| .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body { | ||||
|   background: #f5f5f0 url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
| .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body, | ||||
| .system-foundryvtt-reve-de-dragon .application .window-content { | ||||
|   background: url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon section.sheet-body { | ||||
|   padding: 0.25rem 0.5rem; | ||||
| @@ -2292,7 +2324,7 @@ select, | ||||
|   pointer-events: all; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon div.horloge-roue div.horloge-cercle { | ||||
|   background: hsl(60, 20%, 95%) url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
|   background: hsla(60, 20%, 90%, 0.8); | ||||
|   top: 2%; | ||||
|   left: 2%; | ||||
|   width: 96%; | ||||
| @@ -2737,11 +2769,9 @@ select, | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .chat-card-button:hover { | ||||
|   background: var(--background-custom-button-hover); | ||||
|   background-color: red; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover { | ||||
|   background: var(--background-custom-button-hover); | ||||
|   background-color: red; | ||||
| } | ||||
| .system-foundryvtt-reve-de-dragon .chat-card-button:active, | ||||
| .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active { | ||||
|   | ||||
| @@ -12,7 +12,10 @@ | ||||
|     background: rgba(0,0,0,0.75); | ||||
|   } | ||||
|  | ||||
|   .application .window-content, | ||||
|   .application .window-content { | ||||
|     margin: 0; | ||||
|     padding: 0.2rem; | ||||
|   } | ||||
|   .window-app.sheet .window-content { | ||||
|     margin: 0.2rem; | ||||
|     padding: 0; | ||||
| @@ -200,6 +203,9 @@ | ||||
|   i.moral-radio-checkmark-off:hover, | ||||
|   a:hover { | ||||
|     text-shadow: 1px 0px 0px #ff6600; | ||||
|     img { | ||||
|       filter: drop-shadow(1px 0px 0px #ff6600); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .rollable:hover, .rollable:focus { | ||||
| @@ -741,11 +747,11 @@ | ||||
|   .foundryvtt-reve-de-dragon .item-list .item img { | ||||
|     display: inline; | ||||
|   } | ||||
|  | ||||
|    | ||||
|   .foundryvtt-reve-de-dragon .item-list .item-name { | ||||
|     margin: 0; | ||||
|   } | ||||
|  | ||||
|    | ||||
|   .competence-list .item-controls, | ||||
|   .competence-list .item-actions-controls { | ||||
|     display: contents !important; | ||||
| @@ -754,15 +760,30 @@ | ||||
|   .competence-list .item-controls.hidden-controls { | ||||
|     display: none !important; | ||||
|   } | ||||
|   .item-actions-controls, | ||||
|   .item-controls { | ||||
|     vertical-align: super; | ||||
|     // a { | ||||
|     // } | ||||
|  | ||||
|   .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular), | ||||
|   .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) { | ||||
|     font-size: 0.8em; | ||||
|     color: var(--color-controls-light); | ||||
|   } | ||||
|   .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover, | ||||
|   .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover { | ||||
|     opacity: 0.6; | ||||
|     img { | ||||
|         display: inline; | ||||
|         max-width: 1rem; | ||||
|         max-height: 1rem; | ||||
|         margin: 0 0.1rem; | ||||
|         border: none; | ||||
|         filter: invert(0.8); | ||||
|     } | ||||
|      | ||||
|     i:is(.fas, .fa, .fa-solid, .fa-regular) { | ||||
|       font-size: 0.8em; | ||||
|       color: var(--color-controls-light); | ||||
|     } | ||||
|      | ||||
|     img:hover, | ||||
|     i:is(.fas, .far, .fa-solid, .fa-regular):hover { | ||||
|       opacity: 0.6; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .rdd-roll-dialog .description-sort { | ||||
| @@ -910,6 +931,11 @@ | ||||
|     color: var(--color-text-dark-primary); | ||||
|     border-radius: 0.2rem; | ||||
|   } | ||||
|   form.app-personnage-aleatoire { | ||||
|     h2 { | ||||
|       min-width: 30rem, | ||||
|     } | ||||
|   } | ||||
|   .app-calendar-astrologie{ | ||||
|     div.theme-astral{ | ||||
|       width: 14rem; | ||||
| @@ -932,8 +958,10 @@ | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .window-app .window-content, .window-app.sheet .window-content .sheet-body{ | ||||
|     background: rgb(245,245,240) url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
|   .window-app .window-content, | ||||
|   .window-app.sheet .window-content .sheet-body, | ||||
|   .application .window-content { | ||||
|     background: url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
|   } | ||||
|  | ||||
|   section.sheet-body { | ||||
| @@ -1654,7 +1682,7 @@ | ||||
|   } | ||||
|  | ||||
|   div.horloge-roue div.horloge-cercle { | ||||
|     background: hsl(60, 20%, 95%) url(../assets/ui/bg_left.webp) no-repeat left top; | ||||
|     background: hsla(60, 20%, 90%, 0.8); | ||||
|     top: 2%; left: 2%; width: 96%; height: 96%; border-radius: 50%; | ||||
|   } | ||||
|  | ||||
| @@ -1998,12 +2026,10 @@ | ||||
|  | ||||
|   .chat-card-button:hover { | ||||
|     background: var(--background-custom-button-hover); | ||||
|     background-color: red; | ||||
|   } | ||||
|  | ||||
|   .chat-card-button-pushed:hover { | ||||
|     background: var(--background-custom-button-hover); | ||||
|     background-color: red; | ||||
|   } | ||||
|  | ||||
|   .chat-card-button:active, .chat-card-button-pushed:active { | ||||
|   | ||||
| @@ -37,6 +37,9 @@ | ||||
|     text-align: justify; | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     div { | ||||
|       display: block; | ||||
|     } | ||||
|   } | ||||
|   div.chat-actions { | ||||
|     grid-area: actions; | ||||
|   | ||||
| @@ -342,7 +342,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async createEmptyTache() { | ||||
|     await this.actor.createItem('tache', 'Nouvelle tache'); | ||||
|     await this.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache') | ||||
|   } | ||||
|  | ||||
|   _getActionCombat(event) { | ||||
|   | ||||
| @@ -47,11 +47,12 @@ import { RdDRollResult } from "./rdd-roll-result.js"; | ||||
| import { RdDInitiative } from "./initiative.mjs"; | ||||
| import RollDialog from "./roll/roll-dialog.mjs"; | ||||
| import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; | ||||
| import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION } from "./roll/roll-constants.mjs"; | ||||
| import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs"; | ||||
| import { PART_TACHE } from "./roll/roll-part-tache.mjs"; | ||||
| import { PART_COMP } from "./roll/roll-part-comp.mjs"; | ||||
| import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs"; | ||||
| import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs"; | ||||
| import { PART_SORT } from "./roll/roll-part-sort.mjs"; | ||||
|  | ||||
| export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] | ||||
|  | ||||
| @@ -741,12 +742,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async sortMisEnReserve(sort, draconic, coord, ptreve) { | ||||
|     await this.createEmbeddedDocuments("Item", [{ | ||||
|       type: ITEM_TYPES.sortreserve, | ||||
|       name: sort.name, | ||||
|       img: sort.img, | ||||
|       system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' } | ||||
|     }], | ||||
|     await this.createEmbeddedDocuments("Item", [RdDItemSort.prepareSortEnReserve(sort, draconic, ptreve, coord)], | ||||
|       { renderSheet: false }); | ||||
|     this.tmrApp.updateTokens(); | ||||
|   } | ||||
| @@ -1712,15 +1708,18 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|       ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!") | ||||
|       return | ||||
|     } | ||||
|     if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { | ||||
|       return await this.rollUnSortV2(); | ||||
|     } | ||||
|     // Duplication car les pts de reve sont modifiés dans le sort! | ||||
|     let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord))) | ||||
|     if (sorts.length == 0) { | ||||
|       ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`); | ||||
|       return; | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     const draconicList = this.computeDraconicAndSortIndex(sorts); | ||||
|     const reve = foundry.utils.duplicate(this.system.carac.reve); | ||||
|     const draconicList = this.computeDraconicAndSortIndex(sorts) | ||||
|     const reve = foundry.utils.duplicate(this.system.carac.reve) | ||||
|  | ||||
|     const dialog = await this.openRollDialog({ | ||||
|       name: 'lancer-un-sort', | ||||
| @@ -1743,6 +1742,27 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     this.tmrApp?.setTMRPendingAction(dialog); | ||||
|   } | ||||
|  | ||||
|   async rollUnSortV2() { | ||||
|     const rollData = { | ||||
|       ids: { actorId: this.id }, | ||||
|       type: { allowed: [ROLL_TYPE_SORT], current: ROLL_TYPE_SORT } | ||||
|     }; | ||||
|     const dialog = await RollDialog.create(rollData, { | ||||
|       callbacks: [roll => { | ||||
|         this.tmrApp?.restoreTMRAfterAction(); | ||||
|         if (roll.closeTMR) { | ||||
|           this.tmrApp?.close(); | ||||
|           this.tmrApp = undefined; | ||||
|         } | ||||
|       } ], | ||||
|       onRollDone: RollDialog.onRollDoneClose, | ||||
|       onClose: () => { | ||||
|         this.tmrApp?.restoreTMRAfterAction(); | ||||
|       } | ||||
|     }); | ||||
|     this.tmrApp?.setTMRPendingAction(dialog); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective' | ||||
|     let addMsg = ""; | ||||
| @@ -1814,11 +1834,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         } | ||||
|         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 | ||||
|           }] | ||||
|           const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel) | ||||
|           await this.updateEmbeddedDocuments('Item', | ||||
|             [{ _id: rollData.selectedSort._id, 'system.lancements': lancements }] | ||||
|           ) | ||||
| @@ -2109,7 +2125,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   /* -------------------------------------------- */ | ||||
|   _getSignesDraconiques(coord) { | ||||
|     const type = TMRUtility.getTMRType(coord); | ||||
|     return this.itemTypes["signedraconique"].filter(it => it.system.typesTMR.includes(type)); | ||||
|     return this.itemTypes[ITEM_TYPES.signedraconique].filter(it => it.system.typesTMR.includes(type)); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -2121,18 +2137,19 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|   async rollLireSigneDraconique(coord) { | ||||
|     if (!this.isHautRevant()) { | ||||
|       ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!"); | ||||
|       return; | ||||
|       return | ||||
|     } | ||||
|     let signes = this._getSignesDraconiques(coord); | ||||
|     let signes = this._getSignesDraconiques(coord) | ||||
|     if (signes.length == 0) { | ||||
|       ui.notifications.info(`Aucun signe draconiques en ${coord} !`); | ||||
|       return; | ||||
|       ui.notifications.info(`Aucun signe draconiques en ${coord} !`) | ||||
|       return | ||||
|     } | ||||
|  | ||||
|     let draconicList = this.getDraconics() | ||||
|       .map(draconic => { | ||||
|         let draconicLecture = foundry.utils.duplicate(draconic); | ||||
|         draconicLecture.system.defaut_carac = "intellect"; | ||||
|         return draconicLecture; | ||||
|         let draconicLecture = foundry.utils.duplicate(draconic) | ||||
|         draconicLecture.system.defaut_carac = "intellect" | ||||
|         return draconicLecture | ||||
|       }); | ||||
|  | ||||
|     const intellect = this.system.carac.intellect; | ||||
| @@ -2406,7 +2423,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     if (this.tmrApp) { | ||||
|       ui.notifications.warn("Vous êtes déja dans les TMR....") | ||||
|       this.tmrApp.forceTMRDisplay() | ||||
|       return | ||||
|       return false | ||||
|     } | ||||
|     if (mode != 'visu' && this.isDemiReve()) { | ||||
|       ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation") | ||||
| @@ -2414,6 +2431,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     } | ||||
|     if (mode == 'visu') { | ||||
|       await this._doDisplayTMR(mode) | ||||
|       return false | ||||
|     } | ||||
|     else { | ||||
|       const rencontre = this.getRencontreTMREnAttente(); | ||||
| @@ -2426,6 +2444,7 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|         buttonLabel: 'Monter dans les TMR', | ||||
|         onAction: async () => await this._doDisplayTMR(mode) | ||||
|       }) | ||||
|       return true | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -2463,6 +2482,29 @@ export class RdDActor extends RdDBaseActorSang { | ||||
|     await this.tmrApp.onDeplacement() | ||||
|   } | ||||
|  | ||||
|   async quitterTMR(message, viewOnly, cumulFatigue) { | ||||
|     if (this.tmrApp) { | ||||
|       this.tmrApp = undefined | ||||
|       const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue"); | ||||
|       await this.santeIncDec( | ||||
|         appliquerFatigue ? "fatigue" : "endurance", | ||||
|         (appliquerFatigue ? 1 : -1) * cumulFatigue) | ||||
|       if (!viewOnly) { | ||||
|         await this.supprimerSignesDraconiques(it => it.system.ephemere && it.system.duree == '1 round', { render: false }) | ||||
|         await this.setEffect(STATUSES.StatusDemiReve, false) | ||||
|         ChatUtility.tellToUserAndGM(message) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async supprimerSignesDraconiques(filter = it => true, options = { render: true }) { | ||||
|     const signes = this.itemTypes[ITEM_TYPES.signedraconique].filter(filter) | ||||
|     if (signes.length > 0) { | ||||
|       this.deleteEmbeddedDocuments("Item", signes.map(item => item.id), options) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async rollSoins(blesse, blessureId) { | ||||
|     const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId); | ||||
|   | ||||
| @@ -246,10 +246,10 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|     if (this.isEffectAllowed(statusId)) { | ||||
|       const effect = this.getEffectByStatus(statusId); | ||||
|       if (!status && effect) { | ||||
|         await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]); | ||||
|         await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id], { render: true}) | ||||
|       } | ||||
|       if (status && !effect) { | ||||
|         await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]); | ||||
|         await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true}) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -387,7 +387,7 @@ export class RdDBaseActorReve extends RdDBaseActor { | ||||
|     if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) { | ||||
|       const rollData = { | ||||
|         ids: { actorId: this.id }, | ||||
|         type: { allowed: [PART_COMP], current: PART_COMP }, | ||||
|         type: { allowed: DEFAULT_ROLL_TYPES, current: PART_COMP }, | ||||
|         selected: { | ||||
|           carac: { key: caracName }, | ||||
|           comp: options.resistance ? { key: undefined, forced: true } : undefined | ||||
|   | ||||
| @@ -116,6 +116,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve { | ||||
|       blessure: blessure | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async santeIncDec(name, inc, isCritique = false) { | ||||
|     if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) { | ||||
| @@ -179,6 +180,26 @@ export class RdDBaseActorSang extends RdDBaseActorReve { | ||||
|     return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques)); | ||||
|   } | ||||
|  | ||||
|   async onCreateItem(item, options, id) { | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.blessure: | ||||
|         await this.changeBleedingState() | ||||
|         break | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async onUpdateItem(item, options, id) { | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.blessure: | ||||
|         await this.changeBleedingState() | ||||
|         break | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async changeBleedingState() { | ||||
|     const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding()) | ||||
|     await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async ajouterBlessure(encaissement, attackerToken = undefined) { | ||||
|   | ||||
| @@ -248,28 +248,12 @@ export class RdDBaseActor extends Actor { | ||||
|   /* -------------------------------------------- */ | ||||
|   async onPreUpdateItem(item, change, options, id) { } | ||||
|  | ||||
|   async onCreateItem(item, options, id) { | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.blessure: | ||||
|         await this.changeBleedingState() | ||||
|         break | ||||
|     } | ||||
|   } | ||||
|   async onCreateItem(item, options, id) { } | ||||
|  | ||||
|   async onUpdateItem(item, options, id) { | ||||
|     switch (item.type) { | ||||
|       case ITEM_TYPES.blessure: | ||||
|         await this.changeBleedingState() | ||||
|         break | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async changeBleedingState() { | ||||
|     const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding()) | ||||
|     await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false) | ||||
|   } | ||||
|   async onUpdateItem(item, options, id) { } | ||||
|  | ||||
|   async onUpdateActor(update, options, actorId) { } | ||||
|  | ||||
|   async onDeleteItem(item, options, id) { | ||||
|     if (item.isInventaire()) { | ||||
|       await this._removeItemFromConteneur(item) | ||||
|   | ||||
| @@ -20,14 +20,15 @@ const PATHS = [ | ||||
| const RANDOM_VALUES = { | ||||
|   'system.sexe': { 'masculin': 1, 'féminin': 1 }, | ||||
|   'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 }, | ||||
|   'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 }, | ||||
|   'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 }, | ||||
|   'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 }, | ||||
|   'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 }, | ||||
| } | ||||
|  | ||||
| export class AppPersonnageAleatoire extends FormApplication { | ||||
|   static preloadHandlebars() { | ||||
|     foundry.applications.handlebars.loadTemplates([ | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs', | ||||
|       'systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs', | ||||
|     ]) | ||||
|   } | ||||
|  | ||||
| @@ -49,14 +50,14 @@ export class AppPersonnageAleatoire extends FormApplication { | ||||
|     this.current = foundry.utils.duplicate(actor) | ||||
|     this.checked = { | ||||
|       'name': false, | ||||
|       'system.sexe': true, | ||||
|       'system.age': true, | ||||
|       'system.taille': true, | ||||
|       'system.poids': true, | ||||
|       'system.main': true, | ||||
|       'system.heure': true, | ||||
|       'system.cheveux': true, | ||||
|       'system.yeux': true | ||||
|       'system.sexe': (this.actor.system.sexe ?? '') == '', | ||||
|       'system.age': this.actor.system.age == 0, | ||||
|       'system.taille': (this.actor.system.taille ?? '') == '', | ||||
|       'system.poids': (this.actor.system.poids ?? '') == '', | ||||
|       'system.main': (this.actor.system.main ?? '') == '', | ||||
|       'system.heure': (this.actor.system.heure ?? '') == '', | ||||
|       'system.cheveux': (this.actor.system.cheveux ?? '') == '', | ||||
|       'system.yeux': (this.actor.system.yeux ?? '') == '', | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -76,6 +77,8 @@ export class AppPersonnageAleatoire extends FormApplication { | ||||
|     this.html.find("button.button-apply").click(async event => await this.onApply()) | ||||
|     this.html.find("input.current-value").change(async event => await this.onChange(event)) | ||||
|     this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event)) | ||||
|     this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin')) | ||||
|     this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin')) | ||||
|     this.html.find("a.random").click(async event => await this.onRandom(event)) | ||||
|     this.html.find("a.reset").click(async event => await this.onReset(event)) | ||||
|     this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected()) | ||||
| @@ -96,6 +99,10 @@ export class AppPersonnageAleatoire extends FormApplication { | ||||
|     const fields = this.html.find(selector).parents("div.random-field:first") | ||||
|     return fields[0].attributes['data-path'].value | ||||
|   } | ||||
|   async onSexe(sexe) { | ||||
|     this.current['system.sexe'] = sexe | ||||
|     this.render() | ||||
|   } | ||||
|  | ||||
|   async onChange(event) { | ||||
|     const path = this.getPath(event.currentTarget) | ||||
| @@ -180,8 +187,9 @@ export class AppPersonnageAleatoire extends FormApplication { | ||||
|     const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2) | ||||
|     const total = await RdDDice.rollTotal(`2d${variation} + ${base}`) | ||||
|     const cm = total % 100 | ||||
|     const dm = cm < 10 ? '0' : '' | ||||
|     const m = (total - cm) / 100 | ||||
|     return `${m}m${cm}` | ||||
|     return `${m}m${dm}${cm}` | ||||
|   } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -106,6 +106,25 @@ export class ChatUtility { | ||||
|     return await ChatMessage.create(messageData) | ||||
|   } | ||||
|  | ||||
|   static tellToUser(message) { | ||||
|     ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] }); | ||||
|   } | ||||
|  | ||||
|   static tellToGM(message) { | ||||
|     ChatMessage.create({ | ||||
|       user: game.user.id, | ||||
|       content: message, | ||||
|       whisper: ChatUtility.getGMs() | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   static tellToUserAndGM(message) { | ||||
|     ChatMessage.create({ | ||||
|       user: game.user.id, | ||||
|       content: message, | ||||
|       whisper: ChatUtility.getUserAndGMs() | ||||
|     }) | ||||
|   } | ||||
|   static getOwners(document) { | ||||
|     return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user] | ||||
|   } | ||||
|   | ||||
| @@ -55,7 +55,7 @@ export const RDD_CONFIG = { | ||||
|   particuliere: { | ||||
|     force: { key: 'force', descr: 'en force', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-force.svg'}, | ||||
|     finesse: { key: 'finesse', descr: 'en finesse', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-finesse.svg'}, | ||||
|     rapidite: { key: 'finesse', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'}, | ||||
|     rapidite: { key: 'rapidite', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'}, | ||||
|   } | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -148,10 +148,17 @@ export class RdDItemSort extends Item { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static incrementBonusCase(actor, sort, coord) { | ||||
|     let bonuscase = RdDItemSort.calculBonuscase(sort, coord) | ||||
|  | ||||
|     actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   static calculBonuscase(sort, coord) { | ||||
|     if (TMRUtility.isFleuve(coord)) { | ||||
|       coord = FLEUVE_COORD; | ||||
|       coord = FLEUVE_COORD | ||||
|     } | ||||
|     let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase); | ||||
|     let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase) | ||||
|     const existing = list.find(it => it.case == coord) | ||||
|     const bonus = Number(existing?.bonus ?? 0) + 1 | ||||
|     if (existing) { | ||||
| @@ -160,11 +167,9 @@ export class RdDItemSort extends Item { | ||||
|     else { | ||||
|       list.push({ case: coord, bonus: 1 }) | ||||
|     } | ||||
|  | ||||
|     actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]); | ||||
|     return RdDItemSort.bonuscasesToString(list) | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static getCaseBonus(sort, coord) { | ||||
|     const search = TMRUtility.isFleuve(coord) | ||||
| @@ -189,4 +194,22 @@ export class RdDItemSort extends Item { | ||||
|       .map(it => it.split(':')) | ||||
|       .map(it => { return { case: it[0], bonus: it[1] } }); | ||||
|   } | ||||
|  | ||||
|   static prepareSortEnReserve(sort, draconic, ptreve, coord) { | ||||
|     return { | ||||
|       type: ITEM_TYPES.sortreserve, | ||||
|       name: sort.name, | ||||
|       img: sort.img, | ||||
|       system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' } | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   static prepareSortAddLancement(sort, reveSort) { | ||||
|     const precedents = sort.system.lancements ?? [] | ||||
|     const lancements = [...precedents, { | ||||
|       timestamp: game.system.rdd.calendrier.getTimestamp(), | ||||
|       reve: reveSort | ||||
|     }] | ||||
|     return lancements | ||||
|   } | ||||
| } | ||||
| @@ -47,7 +47,7 @@ export class RdDBonus { | ||||
|       penetration: RdDBonus._peneration(rollData), | ||||
|       dmgTactique: RdDBonus.dmgBonus(rollData.tactique), | ||||
|       dmgParticuliere: RdDBonus._dmgParticuliere(rollData), | ||||
|       dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used), | ||||
|       dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris?.used), | ||||
|       mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee), | ||||
|       dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme), | ||||
|       dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise) | ||||
|   | ||||
| @@ -15,9 +15,8 @@ import { RdDItemCompetence } from "./item-competence.js"; | ||||
| import { MAP_PHASE, RdDInitiative } from "./initiative.mjs"; | ||||
| import RollDialog from "./roll/roll-dialog.mjs"; | ||||
| import { PART_DEFENSE } from "./roll/roll-part-defense.mjs"; | ||||
| import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs"; | ||||
| import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"; | ||||
| import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; | ||||
| import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"; | ||||
| import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js"; | ||||
| import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; | ||||
| import { RollBasicParts } from "./roll/roll-basic-parts.mjs"; | ||||
|  | ||||
| @@ -380,7 +379,7 @@ export class RdDCombat { | ||||
|     if (defenderToken && Misc.isFirstConnectedGM()) { | ||||
|       const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) | ||||
|       rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme) | ||||
|       if (msg.defenderRoll.ids) {/* TODO: delete roll V1 */ | ||||
|       if (msg.defenderRoll.v2) {/* TODO: delete roll V1 */ | ||||
|         RollDialog.loadRollData(msg.paramChatDefense) | ||||
|         rddCombat?._chatMessageDefenseV2(msg.paramChatDefense) | ||||
|       } else { | ||||
| @@ -561,7 +560,7 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isEchecTotal(rollData) { | ||||
|     if (rollData.ids /* roll V2*/) { | ||||
|     if (rollData.v2 /* roll V2*/) { | ||||
|       // TODO: en cas de demi-surprise à l'attaque, tout échec est un echec total. | ||||
|       // TODO: en cas de demi-surprise en défense, pas de changement à la règle de base | ||||
|       return rollData.rolled.isETotal | ||||
| @@ -575,7 +574,7 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isParticuliere(rollData) { | ||||
|     if (rollData.ids /* roll V2*/) { | ||||
|     if (rollData.v2 /* roll V2*/) { | ||||
|       return rollData.rolled.isPart | ||||
|     } | ||||
|     if (rollData.attackerRoll || !rollData.ajustements.surprise.used) { | ||||
| @@ -586,7 +585,7 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static isReussite(rollData) { | ||||
|     if (rollData.ids /* roll V2*/) { | ||||
|     if (rollData.v2 /* roll V2*/) { | ||||
|       return rollData.rolled.isSuccess | ||||
|     } | ||||
|     if (!rollData.ajustements.surprise.used) { | ||||
| @@ -686,11 +685,7 @@ export class RdDCombat { | ||||
|   async doRollAttaque(rollData, callbacks = []) { | ||||
|     // TODO V2 await this.proposerAjustementTirLancer(rollData) | ||||
|     await RollDialog.create(rollData, { | ||||
|       onRollDone: (dialog) => { | ||||
|         if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) | ||||
|           dialog.close() | ||||
|       }, | ||||
|       customChatMessage: true, | ||||
|       onRollDone: RollDialog.onRollDoneClose, | ||||
|       callbacks: [ | ||||
|         async (roll) => await this.onAttaqueV2(roll), | ||||
|         ...callbacks | ||||
| @@ -892,7 +887,10 @@ export class RdDCombat { | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   isPossession(attackerRoll) { | ||||
|     return attackerRoll.selectedCarac.label.toLowerCase() == 'possession'; | ||||
|     const carac = attackerRoll.v2 | ||||
|       ? attackerRoll.current.carac?.label | ||||
|       : attackerRoll.selectedCarac.label | ||||
|     return carac?.toLowerCase() == 'possession'; | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
| @@ -1067,7 +1065,7 @@ export class RdDCombat { | ||||
|         opponentId: this.attackerId, | ||||
|       }, | ||||
|       type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE }, | ||||
|       attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll), | ||||
|       attackerRoll: attackerRoll, | ||||
|       passeArme: attackerRoll.passeArme, | ||||
|     }) | ||||
|   } | ||||
| @@ -1075,7 +1073,6 @@ export class RdDCombat { | ||||
|   async doRollDefense(rollData, callbacks = []) { | ||||
|     await RollDialog.create(rollData, { | ||||
|       onRollDone: RollDialog.onRollDoneClose, | ||||
|       customChatMessage: true, | ||||
|       callbacks: [ | ||||
|         async (roll) => { | ||||
|           this.removeChatMessageActionsPasseArme(roll.passeArme); | ||||
|   | ||||
| @@ -461,12 +461,7 @@ export class RdDCommands { | ||||
|  | ||||
|   async supprimerSignesDraconiquesEphemeres() { | ||||
|     if (game.user.isGM) { | ||||
|       game.actors.forEach(actor => { | ||||
|         const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere); | ||||
|         if (ephemeres.length > 0) { | ||||
|           actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id)); | ||||
|         } | ||||
|       }); | ||||
|       game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere)) | ||||
|     } | ||||
|     else { | ||||
|       ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe"); | ||||
|   | ||||
| @@ -156,11 +156,16 @@ export class RdDResolutionTable { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static replaceParticuliereDemiSurprise(chances){ | ||||
|     foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'part'), { overwrite: true }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static significativeRequise(chances) { | ||||
|     chances.roll = Math.min(chances.part + 1, chances.sign) | ||||
|     foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true }); | ||||
|   } | ||||
|   }   | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   static succesRequis(chances) { | ||||
|   | ||||
| @@ -25,7 +25,7 @@ export class RdDRollDialogEthylisme extends Dialog { | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     this.html = html; | ||||
|     this.bringToTop(); | ||||
|     this.bringToFront(); | ||||
|  | ||||
|     this.html.find(".force-alcool").change((event) => { | ||||
|       this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value); | ||||
|   | ||||
| @@ -22,7 +22,7 @@ export class RdDRollResolutionTable extends Dialog { | ||||
|       RdDRollResolutionTable.resolutionTable.render(true); | ||||
|     } | ||||
|     else{ | ||||
|       RdDRollResolutionTable.resolutionTable.bringToTop(); | ||||
|       RdDRollResolutionTable.resolutionTable.bringToFront(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -70,7 +70,7 @@ export class RdDRollResolutionTable extends Dialog { | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     this.html = html; | ||||
|     this.bringToTop(); | ||||
|     this.bringToFront(); | ||||
|  | ||||
|  | ||||
|     this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre)); | ||||
|   | ||||
| @@ -128,7 +128,7 @@ export class RdDRoll extends Dialog { | ||||
|   activateListeners(html) { | ||||
|     super.activateListeners(html); | ||||
|     this.html = html; | ||||
|     this.bringToTop(); | ||||
|     this.bringToFront(); | ||||
|  | ||||
|     console.log('RdDRoll.activateListeners', this.rollData); | ||||
|  | ||||
|   | ||||
| @@ -82,7 +82,7 @@ export class RdDTMRDialog extends Dialog { | ||||
|     this.subdialog = undefined | ||||
|     this.displaySize = undefined | ||||
|     if (!this.viewOnly && !game.user.isGM) { | ||||
|       this.$tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")"); | ||||
|       ChatUtility.tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")"); | ||||
|     } | ||||
|     this.callbacksOnAnimate = []; | ||||
|     const displaySize = TMR_DISPLAY_SIZE.clamp(game.settings.get(SYSTEM_RDD, TMR_DISPLAY_SIZE.code) ?? TMR_DISPLAY_SIZE.def); | ||||
| @@ -125,7 +125,11 @@ export class RdDTMRDialog extends Dialog { | ||||
|     HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue")); | ||||
|     HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor())); | ||||
|  | ||||
|     this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop()); | ||||
|     this.html.find('form.tmr-dialog *').click(event => { | ||||
|       if (this.subdialog?.rendered){ | ||||
|         this.subdialog?.bringToFront() | ||||
|       } | ||||
|     }) | ||||
|  | ||||
|     // Roll Sort | ||||
|     this.html.find('.lancer-sort').click(event => this.lancerUnSort()); | ||||
| @@ -169,26 +173,26 @@ export class RdDTMRDialog extends Dialog { | ||||
|  | ||||
|   async forceTMRDisplay() { | ||||
|     if (this.rendered) { | ||||
|       this.bringToTop() | ||||
|       this.bringSubDialogToTop(); | ||||
|       this.bringToFront() | ||||
|       this.bringSubDialogToFront(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bringSubDialogToTop() { | ||||
|     if (this.subdialog?.bringToTop && this.subdialog?.element && this.subdialog?.element[0]) { | ||||
|       this.subdialog.bringToTop(); | ||||
|   bringSubDialogToFront() { | ||||
|     if (this.subdialog?.bringToFront && this.subdialog?.element && this.subdialog?.element[0]) { | ||||
|       this.subdialog.bringToFront(); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async restoreTMRAfterAction() { | ||||
|     this.subdialog = undefined | ||||
|     await this.maximize() | ||||
|     this.bringToTop() | ||||
|     this.bringToFront() | ||||
|   } | ||||
|  | ||||
|   forceTMRContinueAction() { | ||||
|     ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR'); | ||||
|     this.bringSubDialogToTop(); | ||||
|     this.bringSubDialogToFront(); | ||||
|     return false | ||||
|   } | ||||
|  | ||||
| @@ -343,19 +347,8 @@ export class RdDTMRDialog extends Dialog { | ||||
|       this.forceTMRContinueAction() | ||||
|       return false | ||||
|     } | ||||
|     this.descenteTMR = true; | ||||
|     if (this.actor.tmrApp) { | ||||
|       this.actor.tmrApp = undefined // Cleanup reference | ||||
|       const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue") | ||||
|       await this.actor.santeIncDec( | ||||
|         appliquerFatigue ? "fatigue" : "endurance", | ||||
|         (appliquerFatigue ? 1 : -1) * this.cumulFatigue) | ||||
|       if (!this.viewOnly) { | ||||
|         await this.actor.setEffect(STATUSES.StatusDemiReve, false) | ||||
|         this.$tellToUserAndGM(message) | ||||
|       } | ||||
|  | ||||
|     } | ||||
|     this.descenteTMR = true | ||||
|     await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue) | ||||
|     this.pixiTMR.close(); | ||||
|     this.pixiTMR = undefined | ||||
|     await super.close(); | ||||
| @@ -412,7 +405,7 @@ export class RdDTMRDialog extends Dialog { | ||||
|   async $ignorerRencontre() { | ||||
|     if (this.currentRencontre) { | ||||
|       console.log("-> ignorer", this.currentRencontre); | ||||
|       this.$tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name); | ||||
|       ChatUtility.tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name); | ||||
|       await this.$deleteRencontreTMRAtPosition() | ||||
|       this.updateTokens(); | ||||
|       this.$updateValuesDisplay(); | ||||
| @@ -578,29 +571,6 @@ export class RdDTMRDialog extends Dialog { | ||||
|     }, 500); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   _tellToUser(message) { | ||||
|     ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   $tellToGM(message) { | ||||
|     ChatMessage.create({ | ||||
|       user: game.user.id, | ||||
|       content: message, | ||||
|       whisper: ChatUtility.getGMs() | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   $tellToUserAndGM(message) { | ||||
|     ChatMessage.create({ | ||||
|       user: game.user.id, | ||||
|       content: message, | ||||
|       whisper: ChatUtility.getUserAndGMs() | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   /* -------------------------------------------- */ | ||||
|   async manageRencontre(tmr) { | ||||
|     if (this.viewOnly) { | ||||
| @@ -676,14 +646,14 @@ export class RdDTMRDialog extends Dialog { | ||||
|       ? TMRUtility.getTMRType(tmr.coord) + " ??" | ||||
|       : tmr.label + " (" + tmr.coord + ")"); | ||||
|  | ||||
|     this.setTMRPendingAction({ bringToTop: () => { } }) | ||||
|     this.setTMRPendingAction({ bringToFront: () => { } }) | ||||
|     const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); | ||||
|     this.restoreTMRAfterAction() | ||||
|     if (myRoll == 7) { | ||||
|       this._tellToUser(myRoll + ": Rencontre en " + coordTMR); | ||||
|       ChatUtility.tellToUser(myRoll + ": Rencontre en " + coordTMR); | ||||
|       return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre()) | ||||
|     } else { | ||||
|       this._tellToUser(myRoll + ": Pas de rencontre en " + coordTMR); | ||||
|       ChatUtility.tellToUser(myRoll + ": Pas de rencontre en " + coordTMR); | ||||
|       return undefined; | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { ChatUtility } from "../chat-utility.js" | ||||
| import RollDialog from "./roll-dialog.mjs" | ||||
| import RollDialog, { ALL_ROLL_TYPES } from "./roll-dialog.mjs" | ||||
| import { RdDCarac } from "../rdd-carac.js" | ||||
| import { RdDCombat } from "../rdd-combat.js" | ||||
| import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" | ||||
| @@ -8,6 +8,10 @@ import { RDD_CONFIG, renderTemplate } from "../constants.js" | ||||
| import { EMPOIGNADE } from "../item/arme.js" | ||||
| import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js" | ||||
| import { RollTypeCuisine } from "./roll-type-cuisine.mjs" | ||||
| import { RollTypeMeditation } from "./roll-type-meditation.mjs" | ||||
| import { PART_DEFENSE } from "./roll-part-defense.mjs" | ||||
| import { PART_ATTAQUE } from "./roll-part-attaque.mjs" | ||||
| import { RdDRollTables } from "../rdd-rolltables.js" | ||||
|  | ||||
| export default class ChatRollResult { | ||||
|   static init() { | ||||
| @@ -18,8 +22,11 @@ export default class ChatRollResult { | ||||
|  | ||||
|   static onReady() { | ||||
|     foundry.applications.handlebars.loadTemplates({ | ||||
|       'partial-infojet': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-infojet.hbs', | ||||
|       'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs', | ||||
|       'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs', | ||||
|       'partial-choix-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-choix-maladresse.hbs', | ||||
|       'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs', | ||||
|       'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs', | ||||
|       'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs', | ||||
|       'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs', | ||||
| @@ -38,7 +45,7 @@ export default class ChatRollResult { | ||||
|     ) | ||||
|     const save = RollDialog.saveParts(roll, impacts) | ||||
|  | ||||
|     ChatUtility.setMessageData(chatMessage, 'rollData', save) | ||||
|     await this.saveChatMessageRoll(chatMessage, save) | ||||
|     return chatMessage | ||||
|   } | ||||
|  | ||||
| @@ -48,7 +55,7 @@ export default class ChatRollResult { | ||||
|     roll.show.chance = this.isAppelChancePossible(roll) | ||||
|     roll.show.encaissement = this.isShowEncaissement(roll) | ||||
|     roll.show.recul = this.getRecul(roll) | ||||
|     //roll.show.particuliere = roll.show.particuliere ?? [] | ||||
|     roll.show.maladresse = this.getMaladresse(roll) | ||||
|   } | ||||
|  | ||||
|   isAppelChancePossible(roll) { | ||||
| @@ -65,6 +72,23 @@ export default class ChatRollResult { | ||||
|     return false | ||||
|   } | ||||
|  | ||||
|   getMaladresse(roll) { | ||||
|     switch (roll.type.current) { | ||||
|       case ROLL_TYPE_DEFENSE: | ||||
|         if (roll.rolled.isETotal) { | ||||
|           const arme = roll.current[PART_DEFENSE].arme | ||||
|           return arme ? 'avec-arme' : 'sans-arme' | ||||
|         } | ||||
|         break | ||||
|       case ROLL_TYPE_ATTAQUE: | ||||
|         if (roll.rolled.isETotal || (roll.rolled.isEchec && roll.active.surprise == 'demi')) { | ||||
|           const arme = roll.current[PART_ATTAQUE].arme | ||||
|           return arme.system.baseInit > 4 ? 'avec-arme' : 'sans-arme' | ||||
|         } | ||||
|         break | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
|   getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) { | ||||
|     switch (roll.type.current) { | ||||
| @@ -100,7 +124,7 @@ export default class ChatRollResult { | ||||
|   } | ||||
|  | ||||
|   async buildRollHtml(roll) { | ||||
|     const template = `systems/foundryvtt-reve-de-dragon/templates/roll/result/chat-${roll.type.current}.hbs` | ||||
|     const template = ALL_ROLL_TYPES.find(it => it.code == roll.type.current).chatResultTemplate | ||||
|     const html = await renderTemplate(template, roll) | ||||
|     return await RdDTextEditor.enrichHTML(html, undefined, { showLink: false }) | ||||
|   } | ||||
| @@ -112,7 +136,9 @@ export default class ChatRollResult { | ||||
|     $(html).on("click", '.resister-recul', event => this.onClickRecul(event)) | ||||
|     $(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event)) | ||||
|     $(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event)) | ||||
|  | ||||
|     $(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal')) | ||||
|     $(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide')) | ||||
|     $(html).on("click", '.tirer-maladresse', event => this.onClickTirerMaladresse(event)) | ||||
|   } | ||||
|  | ||||
|   getCombat(roll) { | ||||
| @@ -120,15 +146,24 @@ export default class ChatRollResult { | ||||
|       case ROLL_TYPE_DEFENSE: | ||||
|         return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId) | ||||
|       case ROLL_TYPE_ATTAQUE: | ||||
|         return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentId) | ||||
|         return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.actorId, roll.ids.actorTokenId, roll.ids.opponentTokenId) | ||||
|     } | ||||
|     return undefined | ||||
|   } | ||||
|  | ||||
|   async saveChatMessageRoll(chatMessage, savedRoll) { | ||||
|     await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) | ||||
|   } | ||||
|  | ||||
|   loadChatMessageRoll(chatMessage) { | ||||
|     return ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|   } | ||||
|  | ||||
|   async updateChatMessage(chatMessage, savedRoll) { | ||||
|     ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) | ||||
|     await this.saveChatMessageRoll(chatMessage, savedRoll) | ||||
|     const copy = foundry.utils.duplicate(savedRoll) | ||||
|     RollDialog.loadRollData(copy) | ||||
|     savedRoll.dmg = copy.current.attaque?.dmg | ||||
|     this.prepareDisplay(copy) | ||||
|     chatMessage.update({ content: await this.buildRollHtml(copy) }) | ||||
|     chatMessage.render(true) | ||||
| @@ -136,7 +171,7 @@ export default class ChatRollResult { | ||||
|  | ||||
|   onClickAppelChance(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     const actor = game.actors.get(savedRoll.ids.actorId) | ||||
|     actor.rollAppelChance( | ||||
|       () => this.onAppelChanceSuccess(savedRoll, chatMessage), | ||||
| @@ -144,11 +179,13 @@ export default class ChatRollResult { | ||||
|     event.preventDefault() | ||||
|   } | ||||
|  | ||||
|   onAppelChanceSuccess(savedRoll, chatMessage) { | ||||
|   async onAppelChanceSuccess(savedRoll, chatMessage) { | ||||
|     const reRoll = foundry.utils.duplicate(savedRoll) | ||||
|     console.log('onAppelChanceSuccess savedRoll', savedRoll) | ||||
|     reRoll.type.retry = true | ||||
|     await this.updateChatMessage(chatMessage, reRoll) | ||||
|     const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)] | ||||
|  | ||||
|     // TODO: annuler les effets | ||||
|     switch (reRoll.type.current) { | ||||
|       case ROLL_TYPE_DEFENSE: | ||||
| @@ -171,7 +208,7 @@ export default class ChatRollResult { | ||||
|  | ||||
|   onClickAppelDestinee(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     const actor = game.actors.get(savedRoll.ids.actorId) | ||||
|  | ||||
|     actor.appelDestinee(async () => { | ||||
| @@ -184,7 +221,7 @@ export default class ChatRollResult { | ||||
|  | ||||
|   async onClickEncaissement(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     const attaque = savedRoll.attackerRoll | ||||
|     const defender = game.actors.get(savedRoll.ids.actorId) | ||||
|     const attacker = game.actors.get(savedRoll.ids.opponentId) | ||||
| @@ -198,7 +235,7 @@ export default class ChatRollResult { | ||||
|  | ||||
|   async onClickRecul(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     const defender = game.actors.get(savedRoll.ids.actorId) | ||||
|     const attacker = game.actors.get(savedRoll.ids.opponentId) | ||||
|     savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) | ||||
| @@ -209,15 +246,37 @@ export default class ChatRollResult { | ||||
|   async onClickChoixParticuliere(event) { | ||||
|     const choix = event.currentTarget.attributes['data-particuliere'].value | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     savedRoll.particuliere = choix | ||||
|     savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]] | ||||
|     await this.updateChatMessage(chatMessage, savedRoll) | ||||
|     await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks) | ||||
|     await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll) | ||||
|   } | ||||
|  | ||||
|   async onClickFaireGouter(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     if (!savedRoll.type.retry) { | ||||
|       savedRoll.type.retry = true | ||||
|       await this.updateChatMessage(chatMessage, savedRoll) | ||||
|     } | ||||
|     await new RollTypeCuisine().onFaireGouter(savedRoll) | ||||
|   } | ||||
|  | ||||
|   async onClickMonteeTMR(event, mode) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) { | ||||
|       savedRoll.done.meditation = true | ||||
|       await this.updateChatMessage(chatMessage, savedRoll) | ||||
|     } | ||||
|   } | ||||
|   async onClickTirerMaladresse(event) { | ||||
|     const chatMessage = ChatUtility.getChatMessage(event) | ||||
|     const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value | ||||
|     const savedRoll = this.loadChatMessageRoll(chatMessage) | ||||
|     savedRoll.maladresse = await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme', toChat: false }) | ||||
|     savedRoll.type.retry = true | ||||
|     await this.updateChatMessage(chatMessage, savedRoll) | ||||
|   } | ||||
| } | ||||
| @@ -13,7 +13,6 @@ export const ATTAQUE_ROLL_TYPES = [ROLL_TYPE_ATTAQUE] | ||||
| export const COMBAT_ROLL_TYPES = [ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE] | ||||
| export const DEMIREVE_ROLL_TYPES = [ROLL_TYPE_SORT] | ||||
| export const DEFAULT_ROLL_TYPES = [ROLL_TYPE_COMP, ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_CUISINE, ROLL_TYPE_OEUVRE, ROLL_TYPE_JEU] | ||||
| export const ALL_ROLL_TYPES = [...DEFAULT_ROLL_TYPES, ...COMBAT_ROLL_TYPES, ...DEMIREVE_ROLL_TYPES] | ||||
|  | ||||
|  | ||||
| export const DIFF = { | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import { RdDItemArme } from "../item/arme.js"; | ||||
| import { RdDBonus } from "../rdd-bonus.js"; | ||||
| import { ITEM_TYPES, RDD_CONFIG } from "../constants.js"; | ||||
| import { CARACS } from "../rdd-carac.js"; | ||||
| import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"; | ||||
| import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs"; | ||||
| import { PART_ATTAQUE } from "./roll-part-attaque.mjs"; | ||||
|  | ||||
| /* -------------------------------------------- */ | ||||
| @@ -27,7 +27,8 @@ export class RollDialogAdapter { | ||||
|     RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle) | ||||
|     RollDialogAdapter.adjustRollDataForV1(rollData) | ||||
|     RollDialogAdapter.adjustAttaqueParticuliere(rollData) | ||||
|  | ||||
|     RollDialogAdapter.adjustAttaqueDmg(rollData) | ||||
|     RollDialogAdapter.adjustDemiSurprise(rollData) | ||||
|     return rolled | ||||
|   } | ||||
|  | ||||
| @@ -95,16 +96,27 @@ export class RollDialogAdapter { | ||||
|       rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll) | ||||
|       rolled.ajustementNecessaire = rolled.niveauNecessaire - diff | ||||
|     } | ||||
|     rollData.ajustements = rollData.ajustements.map(aj => { | ||||
|       return { | ||||
|         used: true, | ||||
|         label: aj.label, | ||||
|         value: aj.diff, | ||||
|         descr: aj.diff == undefined ? aj.label : undefined | ||||
|       } | ||||
|     }) | ||||
|     rollData.ajustements = rollData.ajustements.map(aj => { return { label: aj.label, value: aj.value } }) | ||||
|   } | ||||
|  | ||||
|   static adjustDemiSurprise(rollData) { | ||||
|     if (rollData.active.surprise == 'demi' && rollData.rolled.isPart) { | ||||
|       RdDResolutionTable.replaceParticuliereDemiSurprise(rollData.rolled) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static adjustAttaqueDmg(rollData) { | ||||
|     switch (rollData.type.current) { | ||||
|       case ROLL_TYPE_ATTAQUE: | ||||
|         rollData.dmg = RdDBonus.dmgRollV2(rollData, rollData.current.attaque) | ||||
|         break | ||||
|       case ROLL_TYPE_DEFENSE: | ||||
|         rollData.dmg = RdDBonus.dmgRollV2(rollData.attackerRoll, rollData.attackerRoll.current.attaque) | ||||
|         break | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   static adjustAttaqueParticuliere(rollData) { | ||||
|     if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) { | ||||
|       return | ||||
|   | ||||
| @@ -48,7 +48,7 @@ import { ActorImpacts } from "../technical/actor-impacts.mjs"; | ||||
|  | ||||
| const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api | ||||
|  | ||||
| const ALL_ROLL_TYPES = [ | ||||
| export const ALL_ROLL_TYPES = [ | ||||
|   new RollTypeComp(), | ||||
|   new RollTypeTache(), | ||||
|   new RollTypeAttaque(), | ||||
| @@ -173,15 +173,16 @@ const ROLL_PARTS = [ | ||||
| /* -------------------------------------------- */ | ||||
| export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2) | ||||
| { | ||||
|   static onRollDoneDoNothing(dialog) { | ||||
|   static onCloseDoNothing() { | ||||
|   } | ||||
|   static onRollDoneDoNothing(dialog, roll) { | ||||
|     dialog.render() | ||||
|   } | ||||
|   static onRollDoneClose(dialog) { | ||||
|     if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) | ||||
|   static onRollDoneClose(dialog, roll) { | ||||
|     if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST)) | ||||
|       dialog.close() | ||||
|   } | ||||
|  | ||||
|  | ||||
|   static init() { | ||||
|   } | ||||
|  | ||||
| @@ -198,7 +199,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|  | ||||
|     ChatRollResult.onReady() | ||||
|  | ||||
|     foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.template)) | ||||
|     foundry.applications.handlebars.loadTemplates(ALL_ROLL_TYPES.map(m => m.chatResultTemplate)) | ||||
|     foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template)) | ||||
|     ROLL_PARTS.forEach(p => p.onReady()) | ||||
|  | ||||
| @@ -236,6 +237,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|   static async create(rollData, rollOptions = {}) { | ||||
|     const rollDialog = new RollDialog(rollData, rollOptions) | ||||
|     rollDialog.render(true) | ||||
|     return rollDialog | ||||
|   } | ||||
|  | ||||
|   static get PARTS() { | ||||
| @@ -314,6 +316,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|   constructor(rollData, rollOptions) { | ||||
|     super() | ||||
|  | ||||
|     this.hooks = [] | ||||
|     this.rollData = RollDialog.$prepareRollData(rollData) | ||||
|     this.rollOptions = { | ||||
|       callbacks: [ | ||||
| @@ -321,13 +324,28 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|         async r => await r.active.actor.appliquerAppelMoral(r), | ||||
|         ...(rollOptions.callbacks ?? []) | ||||
|       ], | ||||
|       customChatMessage: rollOptions.customChatMessage, | ||||
|       onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing | ||||
|       onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing, | ||||
|       onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing | ||||
|     } | ||||
|     this.chatRollResult = new ChatRollResult(); | ||||
|     this.chatRollResult = new ChatRollResult() | ||||
|     this.selectType() | ||||
|     this.registerHooks(rollData); | ||||
|   } | ||||
|  | ||||
|   registerHooks(rollData) { | ||||
|     ROLL_PARTS.filter(p => p.isValid(rollData)) | ||||
|       .forEach(p => p.getHooks(this).forEach(h => { | ||||
|         const hook = h.hook; | ||||
|         const id = Hooks.on(hook, h.fn) | ||||
|         this.hooks.push({ hook, id }) | ||||
|       })) | ||||
|   } | ||||
|  | ||||
|   unregisterHooks() { | ||||
|     this.hooks.forEach(h => Hooks.off(h.hook, h.id)) | ||||
|   } | ||||
|  | ||||
|  | ||||
|   selectType() { | ||||
|     const selectedType = this.getSelectedType(); | ||||
|     this.rollData.type.label = selectedType.title(this.rollData) | ||||
| @@ -383,7 +401,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|     return RollDialog.getActiveParts(rollData) | ||||
|       .map(p => p.getAjustements(rollData)) | ||||
|       .reduce((a, b) => a.concat(b)) | ||||
|       .sort((a, b) => a.diff == undefined ? 1 : b.diff == undefined ? -1 : 0) | ||||
|       .sort((a, b) => a.value == undefined ? 1 : b.value == undefined ? -1 : 0) | ||||
|   } | ||||
|  | ||||
|   async buildHTMLTable(carac, diff) { | ||||
| @@ -405,7 +423,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|  | ||||
|     visibleRollParts.forEach(p => p.prepareContext(rollData)) | ||||
|  | ||||
|     RollDialog.calculAjustements(rollData) | ||||
|     RollDialog.calculAjustement(rollData) | ||||
|  | ||||
|     const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData()) | ||||
|     const context = await super._prepareContext() | ||||
| @@ -427,12 +445,11 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static calculAjustements(rollData) { | ||||
|   static calculAjustement(rollData) { | ||||
|     rollData.ajustements = RollDialog.getAjustements(rollData) | ||||
|     rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined) | ||||
|     rollData.current.totaldiff = rollData.ajustements | ||||
|       .map(adj => adj.diff) | ||||
|       .filter(d => d != undefined) | ||||
|       .filter(a => a.value != undefined) | ||||
|       .map(a => a.value) | ||||
|       .reduce(Misc.sum(), 0) | ||||
|   } | ||||
|  | ||||
| @@ -440,20 +457,25 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|     return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current) | ||||
|   } | ||||
|  | ||||
|   async close(options) { | ||||
|     if (this.rollOptions.onClose) { | ||||
|       this.rollOptions.onClose() | ||||
|     } | ||||
|     this.unregisterHooks() | ||||
|     return await super.close(options) | ||||
|   } | ||||
|  | ||||
|   async roll() { | ||||
|  | ||||
|     const roll = RollDialog.saveParts(this.rollData) | ||||
|     this.loadRollData(roll) | ||||
|     RollDialog.loadRollData(roll) | ||||
|     const selectedRollType = this.getSelectedType(roll); | ||||
|     selectedRollType.onSelect(roll) | ||||
|     roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 | ||||
|     roll.choix = {} | ||||
|     roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll)) | ||||
|  | ||||
|     const impacts = { | ||||
|       active: new ActorImpacts(roll.active), | ||||
|       opponent: roll.opponent ? new ActorImpacts(roll.opponent) : undefined | ||||
|     } | ||||
|     const impacts = new ActorImpacts(roll.active) | ||||
|  | ||||
|     roll.result = selectedRollType.getResult(roll, impacts) | ||||
|  | ||||
| @@ -465,17 +487,17 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2 | ||||
|  | ||||
|     await Promise.all(callbacks.map(async callback => await callback(roll))) | ||||
|  | ||||
|     await impacts.active?.applyImpacts() | ||||
|     await impacts.opponent?.applyImpacts() | ||||
|     await impacts.applyImpacts() | ||||
|     selectedRollType.onApplyImpacts(roll, impacts) | ||||
|     await this.chatRollResult.display(roll, impacts) | ||||
|     this.rollOptions.onRollDone(this) | ||||
|     this.rollOptions.onRollDone(this, roll) | ||||
|   } | ||||
|  | ||||
|   loadRollData(roll) { | ||||
|   static loadRollData(roll) { | ||||
|     RollDialog.$prepareRollData(roll) | ||||
|     RollDialog.calculAjustements(roll) | ||||
|     RollDialog.calculAjustement(roll) | ||||
|     roll.v2 = true | ||||
|     return roll | ||||
|   } | ||||
|  | ||||
|   async defaultCallback(roll, rolled) { | ||||
|   | ||||
| @@ -50,14 +50,6 @@ export class RollPartAttaque extends RollPartSelect { | ||||
|   choices(refs) { return refs.attaques } | ||||
|  | ||||
|   static $extractAttaque(attaque, actor) { | ||||
|     // const extracted = foundry.utils.mergeObject({ | ||||
|     //   key: `${attaque.action}::${attaque.label}`, | ||||
|     //   tactique: TACTIQUES[0] | ||||
|     // }, | ||||
|     //   attaque | ||||
|     // ) | ||||
|     // return extracted | ||||
|     // extracted.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 | ||||
|     attaque.key = `${attaque.action}::${attaque.label}` | ||||
|     attaque.tactique = TACTIQUES[0] | ||||
|     attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0 | ||||
| @@ -71,14 +63,9 @@ export class RollPartAttaque extends RollPartSelect { | ||||
|  | ||||
|   getAjustements(rollData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     const ajustements = [] | ||||
|     if (current.tactique) { | ||||
|       ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) | ||||
|     } | ||||
|     if (rollData.opponent?.surprise) { | ||||
|       ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque }) | ||||
|     } | ||||
|     return ajustements | ||||
|     const tactique = current.tactique ? [{ label: current.tactique.label, value: current.tactique.attaque }] : [] | ||||
|     const surprise = rollData.opponent?.surprise ? [{ label: rollData.opponent.surprise.label, value: rollData.opponent.surprise.attaque }] : [] | ||||
|     return [...tactique, ...surprise] | ||||
|   } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -35,7 +35,7 @@ export class RollPartCheckbox extends RollPart { | ||||
|   getAjustements(rollData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     if (current.checked) { | ||||
|       return [{ label: this.getCheckboxLabelAjustement(rollData), diff: current.value }] | ||||
|       return [{ label: this.getCheckboxLabelAjustement(rollData), value: current.value }] | ||||
|     } | ||||
|     return [] | ||||
|   } | ||||
|   | ||||
| @@ -47,7 +47,7 @@ export class RollPartCoeur extends RollPartSelect { | ||||
|     if (current.key != '') { | ||||
|       return [{ | ||||
|         label: "Coeur pour " + current.label, | ||||
|         diff: current.value | ||||
|         value: current.value | ||||
|       }] | ||||
|     } | ||||
|     return [] | ||||
|   | ||||
| @@ -57,7 +57,7 @@ export class RollPartConditions extends RollPart { | ||||
|   getAjustements(rollData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     if (current.value != 0) { | ||||
|       return [{ label: DESCR_CONDITIONS, diff: current.value }] | ||||
|       return [{ label: DESCR_CONDITIONS, value: current.value }] | ||||
|     } | ||||
|     return [] | ||||
|   } | ||||
|   | ||||
| @@ -1,9 +1,6 @@ | ||||
| import { ITEM_TYPES } from "../constants.js" | ||||
| import { Grammar } from "../grammar.js" | ||||
| import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js" | ||||
| import { RdDBonus } from "../rdd-bonus.js" | ||||
| import { CARACS } from "../rdd-carac.js" | ||||
| import { StatusEffects } from "../settings/status-effects.js" | ||||
| import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" | ||||
| import { PART_CARAC } from "./roll-part-carac.mjs" | ||||
| import { PART_COMP } from "./roll-part-comp.mjs" | ||||
| @@ -113,7 +110,7 @@ export class RollPartDefense extends RollPartSelect { | ||||
|   isArmeDisparate(rollData) { | ||||
|     const armeDefense = this.getCurrent(rollData).arme | ||||
|     if (armeDefense) { | ||||
|       const armeAttaque = rollData.attackerRoll?.arme | ||||
|       const armeAttaque = rollData.attackerRoll?.current.attaque.arme | ||||
|       return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign' | ||||
|     } | ||||
|     return false | ||||
| @@ -126,7 +123,11 @@ export class RollPartDefense extends RollPartSelect { | ||||
|       return { diff: 0, type: DIFF.LIBRE } | ||||
|     } | ||||
|     else { | ||||
|       return { diff: rollData.attackerRoll.diff ?? 0, type: DIFF.DEFENSE } | ||||
|       const attackerRoll = rollData.attackerRoll | ||||
|       const diff = attackerRoll.v2 | ||||
|         ? attackerRoll.selected.diff.value | ||||
|         : attackerRoll.diff | ||||
|       return { diff: diff ?? 0, type: DIFF.DEFENSE } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -66,7 +66,7 @@ export class RollPartDiff extends RollPart { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     return [{ | ||||
|       label: current.label, | ||||
|       diff: current.value | ||||
|       value: current.value | ||||
|     }] | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -81,7 +81,9 @@ export class RollPartJeu extends RollPartSelect { | ||||
|  | ||||
|   $selectJeu(rollData, key) { | ||||
|     this.selectByKey(rollData, key, 0) | ||||
|     RollPartJeu.forceCompJeu(rollData) | ||||
|     if (rollData.type.current == ROLL_TYPE_JEU) { | ||||
|       RollPartJeu.forceCompJeu(rollData) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   static forceCompJeu(rollData) { | ||||
|   | ||||
| @@ -72,9 +72,10 @@ export class RollPartMeditation extends RollPartSelect { | ||||
|   } | ||||
|  | ||||
|   getAjustements(rollData) { | ||||
|     const malusEchecs = { label: "Méditation", diff: this.getMalusEchecs(rollData) } | ||||
|     const malusConditions = { label: "Conditions", diff: this.getMalusConditions(rollData) } | ||||
|     return [malusConditions, ...(malusEchecs.diff == 0 ? [] : [malusEchecs])] | ||||
|     const malus = this.getMalusEchecs(rollData) | ||||
|     const malusEchecs = malusEchecs == 0 ? [] : [{ label: "Méditation", value: malus }] | ||||
|     const malusConditions = { label: "Conditions", value: this.getMalusConditions(rollData) } | ||||
|     return [malusConditions, ...malusEchecs] | ||||
|   } | ||||
|  | ||||
|   $selectMeditation(rollData, key) { | ||||
|   | ||||
| @@ -16,7 +16,7 @@ export class RollPartSelect extends RollPart { | ||||
|   getAjustements(rollData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     if (current) { | ||||
|       return [{ label: current.label, diff: current.value }] | ||||
|       return [{ label: current.label, value: current.value }] | ||||
|     } | ||||
|     return [] | ||||
|   } | ||||
|   | ||||
| @@ -76,8 +76,8 @@ export class RollPartSign extends RollPart { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     if (current.surprise == 'demi') { | ||||
|       return [ | ||||
|         { label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }, | ||||
|         ...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it, diff: undefined } }) | ||||
|         { label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur) }, | ||||
|         ...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it } }) | ||||
|       ] | ||||
|     } | ||||
|     return [] | ||||
|   | ||||
| @@ -22,9 +22,27 @@ export class RollPartSort extends RollPartSelect { | ||||
|   isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } | ||||
|   visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) } | ||||
|  | ||||
|   restore(rollData) { | ||||
|     const saved = this.getSaved(rollData) | ||||
|     this.setCurrent(rollData, { | ||||
|       key: saved.key, | ||||
|       isReserve: saved.isReserve, | ||||
|       ptreve: saved.ptreve | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   store(rollData, targetData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     this.setSaved(targetData, { | ||||
|       key: current.key, | ||||
|       isReserve: current.isReserve, | ||||
|       ptreve: current.ptreve | ||||
|     }) | ||||
|   } | ||||
|  | ||||
|   loadRefs(rollData) { | ||||
|     const refs = this.getRefs(rollData) | ||||
|     const coord = rollData.active.actor.system.reve.tmrpos.coord | ||||
|     const coord = this.getCoord(rollData) | ||||
|     const draconics = rollData.active.actor.getDraconics() | ||||
|     const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort] | ||||
|       .map(s => RollPartSort.$extractSort(s, coord, draconics)) | ||||
| @@ -33,7 +51,7 @@ export class RollPartSort extends RollPartSelect { | ||||
|       { | ||||
|         coord: coord, | ||||
|         tmr: TMRUtility.getTMR(coord), | ||||
|         reve: rollData.active.actor.system.reve.reve.value, | ||||
|         reve: this.getReveActuel(rollData), | ||||
|         draconics: draconics, | ||||
|         all: sorts, | ||||
|         sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord)) | ||||
| @@ -41,10 +59,18 @@ export class RollPartSort extends RollPartSelect { | ||||
|       { inplace: true } | ||||
|     ) | ||||
|     if (refs.sorts.length > 0) { | ||||
|       this.$selectSort(rollData) | ||||
|       this.$selectSort(rollData, this.getSaved(rollData)) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getReveActuel(rollData) { | ||||
|     return rollData.active.actor.system.reve.reve.value | ||||
|   } | ||||
|  | ||||
|   getCoord(rollData) { | ||||
|     return rollData.active.actor.system.reve.tmrpos.coord | ||||
|   } | ||||
|  | ||||
|   choices(refs) { return refs.sorts } | ||||
|  | ||||
|   static $extractSort(sort, coord, draconics) { | ||||
| @@ -56,37 +82,35 @@ export class RollPartSort extends RollPartSelect { | ||||
|       value: isDiffVariable ? -7 : parseInt(sort.system.difficulte), | ||||
|       ptreve: isReveVariable ? 1 : sort.system.ptreve, | ||||
|       caseTMR: RdDItemSort.getCaseTMR(sort), | ||||
|       bonusCase: RdDItemSort.getCaseBonus(sort, coord), | ||||
|       isDiffVariable: isDiffVariable, | ||||
|       isReveVariable: isReveVariable, | ||||
|       isReserve: false, | ||||
|       sort: sort, | ||||
|       draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name) | ||||
|       draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name), | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   getAjustements(rollData) { | ||||
|     const current = this.getCurrent(rollData) | ||||
|     if (current) { | ||||
|       const reserve = current.isReserve ? | ||||
|         [{ label: `Mise en réserve en ${current.coord}` }] : [] | ||||
|       const bonusCase = current.bonusCase ? | ||||
|         [{ label: `Bonus case +${current.bonusCase}%` }] : [] | ||||
|       return [ | ||||
|         { label: current.label, diff: current.value }, | ||||
|         { label: `r${current.ptreve}` }, | ||||
|         ...bonusCase, | ||||
|         ...reserve | ||||
|       ] | ||||
|       const sort = { label: current.label, value: current.value } | ||||
|       const reserve = current.isReserve ? [{ label: `Mise en réserve en ${this.getCoord(rollData)}` }] : [] | ||||
|       const bonusCase = current.bonusCase ? [{ label: `Bonus case +${current.bonusCase}%` }] : [] | ||||
|       const reve = { label: `Rêve ${current.ptreve}` } | ||||
|       return [sort, ...bonusCase, reve, ...reserve] | ||||
|     } | ||||
|     return [] | ||||
|   } | ||||
|  | ||||
|   $selectSort(rollData, key) { | ||||
|     const previous = this.getCurrent(rollData) | ||||
|     const current = this.selectByKey(rollData, key, -7) | ||||
|     if (current.key != previous.key) { } | ||||
|     current.bonusCase = RdDItemSort.getCaseBonus(current.sort, | ||||
|       rollData.active.actor.system.reve.tmrpos.coord) | ||||
|   $selectSort(rollData, values) { | ||||
|     const current = this.selectByKey(rollData, values.key) | ||||
|     if (values.ptreve) { | ||||
|       current.ptreve = values.ptreve | ||||
|     } | ||||
|     if (values.isReserve != undefined) { | ||||
|       current.isReserve = values.isReserve | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async _onRender(rollDialog, context, options) { | ||||
| @@ -99,7 +123,7 @@ export class RollPartSort extends RollPartSelect { | ||||
|     selectSort.addEventListener("change", e => { | ||||
|       const selectOptions = e.currentTarget.options | ||||
|       const index = selectOptions.selectedIndex | ||||
|       this.$selectSort(rollDialog.rollData, selectOptions[index]?.value) | ||||
|       this.$selectSort(rollDialog.rollData, { key: selectOptions[index]?.value }) | ||||
|       rollDialog.render() | ||||
|     }) | ||||
|  | ||||
|   | ||||
| @@ -18,10 +18,12 @@ export class RollPartTache extends RollPartSelect { | ||||
|   loadRefs(rollData) { | ||||
|     const refs = this.getRefs(rollData) | ||||
|     const selected = this.getSelected(rollData) | ||||
|     refs.forced = selected.forced | ||||
|     refs.all = rollData.active.actor.itemTypes[ITEM_TYPES.tache] | ||||
|       .filter(tache => !selected.forced || tache.id == selected.key) | ||||
|       .filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache) | ||||
|       .map(tache => RollPartTache.$extractTache(tache, rollData.active.actor)) | ||||
|  | ||||
|     refs.taches = refs.all | ||||
|     if (refs.taches.length > 0) { | ||||
|       this.$selectTache(rollData) | ||||
| @@ -46,6 +48,8 @@ export class RollPartTache extends RollPartSelect { | ||||
|  | ||||
|   async _onRender(rollDialog, context, options) { | ||||
|     const selectTache = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tache"]`) | ||||
|     const buttonCreate = rollDialog.element.querySelector(`roll-section[name="${this.code}"] button[name="create-tache"]`) | ||||
|     const buttonEdit = rollDialog.element.querySelector(`roll-section[name="${this.code}"] button[name="edit-tache"]`) | ||||
|  | ||||
|     selectTache.addEventListener("change", e => { | ||||
|       const selectOptions = e.currentTarget.options | ||||
| @@ -53,14 +57,43 @@ export class RollPartTache extends RollPartSelect { | ||||
|       this.$selectTache(rollDialog.rollData, selectOptions[index]?.value) | ||||
|       rollDialog.render() | ||||
|     }) | ||||
|  | ||||
|     buttonCreate?.addEventListener( | ||||
|       "click", async e => { | ||||
|         e.preventDefault() | ||||
|         await rollDialog.rollData.active.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache') | ||||
|       }) | ||||
|  | ||||
|     buttonEdit?.addEventListener( | ||||
|       "click", e => { | ||||
|         e.preventDefault() | ||||
|         const current = this.getCurrent(rollDialog.rollData) | ||||
|         current.tache?.sheet.render(true) | ||||
|       }) | ||||
|   } | ||||
|  | ||||
|   getHooks(rollDialog) { | ||||
|     return [ | ||||
|       { hook: "createItem", fn: (item, options, id) => this.onCreateUpdateItem(rollDialog, item, options, id) }, | ||||
|       { hook: "updateItem", fn: (item, options, id) => this.onCreateUpdateItem(rollDialog, item, options, id) } | ||||
|     ] | ||||
|   } | ||||
|  | ||||
|   onCreateUpdateItem(rollDialog, item, options, id) { | ||||
|     if (item.type == ITEM_TYPES.tache && item.parent?.id == rollDialog.rollData.active.actor.id) { | ||||
|       this.loadRefs(rollDialog.rollData) | ||||
|       rollDialog.render() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   impactOtherPart(part, rollData) { | ||||
|     if (this.visible(rollData)) { | ||||
|       const current = this.getCurrent(rollData) | ||||
|       switch (part.code) { | ||||
|         case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) | ||||
|         case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) | ||||
|       if (current.tache) { | ||||
|         switch (part.code) { | ||||
|           case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) | ||||
|           case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return undefined | ||||
|   | ||||
| @@ -15,10 +15,6 @@ export class RollPartTricher extends RollPart { | ||||
|     current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100) | ||||
|   } | ||||
|  | ||||
|   getAjustements(rollData) { | ||||
|     return [] | ||||
|   } | ||||
|  | ||||
|   async _onRender(rollDialog, context, options) { | ||||
|     const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,8 @@ export const ROLLDIALOG_SECTION = { | ||||
|   CONDITIONS: 'conditions', | ||||
|   AJUSTEMENTS: 'ajustements', | ||||
| } | ||||
|  | ||||
|  | ||||
| export class RollPart { | ||||
|   static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` } | ||||
|  | ||||
| @@ -104,10 +106,9 @@ export class RollPart { | ||||
|     return { code: this.code, name: this.name, template: this.template, section: this.section } | ||||
|   } | ||||
|  | ||||
|   getAjustements(rollData) { | ||||
|     return [] | ||||
|   } | ||||
|   getAjustements(rollData) { return [] } | ||||
|  | ||||
|   async _onRender(rollDialog, context, options) { } | ||||
|  | ||||
|   getHooks() { return [] } | ||||
| } | ||||
| @@ -1,5 +1,4 @@ | ||||
| import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs" | ||||
| import { PART_ATTAQUE } from "./roll-part-attaque.mjs" | ||||
| import { RollType } from "./roll-type.mjs" | ||||
|  | ||||
| export class RollTypeAttaque extends RollType { | ||||
|   | ||||
| @@ -32,17 +32,17 @@ export class RollTypeCuisine extends RollType { | ||||
|     if (current.fabriquer) { | ||||
|       const plat = this.$prepareNourriture(rollData.active.name, current, result) | ||||
|       result.messages.push(`${plat.system.quantite} ${plat.name} ont été préparés dans l'équipement`) | ||||
|       impacts.active.addCreatedItem(plat) | ||||
|       impacts.addCreated('Item', plat) | ||||
|       result.plat = { id: plat.id } | ||||
|     } | ||||
|     if (current.ingredient) { | ||||
|       const quantite = Math.min(current.proportions, current.ingredient.system.quantite) | ||||
|       if (quantite == current.ingredient.system.quantite) { | ||||
|         impacts.active.addDeletedItem(current.ingredient) | ||||
|         impacts.addDeleted('Item', current.ingredient) | ||||
|         result.messages.push(`Il n'y a plus de ${ingredient.name}`) | ||||
|       } | ||||
|       else { | ||||
|         impacts.active.addItemDelta(current.ingredient, 'system.quantite', -current.proportions) | ||||
|         impacts.addDelta('Item', current.ingredient, 'system.quantite', -current.proportions) | ||||
|         result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`) | ||||
|       } | ||||
|     } | ||||
| @@ -51,7 +51,7 @@ export class RollTypeCuisine extends RollType { | ||||
|   onApplyImpacts(roll, impacts) { | ||||
|     if (roll.result.plat)  { | ||||
|       // le plat n'est pas créé immédiatement, il faut donc retrouver l'id | ||||
|       roll.result.plat.id = impacts.active.itemCreates.find(it => it.id = roll.result.plat.id)?.createdId | ||||
|       roll.result.plat.id = impacts.findCreatedId('Item', roll.result.plat.id) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| import { RdDItemSigneDraconique } from "../item/signedraconique.js" | ||||
| import { RollBasicParts } from "./roll-basic-parts.mjs" | ||||
| import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs" | ||||
| import { PART_MEDITATION } from "./roll-part-meditation.mjs" | ||||
| import { RollType } from "./roll-type.mjs" | ||||
| @@ -26,7 +27,7 @@ export class RollTypeMeditation extends RollType { | ||||
|     const rolled = rollData.rolled | ||||
|     if (meditation && rolled) { | ||||
|       if (rolled.isSuccess) { | ||||
|         await actor.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)]) | ||||
|         await actor.createEmbeddedDocuments('Item', [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)]) | ||||
|       } | ||||
|       if (rolled.isEPart) { | ||||
|         await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }]) | ||||
| @@ -34,4 +35,9 @@ export class RollTypeMeditation extends RollType { | ||||
|       await actor.santeIncDec("fatigue", 2) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   async onMonteeTMR(savedRoll, mode){ | ||||
|     const actor = RollBasicParts.getTokenActor(savedRoll).actor | ||||
|     return actor?.displayTMR(mode) | ||||
|   } | ||||
| } | ||||
| @@ -1,4 +1,9 @@ | ||||
| import { RdDItemCompetence } from "../item-competence.js" | ||||
| import { RdDItemSort } from "../item-sort.js" | ||||
| import { RdDResolutionTable } from "../rdd-resolution-table.js" | ||||
| import { DIFF, ROLL_TYPE_SORT } from "./roll-constants.mjs" | ||||
| import { PART_COMP } from "./roll-part-comp.mjs" | ||||
| import { PART_SORT } from "./roll-part-sort.mjs" | ||||
| import { RollType } from "./roll-type.mjs" | ||||
|  | ||||
| export class RollTypeSort extends RollType { | ||||
| @@ -11,4 +16,69 @@ export class RollTypeSort extends RollType { | ||||
|   onSelect(rollData) { | ||||
|     this.setDiffType(rollData, DIFF.AUCUN) | ||||
|   } | ||||
|  | ||||
|   getResult(rollData, impacts) { | ||||
|     const rolled = rollData.rolled | ||||
|     const actor = rollData.active.actor | ||||
|     const coord = actor.system.reve.tmrpos.coord | ||||
|     const reveActuel = parseInt(actor.system.reve.reve.value) | ||||
|     const draconic = rollData.current[PART_COMP].comp | ||||
|  | ||||
|     const current = rollData.current[PART_SORT] | ||||
|     const sort = current.sort | ||||
|     const isReserve = current.isReserve | ||||
|     const reveSort = current.ptreve | ||||
|     const isThanatos = RdDItemCompetence.isThanatos(draconic) | ||||
|  | ||||
|     actor.tmrApp?.restoreTMRAfterAction() | ||||
|  | ||||
|     current.depenseReve = reveSort | ||||
|     if (isThanatos) { // Si Thanatos | ||||
|       impacts.addActorUpdate("system.reve.reve.thanatosused", true) | ||||
|     } | ||||
|  | ||||
|     if (rolled.isSuccess) { // Réussite du sort ! | ||||
|       if (rolled.isPart) { | ||||
|         current.depenseReve = Math.max(Math.floor(current.depenseReve / 2), 1) | ||||
|       } | ||||
|       if (isReserve) { | ||||
|         current.depenseReve++ | ||||
|       } | ||||
|  | ||||
|       if (reveActuel > current.depenseReve) { | ||||
|         // Incrémenter/gére le bonus de case | ||||
|         impacts.addUpdate('Item', sort, 'system.bonuscase', RdDItemSort.calculBonuscase(sort, coord)) | ||||
|  | ||||
|         if (isReserve) { | ||||
|           impacts.addCreated('Item', RdDItemSort.prepareSortEnReserve(sort, draconic, reveSort, coord)) | ||||
|         } | ||||
|         else { | ||||
|           rollData.closeTMR = true | ||||
|           if (sort.system.isrituel) { | ||||
|             impacts.addUpdate('Item', sort, 'system.lancements', RdDItemSort.prepareSortAddLancement(sort, reveSort)) | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|       else { | ||||
|         current.depenseReve = 0; | ||||
|         rollData.show.reveInsuffisant = true | ||||
|         foundry.utils.mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), { overwrite: true }) | ||||
|       } | ||||
|     } else { | ||||
|       rollData.closeTMR = true | ||||
|       if (rolled.isETotal) { // Echec total ! | ||||
|         current.depenseReve = Math.min(reveActuel, Math.floor(current.depenseReve * 1.5)) | ||||
|         // TODO: mise en réserve d'un échec total... | ||||
|       } else { | ||||
|         current.depenseReve = 0 | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     impacts.addActorDelta("system.reve.reve.value", - Math.min(current.depenseReve, reveActuel)) | ||||
|      | ||||
|     if (current.depenseReve >= reveActuel) { // 0 points de reve | ||||
|       rollData.show.zeroReve = true | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -12,7 +12,7 @@ export class RollTypeTache extends RollType { | ||||
|   title(rollData) { | ||||
|     const current = rollData.current[PART_TACHE] | ||||
|     const tache = current?.tache | ||||
|     return `travaille à sa tâche: ${tache.name ?? ''}` | ||||
|     return tache ? `travaille à sa tâche: ${tache.name}` : `n'a pas de tâches à travailler` | ||||
|   } | ||||
|  | ||||
|   onSelect(rollData) { | ||||
|   | ||||
| @@ -1,15 +1,25 @@ | ||||
|  | ||||
| const ACTOR_EMBEDDED_DOCTYPES = ['Item', 'ActiveEffect'] | ||||
| /** | ||||
|  * class designed to store actor modification instructions, to apply them in a single operation, and have the ability to revert these | ||||
|  */ | ||||
| export class ActorImpacts { | ||||
|   static $newDocumentImpacts(docType) { | ||||
|     return { creates: [], deletes: [], updates: [], docType: docType } | ||||
|   } | ||||
|   static $checkDocType(docType) { | ||||
|     if (!ACTOR_EMBEDDED_DOCTYPES.includes(docType)) { | ||||
|       throw `Unsupported document type ${docType}` | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   constructor(actorToken) { | ||||
|     this.actorToken = actorToken | ||||
|     this.updates = [] | ||||
|     this.deltas = [] | ||||
|     this.itemCreates = [] | ||||
|     this.itemUpdates = [] | ||||
|     this.itemDeletes = [] | ||||
|     ACTOR_EMBEDDED_DOCTYPES.forEach( | ||||
|       docType => this[docType] = ActorImpacts.$newDocumentImpacts(docType) | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   addActorUpdate(path, value) { | ||||
| @@ -27,46 +37,55 @@ export class ActorImpacts { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   addDeletedItem(item) { | ||||
|     this.itemDeletes.push(item) | ||||
|   } | ||||
|   addCreatedItem(item) { | ||||
|     this.itemCreates.push(item) | ||||
|   addDeleted(docType, document) { | ||||
|     ActorImpacts.$checkDocType(docType) | ||||
|     this[docType].deletes.push(document) | ||||
|   } | ||||
|  | ||||
|   addItemUpdate(item, path, value) { | ||||
|     const existing = this.itemUpdates.find(it => it.id == item.id) | ||||
|   addCreated(docType, document) { | ||||
|     ActorImpacts.$checkDocType(docType) | ||||
|     this[docType].creates.push(document) | ||||
|   } | ||||
|  | ||||
|   addUpdate(docType, document, path, value) { | ||||
|     ActorImpacts.$checkDocType(docType) | ||||
|     const update = [path, value] | ||||
|     const existing = this[docType].updates.find(it => it.id == document.id) | ||||
|     if (existing) { | ||||
|       existing.updates.push(update) | ||||
|     } | ||||
|     else { | ||||
|       this.itemUpdates.push({ id: item.id, updates: [update], deltas: [] }) | ||||
|       this[docType].updates.push({ id: document.id, updates: [update], deltas: [] }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   addItemDelta(item, path, value) { | ||||
|   addDelta(document, path, value) { | ||||
|     ActorImpacts.$checkDocType(document) | ||||
|     const intValue = Number.parseInt(value) | ||||
|     if (Number.isInteger(intValue) && intValue != 0) { | ||||
|       const delta = [path, intValue] | ||||
|       const existing = this.itemUpdates.find(it => it.id == item.id) | ||||
|       const existing = this[docType].updates.find(it => it.id == document.id) | ||||
|       if (existing) { | ||||
|         existing.deltas.push(delta) | ||||
|       } | ||||
|       else { | ||||
|         this.itemUpdates.push({ id: item.id, updates: [], deltas: [delta] }) | ||||
|         this[docType].updates.push({ id: document.id, updates: [], deltas: [delta] }) | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|       console.error('Cannot use non integer value {} for delta update', value) | ||||
|       console.error('Cannot use non-integer value {} for delta update', value) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   reverseImpacts() { | ||||
|     const reverse = ActorImpacts.$computeReverts(new ActorImpacts(this.actorToken), this, __ => this.actorToken.actor) | ||||
|     reverse.itemCreates = this.itemDeletes.map(it => foundry.utils.duplicate(it)) | ||||
|     reverse.itemDeletes = this.itemCreates.map(it => { return { id: it.id } }) | ||||
|     reverse.itemUpdates = this.itemUpdates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getActorItem(id))) | ||||
|     ACTOR_EMBEDDED_DOCTYPES.forEach( | ||||
|       docType => { | ||||
|         reverse[docType].creates = this[docType].deletes.map(it => foundry.utils.duplicate(it)) | ||||
|         reverse[docType].deletes = this[docType].creates.map(it => { return { id: it.id } }) | ||||
|         reverse[docType].updates = this[docType].updates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getEmbeddedDocument(docType, id))) | ||||
|       } | ||||
|     ) | ||||
|     return reverse | ||||
|   } | ||||
|  | ||||
| @@ -77,40 +96,44 @@ export class ActorImpacts { | ||||
|  | ||||
|   async applyImpacts() { | ||||
|     const actor = this.actorToken.actor | ||||
|     const isItemsDelete = this.itemDeletes.length > 0 | ||||
|     const isItemsCreate = this.itemCreates.length > 0 | ||||
|     const isItemsUpdate = this.itemUpdates.length > 0 | ||||
|     const isActorUpdate = this.updates.length > 0 || this.deltas.length > 0 | ||||
|     await Promise.all(ACTOR_EMBEDDED_DOCTYPES.map(async docType => await this.$applyDocumentsImpacts(actor, docType))) | ||||
|     const updates = ActorImpacts.$computeUpdates(this, id => actor) | ||||
|     await actor.update(updates, { render: true }) | ||||
|   } | ||||
|  | ||||
|     if (isItemsDelete) { | ||||
|       const deletes = this.itemDeletes.map(it => it.id) | ||||
|       await actor.deleteEmbeddedDocuments('Item', deletes, { render: !(isItemsCreate || isItemsUpdate || isActorUpdate) }) | ||||
|  | ||||
|   async $applyDocumentsImpacts(actor, docType) { | ||||
|     if (this[docType].deletes.length > 0) { | ||||
|       const deletes = this[docType].deletes.map(it => it.id) | ||||
|       await actor.deleteEmbeddedDocuments(docType, deletes, { render: false }) | ||||
|     } | ||||
|  | ||||
|     if (isItemsCreate) { | ||||
|       const creates = this.itemCreates | ||||
|       const created = await actor.createEmbeddedDocuments('Item', creates, { render: !(isItemsUpdate || isActorUpdate)}) | ||||
|       for (let i=0; i<creates.length; i++){ | ||||
|     if (this[docType].creates.length > 0) { | ||||
|       const creates = this[docType].creates | ||||
|       const created = await actor.createEmbeddedDocuments(docType, creates, { render: false }) | ||||
|       for (let i = 0; i < creates.length; i++) { | ||||
|         creates[i].createdId = created[i].id | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (isItemsUpdate) { | ||||
|       const updates = this.itemUpdates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getActorItem(id))) | ||||
|       await actor.updateEmbeddedDocuments('Item', updates, { render: !isActorUpdate }) | ||||
|     } | ||||
|  | ||||
|     if (isActorUpdate) { | ||||
|       const updates = ActorImpacts.$computeUpdates(this, id => actor) | ||||
|       await actor.update(updates, { render: true }) | ||||
|     if (this[docType].updates.length > 0) { | ||||
|       const updates = this[docType].updates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getEmbeddedDocument(docType, id))) | ||||
|       await actor.updateEmbeddedDocuments(docType, updates, { render: false }) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   $getActorItem(id) { | ||||
|     return this.actorToken.actor.items.get(id) | ||||
|   findCreatedId(docType, origId){ | ||||
|      return this[docType].creates.find(it => it.id = origId)?.createdId | ||||
|   } | ||||
|  | ||||
|   $getEmbeddedDocument(docType, id) { | ||||
|     return this.actorToken.actor.getEmbeddedDocument(docType, id) | ||||
|   } | ||||
|  | ||||
|   static $computeUpdates(u, getSource) { | ||||
|     if (u.updates.length == 0 && u.deltas.length == 0) { | ||||
|       return {} | ||||
|     } | ||||
|     const source = getSource(u.id) | ||||
|     const instruction = { _id: u.id } | ||||
|     u.updates.forEach(u => instruction[u[0]] = u[1]) | ||||
| @@ -124,5 +147,4 @@ export class ActorImpacts { | ||||
|     target.deltas = u.deltas.map(d => [d[0], -d[1]]) | ||||
|     return target | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,12 +1,12 @@ | ||||
| <form class="app-personnage-aleatoire"> | ||||
|   <h2>Génération aléatoire pour {{actor.name}}</h2> | ||||
|   <h2>{{actor.name}}</h2> | ||||
|   <div class="flex-group-left"> | ||||
|     {{#if options.isGM}} | ||||
|     {{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs" | ||||
|       label="Nom" path="name" type="text" value=current.name checked=checked.name | ||||
|     }} | ||||
|     {{/if}} | ||||
|     {{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs" | ||||
|     {{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs" | ||||
|       label="Sexe" path="system.sexe" type="text" | ||||
|       value=current.system.sexe checked=checked.system.sexe | ||||
|     }} | ||||
|   | ||||
| @@ -12,8 +12,8 @@ | ||||
|   <input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/> | ||||
|   {{/if}} | ||||
|   <div class="item-controls"> | ||||
|     <input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/> | ||||
|     <a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a> | ||||
|     <a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a> | ||||
|     <input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/> | ||||
|   </div> | ||||
| </div> | ||||
							
								
								
									
										11
									
								
								templates/actor/random/sexe-aleatoire.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/actor/random/sexe-aleatoire.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <div class="flexrow random-field" data-path="{{path}}"> | ||||
|   <label for="{{path}}">{{label}}:</label> | ||||
|   <input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/> | ||||
|   <div class="item-controls"> | ||||
|     <input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/> | ||||
|     <a data-action="sexe-feminin" data-tooltip="sexe féminin"><i class="fa-solid fa-venus"></i></a> | ||||
|     <a data-action="sexe-masculin" data-tooltip="sexe masculin"><i class="fa-solid fa-mars"></i></a> | ||||
|     <a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a> | ||||
|     <a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a> | ||||
|   </div> | ||||
| </div> | ||||
| @@ -1,4 +1,3 @@ | ||||
| {{log rolled}} | ||||
| <div> | ||||
|   <span {{#if ajustements}}class="tooltip-overflow tooltip-dotted" {{/if}}> | ||||
|     <span> | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|  | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
| @@ -19,18 +19,13 @@ | ||||
|     {{#if rolled.isSuccess}} | ||||
|       <span> | ||||
|         <strong>{{opponent.name}}</strong> doit se défendre à <strong>{{current.diff.value}}</strong>, | ||||
|         {{#if (eq current.dmg.mortalite 'empoignade')}} | ||||
|         {{#if (eq dmg.mortalite 'empoignade')}} | ||||
|         ou {{active.name}} marquera un point d'empoignade | ||||
|         {{else if (eq current.dmg.mortalite 'non-mortel')}} | ||||
|         ou encaisser à <span class="rdd-roll-norm">{{plusMoins current.dmg.total}} (non-mortel)</span> | ||||
|         {{else if (eq dmg.mortalite 'non-mortel')}} | ||||
|         ou encaisser à <span class="rdd-roll-norm">{{plusMoins dmg.total}} (non-mortel)</span> | ||||
|         {{else}} | ||||
|         {{!-- {{~#if (eq current.dmg.mortalite 'mortel')}} --}} | ||||
|         ou encaisser à <span class="rdd-roll-echec">{{plusMoins current.dmg.total}}</span> | ||||
|         {{!-- {{~#if (eq current.dmg.mortalite 'cauchemar')}} --}} | ||||
|         {{!-- {{else}} | ||||
|         <span class="rdd-roll-etotal">{{plusMoins dmg.total}}</span> (entités de cauchemar) --}} | ||||
|         ou encaisser à <span class="rdd-roll-echec">{{plusMoins dmg.total}}</span> | ||||
|         {{/if}} | ||||
|          | ||||
|       </span> | ||||
|       {{#if show.recul}} | ||||
|         <span class='chat-card-info'> | ||||
| @@ -61,9 +56,11 @@ | ||||
|     <p> | ||||
|     {{> "systems/foundryvtt-reve-de-dragon/templates/chat-info-appel-au-moral.hbs"}} | ||||
|     </p> | ||||
|     {{> 'partial-maladresse'}} | ||||
|   </div> | ||||
|    | ||||
|  | ||||
|   <div class="chat-actions"> | ||||
|     {{> 'partial-choix-maladresse'}} | ||||
|     {{> 'partial-attaque-particuliere'}} | ||||
|     {{!-- TODO: maladresses --}} | ||||
|   </div> | ||||
|   | ||||
| @@ -4,16 +4,16 @@ | ||||
|     <img src="{{current.comp.comp.img}}" data-tooltip="{{current.comp.label}}" /> | ||||
|   </div> | ||||
|   <div class="chat-header"> | ||||
|     {{active.name}} fait un jet de {{current.comp.label}} | ||||
|     {{active.name}} fait un jet {{#if (eq current.comp.key '')}}sans compétence{{else}}de {{current.comp.label}}{{/if}} | ||||
|   </div> | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     {{current.carac.label}}{{#unless (eq current.comp.key '')}} / {{current.comp.label}}{{/unless}} à {{current.diff.value}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
|     <p>Qualité {{rolled.ptQualite}}, points de tâche {{rolled.ptQualite}} | ||||
|     <p>Qualité {{rolled.ptQualite}}, points de tâche {{rolled.ptTache}} | ||||
|     </p> | ||||
|     {{> 'partial-info-appel-moral'}} | ||||
|   </div> | ||||
|   | ||||
| @@ -14,19 +14,19 @@ | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> "partial-infojet"}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
|     <p> | ||||
|     {{active.name}} | ||||
|     {{#if rolled.isSuccess}} | ||||
|       réussit la recette, pour un plat de qualité {{result.qualite~}} | ||||
|       {{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if~}} | ||||
|       réussit la recette, pour un plat de qualité {{result.qualite}} | ||||
|       {{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if}} | ||||
|     {{else}} | ||||
|       fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite~}} | ||||
|       {{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if~}} | ||||
|     {{/if~}}. | ||||
|       fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite}} | ||||
|       {{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if}} | ||||
|     {{~/if~}}. | ||||
|     {{#if (lt result.exotisme 0)}} | ||||
|     <br>Au vu de l'exotisme du plat, les convives devront réussir un jet de @roll[Volonté/Cuisine/{{result.exotisme}}]. | ||||
|     En cas d'échec, ils peuvent se forcer à faire plaisir à {{active.name}}, mais devront faire un jet de moral Malheureux. | ||||
|   | ||||
| @@ -11,7 +11,7 @@ | ||||
|  | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
| @@ -42,9 +42,11 @@ | ||||
|       </span> | ||||
|     {{/if}} | ||||
|     {{> 'partial-info-appel-moral'}} | ||||
|     {{> 'partial-maladresse'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-actions"> | ||||
|     {{!-- TODO: maladresses --}} | ||||
|     {{> 'partial-choix-maladresse'}} | ||||
|     {{> 'partial-recul-choc'}} | ||||
|     {{> 'partial-encaissement'}} | ||||
|   </div> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
| @@ -39,6 +39,19 @@ | ||||
|     {{/if}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-actions"> | ||||
|     {{#if rolled.isSuccess}} | ||||
|       {{#unless done.meditation}} | ||||
|       <a class='chat-card-button monter-tmr-normale' data-tooltip="Montée rapide dans les TMR" > | ||||
|         <img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/> Montée normale dans les TMR | ||||
|       </a> | ||||
|       <a class='chat-card-button monter-tmr-rapide' data-tooltip="Montée rapide dans les TMR" > | ||||
|         <img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/> Montée rapide dans les TMR | ||||
|       </a> | ||||
|       {{/unless}} | ||||
|     {{/if}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-buttons"> | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
| @@ -9,7 +9,7 @@ | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
|   | ||||
| @@ -0,0 +1,47 @@ | ||||
| <div class="roll-chat"> | ||||
|   <div class="chat-img"> | ||||
|     <img src="{{active.img}}" data-tooltip="{{active.name}}" /> | ||||
|     <img src="{{current.sort.sort.img}}" data-tooltip="{{current.sort.label}}" /> | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-header"> | ||||
|     {{active.name}} | ||||
|     {{#if current.sort.isReserve}}met en réserve{{else}}lance{{/if}} | ||||
|     le {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}} | ||||
|     {{current.sort.label}} | ||||
|     {{#if (ne current.sort.sort.system.draconic current.comp.comp.name)}} | ||||
|     avec la voie de {{current.comp.comp.name}} | ||||
|     {{/if}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <hr> | ||||
|   <div class="chat-details"> | ||||
|     <p> | ||||
|     {{#if rolled.isETotal}}Echec TOTAL | ||||
|     {{else if rolled.isEchec}}Echec | ||||
|     {{else}}Réussite{{/if}} | ||||
|     du {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}}, | ||||
|     {{#if rolled.isSuccess}} | ||||
|     le sort est {{#if current.sort.isReserve}}mis en réserve{{else}}lancé{{/if}} | ||||
|     avec {{current.sort.ptreve}} point{{~#if (gt current.sort.ptreve 1)}}s{{/if}} de rêve en {{caseTmr-label refs.sort.coord}} ({{refs.sort.coord}}). | ||||
|     {{/if}} | ||||
|     </p> | ||||
|     <p> | ||||
|     {{#if (eq current.sort.depenseReve 0)}}Pas de dépense de rêve | ||||
|     {{else if (eq current.sort.depenseReve 1)}}1 point de rêve a été dépensé | ||||
|     {{else}}{{current.sort.depenseReve}} points de rêve ont été dépensés | ||||
|     {{~/if}}. | ||||
|     {{#if show.reveInsuffisant}}Pas assez de rêve!{{/if}} | ||||
|     </p> | ||||
|  | ||||
|     {{> "systems/foundryvtt-reve-de-dragon/templates/chat-description.hbs" current.sort.sort.system}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-buttons"> | ||||
|   </div> | ||||
| </div> | ||||
| @@ -9,7 +9,7 @@ | ||||
|    | ||||
|   <div class="chat-resume"> | ||||
|     {{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}} | ||||
|     <br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}} | ||||
|     <br>{{> 'partial-infojet'}} | ||||
|   </div> | ||||
|  | ||||
|   <div class="chat-details"> | ||||
|   | ||||
							
								
								
									
										9
									
								
								templates/roll/result/partial-choix-maladresse.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/roll/result/partial-choix-maladresse.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| {{#if show.maladresse}} | ||||
|   {{#unless maladresse}} | ||||
|   <a class='chat-card-button tirer-maladresse' data-maladresse='{{show.maladresse}}' | ||||
|     data-tooltip="Tirer la maladresse"> | ||||
|     <img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Tirer une maladresse | ||||
|     {{#if (eq show.maladresse 'avec-arme')}}armé{{else}}non armé{{/if}} | ||||
|   </a> | ||||
|   {{/unless}} | ||||
| {{/if}} | ||||
							
								
								
									
										26
									
								
								templates/roll/result/partial-infojet.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								templates/roll/result/partial-infojet.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| {{#if ajustements}} | ||||
| <div> | ||||
|   <span class="tooltip-overflow tooltip-dotted" > | ||||
|     <span> | ||||
|       <span>{{rolled.caracValue}} à {{plusMoins rolled.finalLevel}}</span> | ||||
|       <span>= {{rolled.score}}%</span> | ||||
|       {{#if (and rolled.factorHtml (ne rolled.factorHtml 1))}} | ||||
|         <span class="rdd-diviseur">×{{{rolled.factorHtml}}}</span> | ||||
|       {{/if}} | ||||
|     </span> | ||||
|     <div class="tooltiptext ttt-ajustements"> | ||||
|       {{#each ajustements as |item key|}} | ||||
|       <div class="{{#if item.strong}}strong-text{{/if}}"> | ||||
|         {{{item.label}}}{{#if item.value includeZero=true}}: {{plusMoins item.value}}{{/if}} | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </span> | ||||
| </div> | ||||
| {{/if}} | ||||
| <div> | ||||
|   <span>{{rolled.roll}} : </span><span class="rdd-roll-{{rolled.code}} strong-text">{{rolled.quality}}</span> | ||||
|   {{#if rolled.ajustementNecessaire}} | ||||
|   <span class="rdd-niveau-requis">(Réussite si {{plusMoins rolled.niveauNecessaire}} / avec niveau {{plusMoins rolled.ajustementNecessaire}}) </span> | ||||
|   {{/if}} | ||||
| </div> | ||||
							
								
								
									
										6
									
								
								templates/roll/result/partial-maladresse.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								templates/roll/result/partial-maladresse.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| {{#if maladresse}} | ||||
| <span class='chat-card-info'> | ||||
|   <img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Maladresse! | ||||
| </span> | ||||
| <div >{{{maladresse}}}</div> | ||||
| {{/if}} | ||||
| @@ -2,21 +2,16 @@ | ||||
|   <span class="tooltip tooltip-dotted"> | ||||
|     <span class="roll-part-resolution">Jet: {{rollData.current.carac.value}} à {{plusMoins rollData.current.totaldiff}}</span> | ||||
|     <div class="tooltiptext ttt-ajustements"> | ||||
|       {{#each rollData.ajustements as |ajust|}} | ||||
|       {{#if ajust}} | ||||
|       {{#each rollData.ajustements as |item|}} | ||||
|       <div> | ||||
|         {{#if ajust.descr}} | ||||
|         {{{ajust.descr}}} | ||||
|         {{else}} | ||||
|         {{{ajust.label}}}{{#if ajust.isDiff}}: {{plusMoins ajust.diff}}{{/if}} | ||||
|         {{/if}} | ||||
|         {{{item.label}}}{{#if item.value includeZero=true}}: {{plusMoins item.value}}{{/if}} | ||||
|       </div> | ||||
|       {{/if}} | ||||
|       {{/each}}  | ||||
|     </div> | ||||
|   </span> | ||||
|   {{#if rollData.current.significative.used}} | ||||
|   <br><span> | ||||
|   <br> | ||||
|   <span> | ||||
|     Significative requise <span class="rdd-diviseur">×{{{rollData.current.significative.label}}}</span>! | ||||
|   </span> | ||||
|   {{/if}} | ||||
|   | ||||
| @@ -7,7 +7,14 @@ | ||||
|       {{selectOptions refs.taches selected=current.key valueAttr="key" labelAttr="label"}} | ||||
|     </select> | ||||
|     <selected-numeric-value>{{plusMoins current.value}}</selected-numeric-value> | ||||
|     {{#unless refs.forced}} | ||||
|     <button name="create-tache" data-tooltip="Créer une nouvelle tâche"><i class="fa-solid fa-circle-plus"></i></button> | ||||
|     {{#if refs.taches.length}} | ||||
|     <button name="edit-tache" data-tooltip="Modifier la tâche"><i class="fa-solid fa-edit"></i></button> | ||||
|     {{/if}} | ||||
|     {{/unless}} | ||||
|   </subline> | ||||
|   {{#if refs.taches.length}} | ||||
|   <subline> | ||||
|     Points de tâche: {{current.tache.system.points_de_tache_courant}} / | ||||
|     {{#if current.tache.system.cacher_points_de_tache}} | ||||
| @@ -25,4 +32,5 @@ | ||||
|   {{#if current.tache.system.periodicite}} | ||||
|     <subline>Périodicité: {{current.tache.system.periodicite}}</subline> | ||||
|   {{/if}} | ||||
|   {{/if}} | ||||
| </roll-part-detail> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user