Compare commits

...

30 Commits
13.0.9 ... v13

Author SHA1 Message Date
e21f7e398a Création de tâches dans la fenêtre de jets 2025-10-18 00:52:14 +02:00
e16f89743a Affichage des ajustements V2 2025-10-18 00:52:14 +02:00
a6c593c100 Corrections premiers retours 2025-10-18 00:52:14 +02:00
cd8e190082 Merge pull request 'v13.0.12 - La méditation d'Illysis' (#776) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 1m49s
Reviewed-on: #776
2025-10-16 20:14:03 +02:00
f2106763c1 v13.0.12 2025-10-16 00:55:58 +02:00
5da5cb0314 Gestion des maladresses 2025-10-16 00:35:43 +02:00
6d7f66569a Lancer de sorts V2 2025-10-15 22:42:14 +02:00
3e8963b20b Impacts uniquement sur l'acteur 2025-10-15 22:42:14 +02:00
2cf5b06da8 Correction: rename bringToTop 2025-10-15 22:42:13 +02:00
68c01fc930 Montée TMR sur méditation
ajout d'un bouton pour aller dans les TMR lors d'une
méditation réussie
2025-10-15 22:42:13 +02:00
3bc1c4871b Biugfix: compétences de jeu
Les compétences de jeu spécifiques (doublon) ne remplacent plus
la compétence active si le jet n'est pas un jet de jeu
2025-10-15 00:26:01 +02:00
3d732e9a8a Suppression des signes draconiques
en cas de descente des TMR, suppression des signes
draconiques éphémères durant seulement 1 round
2025-10-15 00:24:35 +02:00
35f226af5c Correction du générateur aléatoire
- couleurs de cheveux/yeux
- les tailles entre 1m00 et 1m09 sont correctement affichées
- possibilité de positionner le sexe masculin/féminin en un clic
2025-10-14 17:44:39 +02:00
126a0701d8 Merge pull request 'v13.0.11 - Le gambit d'Illysis' (#775) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 2m2s
Reviewed-on: #775
2025-10-09 14:14:44 +02:00
edf920b340 Roll V2: cuisine 2025-10-08 16:36:14 +02:00
293af5ab83 Roll V2: les jeux 2025-10-08 16:35:58 +02:00
1bf9e330f4 Petites améliorations 2025-10-05 22:39:08 +02:00
33dc58138c Merge pull request '13.0.10 - Les papilles d'Illysis' (#774) from VincentVk/foundryvtt-reve-de-dragon:v13 into v13
All checks were successful
Release Creation / build (release) Successful in 1m45s
Reviewed-on: #774
2025-10-05 21:39:20 +02:00
fa6769fcd7 Fenêtres Roll V2
Maintenant disponibles pour:
- méditation
- tâches
- soins
2025-10-05 03:09:52 +02:00
47c4478303 Roll V2 sur compétences&combat
Corrections associées
Maintenant, active en mode rollV2
2025-10-03 22:34:07 +02:00
52065fd6f6 changelog 13.0.10 2025-10-03 02:21:22 +02:00
6886f19921 Jet de compétence V2 2025-10-03 02:21:22 +02:00
10a89cc268 Fix regression table rdd 2025-10-03 02:21:22 +02:00
6a987086f8 Correction message init & pugilat 2025-10-03 02:21:22 +02:00
54f470d531 Roll recette de cuisine 2025-10-03 02:21:22 +02:00
37af0dd4f1 Rename ajustements => v1 2025-10-03 02:21:22 +02:00
d46b039a63 Ajout des saignements 2025-10-03 02:21:21 +02:00
7370b633db Gestion attaques v2 et initiative 2025-10-03 02:21:21 +02:00
d0ba1ebf99 utilisation de renderTemplate "interne"
Import de foundry.applications.handlebars.renderTemplate
au travers d'une constante pour éliminer les warnings
2025-09-30 02:04:53 +02:00
053bc23d12 Move HUD button attaque 2025-09-29 01:47:35 +02:00
150 changed files with 3190 additions and 1118 deletions

View 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,-28)" style=""><path d="M259.063 25.094c-56.045 0-106.836 9.775-144.438 26.125-18.8 8.174-34.34 17.96-45.594 29.53-11.254 11.57-18.28 25.338-18.28 40.188 0 9.936 3.17 19.388 8.625 28.03-10.218 21.883-15.844 45.794-15.844 70.782 0 103.158 95.757 187.844 215.532 187.844 119.776 0 215.563-84.686 215.563-187.844 0-24.99-5.653-48.897-15.875-70.78 5.454-8.644 8.625-18.096 8.625-28.032 0-14.85-7.026-28.617-18.28-40.188-11.256-11.57-26.825-21.356-45.626-29.53-37.603-16.35-88.363-26.126-144.408-26.126zm0 18.687c53.848 0 102.554 9.6 136.968 24.564 17.208 7.482 30.775 16.306 39.658 25.437 8.882 9.133 13 18.115 13 27.157 0 9.043-4.118 18.057-13 27.188-8.883 9.13-22.45 17.956-39.657 25.438-34.413 14.963-83.12 24.562-136.967 24.562-53.85 0-102.555-9.6-136.97-24.563-17.206-7.48-30.804-16.306-39.687-25.437-8.882-9.13-12.97-18.145-12.97-27.188 0-9.042 4.088-18.024 12.97-27.156 8.883-9.13 22.48-17.954 39.688-25.436 34.414-14.964 83.12-24.563 136.97-24.563zm-7.782 17.282c-80.57 0-146 26.008-146 57.844 0 31.836 65.43 57.81 146 57.813 40.04 0 76.404-6.613 102.782-16.94-21.316 3.34-45.064 5.845-70.656 5.845-86.066 0-155.937-21.656-155.937-47.906s69.868-47.282 155.936-47.282c20.43 0 39.926.725 57.813 2.906-24.816-7.704-55.957-12.28-89.94-12.28zM87.657 360.5c-9.916 19.897-14.758 36.638-15.78 49.03-1.23 14.906 2.752 22.238 6.655 24.626 3.905 2.388 11.497 2.48 23.376-5.75 9.25-6.41 20.16-17.73 31.375-34.406-16.778-9.432-32.1-20.71-45.624-33.5zm342.75.063c-13.532 12.782-28.872 24.043-45.656 33.468 11.21 16.666 22.13 27.97 31.375 34.376 11.88 8.23 19.472 8.138 23.375 5.75 3.903-2.388 7.886-9.72 6.656-24.625-1.022-12.38-5.855-29.098-15.75-48.967zm-199.25 64.25c1.36 21.275 5.296 37.554 10.344 48.468 6.272 13.56 13.26 17.82 17.72 17.908 4.457.088 11.14-3.683 17.374-16.907 5.133-10.89 9.165-27.52 10.437-49.467a267.366 267.366 0 0 1-27.967 1.468c-9.437 0-18.75-.506-27.907-1.467z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

1
assets/ui/fatigue.svg Normal file
View 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,-28)" style=""><path d="M249.094 18.25c-42.675 0-81.852 25.486-110.938 68.438C109.07 129.637 90.72 189.74 90.72 256.28c0 66.543 18.35 126.643 47.436 169.595s68.263 68.47 110.938 68.47 81.883-25.518 110.97-68.47c29.084-42.952 47.436-103.052 47.436-169.594 0-66.54-18.352-126.64-47.438-169.592C330.978 43.736 291.77 18.25 249.094 18.25zm-128.97 241.313c18.356 18.096 37.528 26.765 55.72 27.562 18.19.797 35.927-6.096 52.125-21.5l12.874 13.53c-19.214 18.274-42.25 27.658-65.813 26.626-23.56-1.03-47.1-12.3-68-32.905l13.095-13.313zm264.782 0 13.125 13.312C377.135 293.48 353.564 304.75 330 305.78c-23.563 1.033-46.598-8.35-65.813-26.624l12.875-13.53c16.2 15.403 33.934 22.296 52.125 21.5 18.192-.798 37.365-9.467 55.72-27.563zM251.562 371.656c36.423-.156 72.996 19.144 77.438 58.406-51.33 13.296-102.67 12.767-154 0 3.858-38.638 40.14-58.25 76.563-58.406z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
assets/ui/maladresse.svg Normal file
View 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

View 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,-28)" style=""><path d="M45.95 14.553c-19.38.81-30.594 11.357-30.282 30.283l19.768 30.78c4.43-1.213 9.36-3.838 14.248-7.335l42.474 59.935c-17.018 20.83-31.258 44.44-42.71 70.836l26.55 26.552c11.275-23.6 24.634-44.826 39.918-63.864l210.82 297.475 166.807 33.213L460.33 325.62 162.78 114.745c19.907-16.108 41.842-29.91 65.652-41.578l-26.553-26.55c-27.206 11.803-51.442 26.576-72.735 44.292L69.39 48.56c3.443-4.823 6.062-9.735 7.342-14.242l-30.78-19.765zm400.84 86.933v.008l.003-.008h-.002zm0 .008-28.028 124.97-25.116-80.593-18.105 70.667-26.862-49.64-.584 57.818 128.484 91.69 15.184 87.017-1.168-186.885-34.457 39.713-9.346-154.756zm-300.95 27.98 222.224 196.368 25.645 66.75-66.75-25.645L130.6 144.734a308.453 308.453 0 0 1 15.238-15.26zm32.305 196.274v.004h.005l-.005-.004zm.005.004 28.028 22.775-36.21 4.088 57.82 19.272-105.706 4.09 115.05 27.45L136.1 422.114l127.316 25.696-67.164 43.803 208.494 1.752-87.017-15.185-104.54-150.676-35.037-1.752z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

1
assets/ui/part-force.svg Normal file
View 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,-28)" style=""><path d="M227.227 21.777c-1.845 0-3.704.05-5.567.157-15.314.875-30.76 5.305-39.494 10.863l-.008 73.15c2.884-.094 5.777-.147 8.676-.142 23.382.036 47.104 3.286 68.47 9.513l.01-87.507c-7.034-3.518-19.178-6.03-32.087-6.033zm80.74 9.16c-11.925.15-23.077 2.364-29.967 5.596l-.008 77.602v7.658c38.486 15.67 64.814 42.48 58.735 78.764l-.96 5.73-5.562 1.674c-17.45 5.253-34.872 9.703-52.225 13.335v25.234c25.562-.704 51.327-2.687 77.145-6.098l.02-197.928c-8.284-5.563-23.508-10.243-38.842-11.328a100.065 100.065 0 0 0-8.336-.238zM143.223 46.294a99.206 99.206 0 0 0-16.491 1.172c-15.67 2.454-31.477 8.565-40.406 15.402l-.01 72.955c18.808-15.81 46.704-25.143 77.15-28.54l.007-57.966c-4.82-1.752-12.018-2.916-20.25-3.023zm258.394 3.46c-10.804.117-20.722 1.93-27.043 4.655l-.02 183.182c25.074-4.02 50.16-9.412 75.122-16.358l1.99-158.447c-8.352-5.9-23.648-11.025-39.05-12.553a100.98 100.98 0 0 0-11-.478zm-222.775 74.202c-53.72.702-101.407 20.365-97.887 66.6 15.836-3.918 30.84-5.893 44.94-6.1 34.84-.51 64.213 9.704 87.318 27.613 34.608-3.11 69.852-10 105.412-20.314.14-41.287-74.098-68.657-139.783-67.8zm-48.877 78.65c-1.296-.003-2.603.012-3.92.045-17.256.436-36.45 4.03-57.566 11.037 5.79 53.808 26.325 106.41 58.5 143.346 6.226 7.15 12.856 13.712 19.875 19.615 29.303 9.282 69.26 12.917 110.534 12.14 3.777-55.805-8.717-108.357-36.193-142.74-21.265-26.61-51.064-43.39-91.232-43.444zm129.326 22.282a545.177 545.177 0 0 1-27.995 4.15 138.77 138.77 0 0 1 4.502 5.346c3.146 3.937 6.094 8.062 8.873 12.334 9.916.144 19.868.125 29.857-.106H259.29v-21.723zm191.817 15.343c-65.406 17.826-131.462 25.41-195.85 25.315 16.998 35.144 23.828 78.093 21.013 122.6 42.482-2.08 85.03-8.23 118.187-15.983 26.693-32.78 47.37-77.118 56.65-131.932zM400.51 389.9c-38.334 9.145-87.95 16.056-136.873 17.454-47.67 1.36-94.336-2.228-129.448-15.262l-.01 78.93c27.187 12.568 76.414 20.205 127.318 20.298 51.224.094 104.214-7.173 139-20.773l.012-80.647z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View 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,-28)" style=""><path d="M275.03 20c35.223 49.563 53.59 113.64 55.69 173.47C315.154 143 289.092 88.423 250.81 48.75c40.294 79.527 51.15 172.312 37.938 256.094-12.287-75.777-40.564-159.524-92.375-227.156 29.6 70.937 36.64 149.785 24.813 221.843-8.745-51.804-25.41-107.4-52.594-158.81 13.023 54.315 12.854 107.64 3.437 159.28l21.657 6.813 15 4.718-11.28 10.908c-10.68 10.332-19.868 21.905-27.345 34.343 93.614 35.486 232.952 64.53 298.032 41.376-41.02 56.466-210.332 13.822-309.313-18.687-1.514 3.775-2.918 7.594-4.124 11.467a152.536 152.536 0 0 0-6.062 29.657l176.47 66.375c98.5 31.095 150.5-24.62 158.655-81.72C505.253 254.472 485.016 105.66 426.06 20h-22.187c40.092 65.52 66.67 154.216 60.47 255.344-8.154-79.833-42.8-157.214-98.44-219.5 38.676 85.094 56.566 185.746 34.376 288.625.057-118.816-33.1-225.865-105.092-324.47H275.03zm-110.186 1.594c41.255 29.176 74.328 74.093 97.5 120.656-7.702-46.15-21.3-86.79-44-120.656h-53.5zm176.375 0c28.882 15.143 52.096 36.614 71.28 66.78-7.14-27.79-17.217-49.85-31.438-66.78H341.22zM123.686 304.406a179.344 179.344 0 0 1-4.062 64L18.812 336.344V366l91.938 29.094a178.602 178.602 0 0 1-30.313 48.28l50.094 15.75c-3.038-24.898-1.136-49.885 6.282-73.718 7.446-23.92 20.223-46.108 37.032-65.22l-50.156-15.78z" fill="#fff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,4 +1,58 @@
# 13.0 # 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
- Nouvelle fenêtre de jets de dés
- jeux
- cuisine et préparation de nourriture
## 13.0.10 - Les papilles d'Illysis
- Ajout d'un statut "saignement" en cas de blessure grave ou critique sans premiers soins
- Nouvelle fenêtre de jets de dés
- jets de méditation
- jets de tâches
- jets de caractéristiques
- jets de compétences
- Boutons d'initiative et d'attaque V2
- fenêtre d'attaque
- choix des armes
- gestion des particulières
- message au défenseur
- gestion des demi-surprises (attaquant/défenseur)
- gestion des tactiques (attaquant/défenseur)
- en cours nouvelle fenêtre de jets
- jets de compétence avec messages
- jets de cuisine séparés avec messages (pour gérer plus tard les spécificités: fabricatioon de plats)
- gestion des empoignades
- Technique: suppression de warnings foundry sur renderTemplate
## 13.0.9 - Le combat d'Illysis ## 13.0.9 - Le combat d'Illysis
- Fix - Fix

View File

@@ -96,6 +96,7 @@ select,
--gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05), rgba(255, 200, 128, 0.1), rgba(255, 10, 0, 0.3)); --gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05), rgba(255, 200, 128, 0.1), rgba(255, 10, 0, 0.3));
--gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6)); --gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6));
--gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3), rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7)); --gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3), rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7));
--gradient-warning: linear-gradient(150deg, hsla(32, 100%, 50%, 0.3), hsla(52, 60%, 50%, 0.1), hsla(32, 60%, 50%, 0.1), hsla(32, 100%, 50%, 0.3));
--gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2)); --gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2));
--gradient-daylight: conic-gradient(from 0deg, hsla(50, 100%, 80%, 0.7), hsla(30, 30%, 40%, 0.1) 25%, hsla(250, 50%, 40%, 0.1) 25%, hsla(250, 30%, 30%, 0.7) 50%, hsla(250, 50%, 40%, 0.1) 75%, hsla(30, 30%, 40%, 0.1) 75%, hsla(50, 100%, 80%, 0.7)); --gradient-daylight: conic-gradient(from 0deg, hsla(50, 100%, 80%, 0.7), hsla(30, 30%, 40%, 0.1) 25%, hsla(250, 50%, 40%, 0.1) 25%, hsla(250, 30%, 30%, 0.7) 50%, hsla(250, 50%, 40%, 0.1) 75%, hsla(30, 30%, 40%, 0.1) 75%, hsla(50, 100%, 80%, 0.7));
--background-custom-button: linear-gradient(to bottom, hsla(208, 38%, 21%, 0.988) 5%, hsla(202, 42%, 14%, 0.671) 100%); --background-custom-button: linear-gradient(to bottom, hsla(208, 38%, 21%, 0.988) 5%, hsla(202, 42%, 14%, 0.671) 100%);
@@ -159,7 +160,7 @@ select,
min-height: 100px; min-height: 100px;
background: var(--rdd-bg-input-alt); background: var(--rdd-bg-input-alt);
padding: 5px; padding: 5px;
border-radius: 3px; border-radius: 0.2rem;
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
} }
.system-foundryvtt-reve-de-dragon .monnaie-content .window-content { .system-foundryvtt-reve-de-dragon .monnaie-content .window-content {
@@ -176,7 +177,7 @@ select,
background: var(--fieldset-background); background: var(--fieldset-background);
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
margin-bottom: 4px; margin-bottom: 4px;
border-radius: 6px; border-radius: 0.5rem;
border-color: var(--rdd-color-text-primary); border-color: var(--rdd-color-text-primary);
border-width: 2px; border-width: 2px;
} }
@@ -206,7 +207,7 @@ select,
border: 1px solid var(--rdd-color-border-input); border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input); color: var(--rdd-color-text-input);
padding: 2px 2px; padding: 2px 2px;
border-radius: 3px; border-radius: 0.2rem;
} }
.system-foundryvtt-reve-de-dragon .monnaie-content .form-group input[type="checkbox"] { .system-foundryvtt-reve-de-dragon .monnaie-content .form-group input[type="checkbox"] {
flex: 0 0 20px; flex: 0 0 20px;
@@ -250,7 +251,7 @@ select,
min-height: 100px; min-height: 100px;
background: var(--rdd-bg-input-alt); background: var(--rdd-bg-input-alt);
padding: 5px; padding: 5px;
border-radius: 3px; border-radius: 0.2rem;
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
} }
.system-foundryvtt-reve-de-dragon .munition-content .window-content { .system-foundryvtt-reve-de-dragon .munition-content .window-content {
@@ -267,7 +268,7 @@ select,
background: var(--fieldset-background); background: var(--fieldset-background);
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
margin-bottom: 4px; margin-bottom: 4px;
border-radius: 6px; border-radius: 0.5rem;
border-color: var(--rdd-color-text-primary); border-color: var(--rdd-color-text-primary);
border-width: 2px; border-width: 2px;
} }
@@ -297,7 +298,7 @@ select,
border: 1px solid var(--rdd-color-border-input); border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input); color: var(--rdd-color-text-input);
padding: 2px 2px; padding: 2px 2px;
border-radius: 3px; border-radius: 0.2rem;
} }
.system-foundryvtt-reve-de-dragon .munition-content .form-group input[type="checkbox"] { .system-foundryvtt-reve-de-dragon .munition-content .form-group input[type="checkbox"] {
flex: 0 0 20px; flex: 0 0 20px;
@@ -341,7 +342,7 @@ select,
min-height: 100px; min-height: 100px;
background: var(--rdd-bg-input-alt); background: var(--rdd-bg-input-alt);
padding: 5px; padding: 5px;
border-radius: 3px; border-radius: 0.2rem;
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
} }
.system-foundryvtt-reve-de-dragon .tarot-content .window-content { .system-foundryvtt-reve-de-dragon .tarot-content .window-content {
@@ -358,7 +359,7 @@ select,
background: var(--fieldset-background); background: var(--fieldset-background);
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
margin-bottom: 4px; margin-bottom: 4px;
border-radius: 6px; border-radius: 0.5rem;
border-color: var(--rdd-color-text-primary); border-color: var(--rdd-color-text-primary);
border-width: 2px; border-width: 2px;
} }
@@ -388,7 +389,7 @@ select,
border: 1px solid var(--rdd-color-border-input); border: 1px solid var(--rdd-color-border-input);
color: var(--rdd-color-text-input); color: var(--rdd-color-text-input);
padding: 2px 2px; padding: 2px 2px;
border-radius: 3px; border-radius: 0.2rem;
} }
.system-foundryvtt-reve-de-dragon .tarot-content .form-group input[type="checkbox"] { .system-foundryvtt-reve-de-dragon .tarot-content .form-group input[type="checkbox"] {
flex: 0 0 20px; flex: 0 0 20px;
@@ -528,6 +529,10 @@ select,
flex-direction: row; flex-direction: row;
margin: 0.1rem 0; margin: 0.1rem 0;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section subline .warning {
border-radius: 0.5rem;
background: var(--gradient-warning);
}
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-img { .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-img {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -555,6 +560,7 @@ select,
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline div.poesie-extrait { .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline div.poesie-extrait {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: normal;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise { .system-foundryvtt-reve-de-dragon .roll-dialog roll-choix roll-section roll-part-detail subline span.status-surprise {
display: flex; display: flex;
@@ -571,8 +577,12 @@ select,
display: flow; display: flow;
width: 2.5rem; width: 2.5rem;
text-align: right; text-align: right;
margin: 0 0.2rem 0 0.5rem; margin: 0 0.2rem;
padding: 0 0.2rem; padding: 0 0.2rem;
border: 1px solid ;
border-radius: 0.2rem;
height: 1.5rem;
background: hsla(0, 0%, 0%, 0.2);
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-action { .system-foundryvtt-reve-de-dragon .roll-dialog roll-action {
flex-basis: content; flex-basis: content;
@@ -627,12 +637,13 @@ select,
margin: 0 0.1rem; margin: 0 0.1rem;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-carac select[name="select-carac"] { .system-foundryvtt-reve-de-dragon .roll-dialog roll-carac select[name="select-carac"] {
max-width: 6rem; min-width: 6.5rem;
max-width: 8rem;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-comp select[name="select-comp"] { .system-foundryvtt-reve-de-dragon .roll-dialog roll-comp select[name="select-comp"] {
min-width: 8rem; min-width: 8rem;
max-width: 11rem; max-width: 10rem;
margin-left: 1rem; margin-left: 1.5rem;
} }
.system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="coeur"] select[name="coeur"] { .system-foundryvtt-reve-de-dragon .roll-dialog roll-conditions roll-section[name="coeur"] select[name="coeur"] {
max-width: 4rem; max-width: 4rem;
@@ -655,7 +666,8 @@ select,
width: 1.5rem; width: 1.5rem;
text-align: center; text-align: center;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat {
font-family: CaslonAntique; font-family: CaslonAntique;
display: grid; display: grid;
grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions"; grid-template-areas: "img header buttons" "img resume buttons" "details details details" "actions actions actions";
@@ -663,51 +675,65 @@ select,
grid-template-rows: max-content max-content max-content max-content; grid-template-rows: max-content max-content max-content max-content;
gap: 0 0.5rem; gap: 0 0.5rem;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img {
grid-area: img; grid-area: img;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img img { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-img img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-img img {
border: 0; border: 0;
max-height: 3rem; max-height: 3rem;
max-width: 3rem; max-width: 3rem;
object-fit: contain; object-fit: contain;
height: 100%; height: 100%;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-header { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-header,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-header {
grid-area: header; grid-area: header;
font-weight: bold; font-weight: bold;
font-size: 0.9rem; font-size: 0.9rem;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-resume { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-resume,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-resume {
grid-area: resume; grid-area: resume;
text-align: justify; text-align: justify;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-details,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-details {
grid-area: details; grid-area: details;
text-align: justify; text-align: justify;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions { .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; grid-area: actions;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a img { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-actions a img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-actions a img {
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons {
grid-area: buttons; grid-area: buttons;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a {
border-radius: 0.2rem; border-radius: 0.2rem;
cursor: pointer; cursor: pointer;
padding: 0.2rem; padding: 0.2rem;
@@ -718,21 +744,27 @@ select,
display: inline-block; display: inline-block;
align-items: center; align-items: center;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a img { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a img,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a img {
max-width: 1rem; max-width: 1rem;
max-height: 1rem; max-height: 1rem;
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:hover { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:hover,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
} }
.system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:active { .system-foundryvtt-reve-de-dragon .chat-message div.roll-chat div.chat-buttons a:active,
.system-foundryvtt-reve-de-dragon .dialog-content div.roll-chat div.chat-buttons a:active {
position: relative; position: relative;
top: 1px; top: 1px;
} }
.system-foundryvtt-reve-de-dragon .window-header { .system-foundryvtt-reve-de-dragon .window-header {
background: rgba(0, 0, 0, 0.75); 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 { .system-foundryvtt-reve-de-dragon .window-app.sheet .window-content {
margin: 0.2rem; margin: 0.2rem;
padding: 0; padding: 0;
@@ -899,6 +931,12 @@ select,
.system-foundryvtt-reve-de-dragon a:hover { .system-foundryvtt-reve-de-dragon a:hover {
text-shadow: 1px 0px 0px #ff6600; 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:hover,
.system-foundryvtt-reve-de-dragon .rollable:focus { .system-foundryvtt-reve-de-dragon .rollable:focus {
color: #000; color: #000;
@@ -1423,12 +1461,27 @@ select,
.system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls { .system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls {
display: none !important; 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) { .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) {
font-size: 0.8em; font-size: 0.8em;
color: var(--color-controls-light); 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 { .system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6; opacity: 0.6;
} }
@@ -1444,38 +1497,38 @@ select,
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-part { .system-foundryvtt-reve-de-dragon .rdd-roll-part {
align-items: center; align-items: center;
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-gold); background: var(--gradient-gold);
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-sign { .system-foundryvtt-reve-de-dragon .rdd-roll-sign {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-silver); background: var(--gradient-silver);
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-norm { .system-foundryvtt-reve-de-dragon .rdd-roll-norm {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-green); background: var(--gradient-green);
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-notSign, .system-foundryvtt-reve-de-dragon .rdd-roll-notSign,
.system-foundryvtt-reve-de-dragon .rdd-roll-echec { .system-foundryvtt-reve-de-dragon .rdd-roll-echec {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-red); background: var(--gradient-red);
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-epart { .system-foundryvtt-reve-de-dragon .rdd-roll-epart {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-violet); background: var(--gradient-violet);
} }
.system-foundryvtt-reve-de-dragon .rdd-roll-etotal { .system-foundryvtt-reve-de-dragon .rdd-roll-etotal {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-purple-black); background: var(--gradient-purple-black);
} }
.system-foundryvtt-reve-de-dragon .rdd-diviseur { .system-foundryvtt-reve-de-dragon .rdd-diviseur {
border-radius: 6px; border-radius: 0.5rem;
padding: 3px; padding: 3px;
background: var(--gradient-red); background: var(--gradient-red);
} }
@@ -1502,12 +1555,8 @@ select,
font-size: 0.8rem; font-size: 0.8rem;
font-style: italic; font-style: italic;
color: rgba(82, 17, 131, 0.9); color: rgba(82, 17, 131, 0.9);
overflow: hidden; overflow-y: scroll;
} width: 100%;
.system-foundryvtt-reve-de-dragon .poesie-extrait:hover {
max-height: unset;
overflow: visible;
opacity: 1;
} }
.system-foundryvtt-reve-de-dragon .poesie-reference { .system-foundryvtt-reve-de-dragon .poesie-reference {
font-size: 0.7rem; font-size: 0.7rem;
@@ -1573,7 +1622,10 @@ select,
height: var(--form-field-height); height: var(--form-field-height);
margin: 0; margin: 0;
color: var(--color-text-dark-primary); color: var(--color-text-dark-primary);
border-radius: 3px; 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 { .system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral {
width: 14rem; width: 14rem;
@@ -1595,8 +1647,9 @@ select,
height: 2rem; height: 2rem;
} }
.system-foundryvtt-reve-de-dragon .window-app .window-content, .system-foundryvtt-reve-de-dragon .window-app .window-content,
.system-foundryvtt-reve-de-dragon .window-app.sheet .window-content .sheet-body { .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 .application .window-content {
background: url(../assets/ui/bg_left.webp) no-repeat left top;
} }
.system-foundryvtt-reve-de-dragon section.sheet-body { .system-foundryvtt-reve-de-dragon section.sheet-body {
padding: 0.25rem 0.5rem; padding: 0.25rem 0.5rem;
@@ -1624,7 +1677,7 @@ select,
background: hsla(280, 50%, 50%, 0.1); background: hsla(280, 50%, 50%, 0.1);
padding: 1px 4px; padding: 1px 4px;
border: 1px solid var(--color-border-dark-tertiary); border: 1px solid var(--color-border-dark-tertiary);
border-radius: 2px; border-radius: 0.2rem;
white-space: nowrap; white-space: nowrap;
word-break: break-all; word-break: break-all;
} }
@@ -1634,7 +1687,7 @@ select,
font-weight: 560; font-weight: 560;
padding: 0.1rem 0.3rem; padding: 0.1rem 0.3rem;
border: 1px solid var(--color-border-dark-tertiary); border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.25rem; border-radius: 0.2rem;
white-space: nowrap; white-space: nowrap;
word-break: break-all; word-break: break-all;
display: ruby; display: ruby;
@@ -1754,7 +1807,7 @@ select,
.system-foundryvtt-reve-de-dragon .xp-level-up { .system-foundryvtt-reve-de-dragon .xp-level-up {
margin: 0.1rem; margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096; box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.25rem; border-radius: 0.2rem;
padding: 0.1rem; padding: 0.1rem;
flex: 1 1 5rem; flex: 1 1 5rem;
background: var(--gradient-gold) !important; background: var(--gradient-gold) !important;
@@ -1785,7 +1838,7 @@ select,
.system-foundryvtt-reve-de-dragon .list-item { .system-foundryvtt-reve-de-dragon .list-item {
margin: 0.1rem; margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096; box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.25rem; border-radius: 0.2rem;
padding: 0.1rem; padding: 0.1rem;
flex: 1 1 1.5rem; flex: 1 1 1.5rem;
display: flex; display: flex;
@@ -1954,13 +2007,13 @@ select,
justify-content: flex-start; justify-content: flex-start;
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
top: 4.6rem; top: 10rem;
left: -19rem; left: -9rem;
} }
.system-foundryvtt-reve-de-dragon .token-hud-ext.soins { .system-foundryvtt-reve-de-dragon .token-hud-ext.soins {
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
top: 14.7rem; top: 15.5rem;
left: -6rem; left: -6rem;
max-width: 8rem; max-width: 8rem;
line-height: 1rem; line-height: 1rem;
@@ -1975,14 +2028,18 @@ select,
width: 9rem; width: 9rem;
height: fit-content; height: fit-content;
border-radius: 0.3rem; border-radius: 0.3rem;
min-width: 6rem; min-width: 8rem;
flex-basis: auto; flex-basis: auto;
padding: 0; padding: 0;
line-height: 0.95rem; line-height: 1.6rem;
margin: 0.2rem; margin: 0.2rem;
display: flex;
flex-direction: row;
align-items: center;
} }
.system-foundryvtt-reve-de-dragon .rdd-hud-menu label { .system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon select,
font-size: 0.8rem; .system-foundryvtt-reve-de-dragon div.control-icon.token-hud-icon label {
font-size: 1rem;
} }
.system-foundryvtt-reve-de-dragon .item-checkbox { .system-foundryvtt-reve-de-dragon .item-checkbox {
height: 25px; height: 25px;
@@ -2094,6 +2151,9 @@ select,
font-size: 0.7rem; font-size: 0.7rem;
flex-grow: 3; flex-grow: 3;
} }
.system-foundryvtt-reve-de-dragon .chat-message header.message-header .message-metadata {
flex-grow: 3.5;
}
.system-foundryvtt-reve-de-dragon .chat-message hr { .system-foundryvtt-reve-de-dragon .chat-message hr {
margin: 0.2rem 0; margin: 0.2rem 0;
} }
@@ -2264,7 +2324,7 @@ select,
pointer-events: all; pointer-events: all;
} }
.system-foundryvtt-reve-de-dragon div.horloge-roue div.horloge-cercle { .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%; top: 2%;
left: 2%; left: 2%;
width: 96%; width: 96%;
@@ -2314,7 +2374,7 @@ select,
font-size: 0.8rem; font-size: 0.8rem;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
border-radius: 0.3rem; border-radius: 0.2rem;
} }
.system-foundryvtt-reve-de-dragon div.horloge-roue div img { .system-foundryvtt-reve-de-dragon div.horloge-roue div img {
border: none; border: none;
@@ -2641,7 +2701,7 @@ select,
.system-foundryvtt-reve-de-dragon :is(.tooltip, .tooltip-overflow) .ttt-ajustements { .system-foundryvtt-reve-de-dragon :is(.tooltip, .tooltip-overflow) .ttt-ajustements {
width: 10rem; width: 10rem;
background: var(--background-tooltip); background: var(--background-tooltip);
border-radius: 6px; border-radius: 0.5rem;
font-size: 0.9rem; font-size: 0.9rem;
padding: 3px 0; padding: 3px 0;
} }
@@ -2709,11 +2769,9 @@ select,
} }
.system-foundryvtt-reve-de-dragon .chat-card-button:hover { .system-foundryvtt-reve-de-dragon .chat-card-button:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover { .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover {
background: var(--background-custom-button-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:active,
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active { .system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active {

1
icons/cuisine/gibier.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

1
icons/cuisine/herbe.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.6 KiB

1
icons/cuisine/plante.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.8 KiB

1
icons/cuisine/ragout.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -27,6 +27,11 @@
--gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05),rgba(255, 200, 128, 0.1), rgba(255,10,0,0.3)); --gradient-red: linear-gradient(150deg, rgba(255, 0, 0, 0.3), rgba(255, 200, 128, 0.05),rgba(255, 200, 128, 0.1), rgba(255,10,0,0.3));
--gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6)); --gradient-violet: linear-gradient(150deg, rgba(100, 45, 124, 0.6), rgba(216, 157, 192, 0.3), rgba(177, 157, 216, 0.5), rgba(107, 62, 121, 0.3), rgba(100, 45, 124, 0.6));
--gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3),rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7)); --gradient-purple-black: linear-gradient(150deg, rgba(0, 0, 0, 0.7), rgba(100, 45, 124, 0.4), rgba(82, 17, 131, 0.3),rgba(100, 45, 124, 0.4), rgba(0, 0, 0, 0.7));
--gradient-warning: linear-gradient(150deg,
hsla(32, 100%, 50%, 0.3),
hsla(52, 60%, 50%, 0.1),
hsla(32, 60%, 50%, 0.1),
hsla(32, 100%, 50%, 0.3));
--gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2)); --gradient-silver-light: linear-gradient(30deg, rgba(61, 55, 93, 0.2), rgba(178, 179, 196, 0.1), rgba(59, 62, 63, 0.2), rgba(206, 204, 199, 0.1), rgba(61, 46, 49, 0.2));
--gradient-daylight: conic-gradient( --gradient-daylight: conic-gradient(
from 0deg, from 0deg,

View File

@@ -12,7 +12,10 @@
background: rgba(0,0,0,0.75); background: rgba(0,0,0,0.75);
} }
.application .window-content, .application .window-content {
margin: 0;
padding: 0.2rem;
}
.window-app.sheet .window-content { .window-app.sheet .window-content {
margin: 0.2rem; margin: 0.2rem;
padding: 0; padding: 0;
@@ -200,6 +203,9 @@
i.moral-radio-checkmark-off:hover, i.moral-radio-checkmark-off:hover,
a:hover { a:hover {
text-shadow: 1px 0px 0px #ff6600; text-shadow: 1px 0px 0px #ff6600;
img {
filter: drop-shadow(1px 0px 0px #ff6600);
}
} }
.rollable:hover, .rollable:focus { .rollable:hover, .rollable:focus {
@@ -754,16 +760,31 @@
.competence-list .item-controls.hidden-controls { .competence-list .item-controls.hidden-controls {
display: none !important; 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), img {
.item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) { 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; font-size: 0.8em;
color: var(--color-controls-light); 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 { img:hover,
i:is(.fas, .far, .fa-solid, .fa-regular):hover {
opacity: 0.6; opacity: 0.6;
} }
}
.rdd-roll-dialog .description-sort { .rdd-roll-dialog .description-sort {
max-width: 550px; max-width: 550px;
@@ -777,31 +798,31 @@
} }
.rdd-roll-part { .rdd-roll-part {
align-items: center; align-items: center;
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-gold); background: var(--gradient-gold);
} }
.rdd-roll-sign{ .rdd-roll-sign{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-silver); background: var(--gradient-silver);
} }
.rdd-roll-norm{ .rdd-roll-norm{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-green); background: var(--gradient-green);
} }
.rdd-roll-notSign, .rdd-roll-echec{ .rdd-roll-notSign, .rdd-roll-echec{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-red); background: var(--gradient-red);
} }
.rdd-roll-epart{ .rdd-roll-epart{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-violet); background: var(--gradient-violet);
} }
.rdd-roll-etotal{ .rdd-roll-etotal{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-purple-black); background: var(--gradient-purple-black);
} }
.rdd-diviseur{ .rdd-diviseur{
border-radius: 6px; padding: 3px; border-radius: 0.5rem; padding: 3px;
background: var(--gradient-red); background: var(--gradient-red);
} }
@@ -832,13 +853,8 @@
font-size: 0.8rem; font-size: 0.8rem;
font-style: italic; font-style: italic;
color: rgba(82, 17, 131, 0.9); color: rgba(82, 17, 131, 0.9);
overflow: hidden; overflow-y: scroll;
} width: 100%;
.poesie-extrait:hover {
max-height: unset;
overflow: visible;
opacity: 1;
} }
.poesie-reference { .poesie-reference {
@@ -913,7 +929,12 @@
height: var(--form-field-height); height: var(--form-field-height);
margin: 0; margin: 0;
color: var(--color-text-dark-primary); color: var(--color-text-dark-primary);
border-radius: 3px; border-radius: 0.2rem;
}
form.app-personnage-aleatoire {
h2 {
min-width: 30rem,
}
} }
.app-calendar-astrologie{ .app-calendar-astrologie{
div.theme-astral{ div.theme-astral{
@@ -937,8 +958,10 @@
} }
} }
.window-app .window-content, .window-app.sheet .window-content .sheet-body{ .window-app .window-content,
background: rgb(245,245,240) url(../assets/ui/bg_left.webp) no-repeat left top; .window-app.sheet .window-content .sheet-body,
.application .window-content {
background: url(../assets/ui/bg_left.webp) no-repeat left top;
} }
section.sheet-body { section.sheet-body {
@@ -970,7 +993,7 @@
background: hsla(280, 50%, 50%, 0.1); background: hsla(280, 50%, 50%, 0.1);
padding: 1px 4px; padding: 1px 4px;
border: 1px solid var(--color-border-dark-tertiary); border: 1px solid var(--color-border-dark-tertiary);
border-radius: 2px; border-radius: 0.2rem;
white-space: nowrap; white-space: nowrap;
word-break: break-all; word-break: break-all;
} }
@@ -981,7 +1004,7 @@
font-weight: 560; font-weight: 560;
padding: 0.1rem 0.3rem; padding: 0.1rem 0.3rem;
border: 1px solid var(--color-border-dark-tertiary); border: 1px solid var(--color-border-dark-tertiary);
border-radius: 0.25rem; border-radius: 0.2rem;
white-space: nowrap; white-space: nowrap;
word-break: break-all; word-break: break-all;
display: ruby; display: ruby;
@@ -1111,7 +1134,7 @@
.xp-level-up { .xp-level-up {
margin: 0.1rem; margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096; box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.25rem; border-radius: 0.2rem;
padding: 0.1rem; padding: 0.1rem;
flex: 1 1 5rem; flex: 1 1 5rem;
background: var(--gradient-gold) !important; background: var(--gradient-gold) !important;
@@ -1142,7 +1165,7 @@
.list-item { .list-item {
margin: 0.1rem; margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096; box-shadow: inset 0px 0px 1px #00000096;
border-radius: 0.25rem; border-radius: 0.2rem;
padding: 0.1rem; padding: 0.1rem;
flex: 1 1 1.5rem; flex: 1 1 1.5rem;
display: flex; display: flex;
@@ -1319,13 +1342,13 @@
justify-content: flex-start; justify-content: flex-start;
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
top: 4.6rem; top: 10rem;
left: -19rem; left: -9rem;
} }
.token-hud-ext.soins { .token-hud-ext.soins {
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
top: 14.7rem; top: 15.5rem;
left: -6rem; left: -6rem;
max-width: 8rem; max-width: 8rem;
line-height: 1rem; line-height: 1rem;
@@ -1341,14 +1364,18 @@
width: 9rem; width: 9rem;
height: fit-content; height: fit-content;
border-radius: 0.3rem; border-radius: 0.3rem;
min-width: 6rem; min-width: 8rem;
flex-basis: auto; flex-basis: auto;
padding: 0; padding: 0;
line-height: 0.95rem; line-height: 1.6rem;
margin: 0.2rem; margin: 0.2rem;
display: flex;
flex-direction: row;
align-items: center;
select, label {
font-size: 1rem;
} }
.rdd-hud-menu label {
font-size: 0.8rem;
} }
/* ======================================== */ /* ======================================== */
.item-checkbox { .item-checkbox {
@@ -1479,10 +1506,15 @@
.message-content { .message-content {
text-align: justify; text-align: justify;
} }
header.message-header .heure-rdd { header.message-header{
.heure-rdd {
font-size: 0.7rem; font-size: 0.7rem;
flex-grow: 3; flex-grow: 3;
} }
.message-metadata {
flex-grow: 3.5;
}
}
hr { hr {
margin: 0.2rem 0; margin: 0.2rem 0;
} }
@@ -1650,7 +1682,7 @@
} }
div.horloge-roue div.horloge-cercle { 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%; top: 2%; left: 2%; width: 96%; height: 96%; border-radius: 50%;
} }
@@ -1681,7 +1713,7 @@
font-size: 0.8rem; font-size: 0.8rem;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
border-radius: 0.3rem; border-radius: 0.2rem;
} }
div.horloge-roue div img { div.horloge-roue div img {
@@ -1917,7 +1949,7 @@
.ttt-ajustements { .ttt-ajustements {
width: 10rem; width: 10rem;
background: var(--background-tooltip); background: var(--background-tooltip);
border-radius: 6px; border-radius: 0.5rem;
font-size: 0.9rem; font-size: 0.9rem;
padding: 3px 0; padding: 3px 0;
div:nth-child(odd) { div:nth-child(odd) {
@@ -1994,12 +2026,10 @@
.chat-card-button:hover { .chat-card-button:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.chat-card-button-pushed:hover { .chat-card-button-pushed:hover {
background: var(--background-custom-button-hover); background: var(--background-custom-button-hover);
background-color: red;
} }
.chat-card-button:active, .chat-card-button-pushed:active { .chat-card-button:active, .chat-card-button-pushed:active {

View File

@@ -1,5 +1,5 @@
.chat-message { .chat-message div.roll-chat,
div.roll-chat { .dialog-content div.roll-chat {
font-family: CaslonAntique; font-family: CaslonAntique;
display: grid; display: grid;
grid-template-areas: grid-template-areas:
@@ -37,6 +37,9 @@
text-align: justify; text-align: justify;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
div {
display: block;
}
} }
div.chat-actions { div.chat-actions {
grid-area: actions; grid-area: actions;
@@ -84,4 +87,3 @@
} }
} }
}

View File

@@ -89,6 +89,10 @@
display: flex; display: flex;
flex-direction: row; flex-direction: row;
margin: 0.1rem 0; margin: 0.1rem 0;
.warning {
border-radius: 0.5rem;
background: var(--gradient-warning);
}
} }
roll-part-img { roll-part-img {
@@ -117,6 +121,7 @@
div.poesie-extrait{ div.poesie-extrait{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: normal;
} }
span.status-surprise{ span.status-surprise{
display: flex; display: flex;
@@ -137,8 +142,13 @@
display: flow; display: flow;
width: 2.5rem; width: 2.5rem;
text-align: right; text-align: right;
margin: 0 0.2rem 0 0.5rem; margin: 0 0.2rem;
padding: 0 0.2rem; padding: 0 0.2rem;
border: 1px solid ;
border-radius: 0.2rem ;
background: hsla(0, 0%, 0%, 0.2);
height: 1.5rem;
background: hsla(0, 0%, 0%, 0.2);
} }
roll-action { roll-action {
@@ -201,13 +211,13 @@
} }
roll-carac select[name="select-carac"] { roll-carac select[name="select-carac"] {
max-width: 6rem; min-width: 6.5rem;
max-width: 8rem;
} }
roll-comp select[name="select-comp"] { roll-comp select[name="select-comp"] {
min-width: 8rem; min-width: 8rem;
max-width: 11rem; max-width: 10rem;
margin-left: 1rem; margin-left: 1.5rem;
} }
roll-conditions roll-section[name="coeur"] select[name="coeur"] { roll-conditions roll-section[name="coeur"] select[name="coeur"] {

View File

@@ -8,7 +8,7 @@
min-height: 100px; // Hauteur minimale pour la description min-height: 100px; // Hauteur minimale pour la description
background: var(--rdd-bg-input-alt); // Une couleur de fond alternative background: var(--rdd-bg-input-alt); // Une couleur de fond alternative
padding: 5px; padding: 5px;
border-radius: 3px; border-radius: 0.2rem;
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
} }
@@ -28,7 +28,7 @@
background: var(--fieldset-background); background: var(--fieldset-background);
color: var(--rdd-color-text-primary); color: var(--rdd-color-text-primary);
margin-bottom: 4px; margin-bottom: 4px;
border-radius: 6px; border-radius: 0.5rem;
border-color: var(--rdd-color-text-primary); border-color: var(--rdd-color-text-primary);
border-width: 2px; border-width: 2px;
} }
@@ -64,7 +64,7 @@
--rdd-color-text-input --rdd-color-text-input
); // Assurez-vous que cette variable existe ); // Assurez-vous que cette variable existe
padding: 2px 2px; // Augmentation du padding vertical padding: 2px 2px; // Augmentation du padding vertical
border-radius: 3px; border-radius: 0.2rem;
} }
input[type="checkbox"] { input[type="checkbox"] {

View File

@@ -1,4 +1,4 @@
import { SYSTEM_RDD } from "../constants.js"; import { renderTemplate, SYSTEM_RDD } from "../constants.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
const DETAIL_VENTE = 'detailVente'; const DETAIL_VENTE = 'detailVente';

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "../constants.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js"; import { ChatVente } from "./chat-vente.js";

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "../constants.js";
import { HtmlUtility } from "../html-utility.js"; import { HtmlUtility } from "../html-utility.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js"; import { ChatVente } from "./chat-vente.js";

View File

@@ -3,7 +3,7 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDBonus } from "./rdd-bonus.js"; import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js"; import { CARACS, RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js"; import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js";
@@ -174,7 +174,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } }) await this.getBlessure(event)?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
}); });
this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac('chance-actuelle')) this.html.find('.roll-chance-actuelle').click(async event => await this.actor.rollCarac(CARACS.CHANCE_ACTUELLE))
this.html.find('.button-appel-chance').click(async event => await this.actor.rollAppelChance()) this.html.find('.button-appel-chance').click(async event => await this.actor.rollAppelChance())
this.html.find('[name="jet-astrologie"]').click(async event => await this.actor.astrologieNombresAstraux()) this.html.find('[name="jet-astrologie"]').click(async event => await this.actor.astrologieNombresAstraux())
@@ -208,7 +208,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
} }
// Points de reve actuel // Points de reve actuel
this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac('reve-actuel', { resistance: true })) this.html.find('.roll-reve-actuel').click(async event => await this.actor.rollCarac(CARACS.REVE_ACTUEL, { resistance: true }))
this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) this.html.find('.action-empoignade').click(async event => await RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.roll-arme').click(async event => { this.html.find('.roll-arme').click(async event => {
@@ -342,7 +342,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async createEmptyTache() { async createEmptyTache() {
await this.actor.createItem('tache', 'Nouvelle tache'); await this.actor.createItem(ITEM_TYPES.tache, 'Nouvelle tache')
} }
_getActionCombat(event) { _getActionCombat(event) {

View File

@@ -17,9 +17,9 @@ import { Draconique } from "./tmr/draconique.js";
import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js"; import { CARACS, LIST_CARAC_PERSONNAGE, RdDCarac } from "./rdd-carac.js";
import { DialogConsommer } from "./dialog-item-consommer.js"; import { DialogConsommer } from "./dialog-item-consommer.js";
import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js"; import { DialogFabriquerPotion } from "./dialog-fabriquer-potion.js";
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RdDPossession } from "./rdd-possession.js"; import { RdDPossession } from "./rdd-possession.js";
import { ACTOR_TYPES, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { ACTOR_TYPES, renderTemplate, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDConfirm } from "./rdd-confirm.js"; import { RdDConfirm } from "./rdd-confirm.js";
import { DialogRepos } from "./sommeil/dialog-repos.js"; import { DialogRepos } from "./sommeil/dialog-repos.js";
import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDBaseActor } from "./actor/base-actor.js";
@@ -47,6 +47,12 @@ import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDInitiative } from "./initiative.mjs"; import { RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs"; import RollDialog from "./roll/roll-dialog.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js"; import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
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'] export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@@ -98,6 +104,8 @@ export class RdDActor extends RdDBaseActorSang {
} }
isPersonnage() { return true } isPersonnage() { return true }
isFeminin() { return this.system.sexe.length > 0 && this.system.sexe.charAt(0).toLowerCase() == 'f' }
isHautRevant() { return this.system.attributs.hautrevant.value != "" } isHautRevant() { return this.system.attributs.hautrevant.value != "" }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -136,12 +144,12 @@ export class RdDActor extends RdDBaseActorSang {
} }
listActions({ isAttaque = false, isEquipe = false }) { listActions({ isAttaque = false, isEquipe = false }) {
// Recupération des armes // Recupération des attaques
const actions = this.listActionsAttaque() const actions = this.listActionsAttaque()
.filter(it => !isEquipe || it.arme.system.equipe) .filter(it => !isEquipe || it.arme.system.equipe)
if (!isAttaque && this.system.attributs.hautrevant.value) { if (!isAttaque && this.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', initOnly: true }) actions.push({ label: "Draconic", action: 'haut-reve', initOnly: true })
} }
return actions return actions
} }
@@ -158,10 +166,10 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord } getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') } getDraconics() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate([...this.getDraconicList(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) } getBestDraconic() { return foundry.utils.duplicate([...this.getDraconics(), PAS_DE_DRACONIC].sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() { getDraconicOuPossession() {
return [...this.getDraconicList().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC] return [...this.getDraconics().filter(it => it.system.niveau >= 0), POSSESSION_SANS_DRACONIC]
.sort(Misc.descending(it => it.system.niveau)) .sort(Misc.descending(it => it.system.niveau))
.find(it => true) .find(it => true)
} }
@@ -177,7 +185,7 @@ export class RdDActor extends RdDBaseActorSang {
const actions = [] const actions = []
const uniques = [] const uniques = []
const addAttaque = (arme, main) => { const addAttaque = (arme, main = undefined, action = 'attaque') => {
const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main) const dommagesArme = RdDItemArme.valeurMain(arme.system.dommages, main)
const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main) const forceRequise = RdDItemArme.valeurMain(arme.system.force ?? 0, main)
const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0; const ecaillesEfficacite = arme.system.magique ? arme.system.ecaille_efficacite : 0;
@@ -196,7 +204,7 @@ export class RdDActor extends RdDBaseActorSang {
const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite const ajustement = (arme.parent?.getEtatGeneral() ?? 0) + ecaillesEfficacite
actions.push({ actions.push({
name: arme.name + (main ? ' ' + main : ''), label: arme.name + (main ? ' ' + main : ''),
action: 'attaque', action: 'attaque',
initOnly: false, initOnly: false,
arme: arme, arme: arme,
@@ -206,22 +214,23 @@ export class RdDActor extends RdDBaseActorSang {
equipe: arme.system.equipe, equipe: arme.system.equipe,
dommagesArme: dommagesArme, dommagesArme: dommagesArme,
forceRequise: forceRequise, forceRequise: forceRequise,
initiative: RdDInitiative.calculInitiative(niveau, caracValue, ajustement) initiative: RdDInitiative.getRollInitiative(caracValue, niveau, ajustement)
}) })
} }
addAttaque(RdDItemArme.empoignade(this))
addAttaque(RdDItemArme.corpsACorps(this))
this.itemTypes[ITEM_TYPES.arme] this.itemTypes[ITEM_TYPES.arme]
.filter(it => it.isAttaque()) .filter(it => it.isAttaque())
.sort(Misc.ascending(it => it.name)) .sort(Misc.ascending(it => it.name))
.forEach(arme => { .forEach(arme => {
if (arme.system.unemain && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) } if (arme.system.unemain && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.UNE_MAIN) }
if (arme.system.deuxmains && arme.system.competence) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) } if (arme.system.deuxmains && arme.system.competence && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.DEUX_MAINS) }
if (arme.system.lancer) { addAttaque(arme, ATTAQUE_TYPE.LANCER) } if (arme.system.lancer && arme.system.resistance > 0) { addAttaque(arme, ATTAQUE_TYPE.LANCER) }
if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) } if (arme.system.tir) { addAttaque(arme, ATTAQUE_TYPE.TIR) }
}) })
addAttaque(RdDItemArme.pugilat(this), ATTAQUE_TYPE.CORPS_A_CORPS)
addAttaque(RdDItemArme.empoignade(this), ATTAQUE_TYPE.CORPS_A_CORPS, 'empoignade')
return actions return actions
} }
@@ -697,11 +706,12 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async combattreReveDeDragon(force) { async combattreReveDeDragon(force) {
const rencontre = await game.system.rdd.rencontresTMR.getReveDeDragon(force);
let rollData = { let rollData = {
actor: this, actor: this,
competence: this.getDraconicOuPossession(), competence: this.getDraconicOuPossession(),
canClose: false, canClose: false,
rencontre: await game.system.rdd.rencontresTMR.getReveDeDragon(force), rencontre: rencontre,
tmr: true, tmr: true,
use: { libre: false, conditions: false }, use: { libre: false, conditions: false },
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } } forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: this.getReveActuel() } }
@@ -732,12 +742,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async sortMisEnReserve(sort, draconic, coord, ptreve) { async sortMisEnReserve(sort, draconic, coord, ptreve) {
await this.createEmbeddedDocuments("Item", [{ await this.createEmbeddedDocuments("Item", [RdDItemSort.prepareSortEnReserve(sort, draconic, ptreve, coord)],
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' }
}],
{ renderSheet: false }); { renderSheet: false });
this.tmrApp.updateTokens(); this.tmrApp.updateTokens();
} }
@@ -1342,7 +1347,7 @@ export class RdDActor extends RdDBaseActorSang {
async _apprecierCuisine(item, seForcer) { async _apprecierCuisine(item, seForcer) {
const surmonteExotisme = await this._surmonterExotisme(item, seForcer); const surmonteExotisme = await this._surmonterExotisme(item, seForcer);
if (surmonteExotisme) { if (surmonteExotisme) {
await this.apprecier('gout', 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat"); await this.apprecier(CARACS.ODORATGOUT, 'cuisine', item.system.qualite, item.system.boisson ? "apprécie la boisson" : "apprécie le plat");
} }
else if (seForcer) { else if (seForcer) {
await this.jetDeMoral('malheureux'); await this.jetDeMoral('malheureux');
@@ -1360,7 +1365,7 @@ export class RdDActor extends RdDBaseActorSang {
if (exotisme < 0 || qualite < 0) { if (exotisme < 0 || qualite < 0) {
const competence = qualite > 0 ? 'cuisine' : undefined const competence = qualite > 0 ? 'cuisine' : undefined
const difficulte = Math.min(exotisme, qualite) const difficulte = Math.min(exotisme, qualite)
const rolled = await this.doRollCaracCompetence('volonte', competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` }) const rolled = await this.doRollCaracCompetence(CARACS.VOLONTE, competence, difficulte, { title: `tente de surmonter l'exotisme de ${item.name}` })
return rolled.isSuccess return rolled.isSuccess
} }
return true; return true;
@@ -1682,7 +1687,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
computeDraconicAndSortIndex(sortList) { computeDraconicAndSortIndex(sortList) {
let draconicList = this.getDraconicList(); let draconicList = this.getDraconics();
for (let sort of sortList) { for (let sort of sortList) {
let draconicsSort = RdDItemSort.getDraconicsSort(draconicList, sort).map(it => it.name); let draconicsSort = RdDItemSort.getDraconicsSort(draconicList, sort).map(it => it.name);
for (let index = 0; index < draconicList.length && sort.system.listIndex == undefined; index++) { for (let index = 0; index < draconicList.length && sort.system.listIndex == undefined; index++) {
@@ -1703,15 +1708,18 @@ export class RdDActor extends RdDBaseActorSang {
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!") ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
return return
} }
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return await this.rollUnSortV2();
}
// Duplication car les pts de reve sont modifiés dans le sort! // 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))) let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
if (sorts.length == 0) { if (sorts.length == 0) {
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`); ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
return; return
} }
const draconicList = this.computeDraconicAndSortIndex(sorts); const draconicList = this.computeDraconicAndSortIndex(sorts)
const reve = foundry.utils.duplicate(this.system.carac.reve); const reve = foundry.utils.duplicate(this.system.carac.reve)
const dialog = await this.openRollDialog({ const dialog = await this.openRollDialog({
name: 'lancer-un-sort', name: 'lancer-un-sort',
@@ -1734,6 +1742,27 @@ export class RdDActor extends RdDBaseActorSang {
this.tmrApp?.setTMRPendingAction(dialog); 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' isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective'
let addMsg = ""; let addMsg = "";
@@ -1805,11 +1834,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
else { else {
console.log('lancement de sort', rollData.selectedSort) console.log('lancement de sort', rollData.selectedSort)
const precedents = rollData.selectedSort.system.lancements ?? [] const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel)
const lancements = [...precedents, {
timestamp: game.system.rdd.calendrier.getTimestamp(),
reve: rollData.selectedSort.system.ptreve_reel
}]
await this.updateEmbeddedDocuments('Item', await this.updateEmbeddedDocuments('Item',
[{ _id: rollData.selectedSort._id, 'system.lancements': lancements }] [{ _id: rollData.selectedSort._id, 'system.lancements': lancements }]
) )
@@ -1922,6 +1947,21 @@ export class RdDActor extends RdDBaseActorSang {
} }
async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) { async rollCaracCompetence(caracName, compName, diff, options = { title: "" }) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_COMP], current: PART_COMP },
selected: {
carac: { key: caracName },
comp: { key: compName, forced: options.forced },
diff: { value: diff ?? 0 }
}
}
RollDialog.create(rollData, foundry.utils.mergeObject(options, { onRollDone: RollDialog.onRollDoneClose }))
return
}
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(compName); const competence = this.getCompetence(compName);
await this.openRollDialog({ await this.openRollDialog({
@@ -1944,23 +1984,34 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollTache(id, options = {}) { async rollTache(id, options = {}) {
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
const tacheData = this.getTache(id) const tache = this.getTache(id)
const compData = this.getCompetence(tacheData.system.competence) if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
compData.system.defaut_carac = tacheData.system.carac; // Patch ! const rollData = {
ids: { actorId: this.id },
selected: { tache: { key: tache.id, forced: options.forced } },
type: { allowed: [PART_TACHE], current: PART_TACHE }
}
RollDialog.create(rollData, options)
return
}
const compData = this.getCompetence(tache.system.competence)
compData.system.defaut_carac = tache.system.carac; // Patch !
await this.openRollDialog({ await this.openRollDialog({
name: 'jet-competence', name: 'jet-competence',
label: 'Jet de Tâche ' + tacheData.name, label: 'Jet de Tâche ' + tache.name,
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.hbs', template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.hbs',
rollData: { rollData: {
competence: compData, competence: compData,
tache: tacheData, tache: tache,
diffLibre: tacheData.system.difficulte, diffLibre: tache.system.difficulte,
diffConditions: 0, diffConditions: 0,
use: { libre: false, conditions: true }, use: { libre: false, conditions: true },
carac: { carac: {
[tacheData.system.carac]: foundry.utils.duplicate(this.system.carac[tacheData.system.carac]) [tache.system.carac]: foundry.utils.duplicate(this.system.carac[tache.system.carac])
} }
}, },
callbacks: [{ action: r => this._tacheResult(r, options) }] callbacks: [{ action: r => this._tacheResult(r, options) }]
@@ -1994,9 +2045,19 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollJeu(id) { async rollJeu(id) {
const oeuvre = this.getJeu(id); const jeu = this.getJeu(id);
const listCarac = oeuvre.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim()); if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { jeu: { key: jeu.id } },
type: { allowed: [ROLL_TYPE_JEU], current: ROLL_TYPE_JEU }
}
await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const listCarac = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim());
const carac = listCarac.length > 0 ? listCarac[0] : 'chance' const carac = listCarac.length > 0 ? listCarac[0] : 'chance'
const artData = { const artData = {
art: 'jeu', verbe: 'Jeu', art: 'jeu', verbe: 'Jeu',
@@ -2006,14 +2067,25 @@ export class RdDActor extends RdDBaseActorSang {
}; };
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]); listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
artData.competence.system.niveauReel = artData.competence.system.niveau; artData.competence.system.niveauReel = artData.competence.system.niveau;
artData.competence.system.niveau = Math.max(artData.competence.system.niveau, oeuvre.system.base); artData.competence.system.niveau = Math.max(artData.competence.system.niveau, jeu.system.base);
await this._rollArtV1(artData, carac, oeuvre); await this._rollArtV1(artData, carac, jeu);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollMeditation(id) { async rollMeditation(id) {
const meditation = foundry.utils.duplicate(this.getMeditation(id)); const meditation = foundry.utils.duplicate(this.getMeditation(id));
if (meditation && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
selected: { meditation: { key: id } },
type: { allowed: [ROLL_TYPE_MEDITATION], current: ROLL_TYPE_MEDITATION }
}
await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence)); const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence));
competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect
let meditationData = { let meditationData = {
@@ -2053,7 +2125,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
_getSignesDraconiques(coord) { _getSignesDraconiques(coord) {
const type = TMRUtility.getTMRType(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));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -2065,18 +2137,19 @@ export class RdDActor extends RdDBaseActorSang {
async rollLireSigneDraconique(coord) { async rollLireSigneDraconique(coord) {
if (!this.isHautRevant()) { if (!this.isHautRevant()) {
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!"); 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) { if (signes.length == 0) {
ui.notifications.info(`Aucun signe draconiques en ${coord} !`); ui.notifications.info(`Aucun signe draconiques en ${coord} !`)
return; return
} }
let draconicList = this.getDraconicList()
let draconicList = this.getDraconics()
.map(draconic => { .map(draconic => {
let draconicLecture = foundry.utils.duplicate(draconic); let draconicLecture = foundry.utils.duplicate(draconic)
draconicLecture.system.defaut_carac = "intellect"; draconicLecture.system.defaut_carac = "intellect"
return draconicLecture; return draconicLecture
}); });
const intellect = this.system.carac.intellect; const intellect = this.system.carac.intellect;
@@ -2350,14 +2423,15 @@ export class RdDActor extends RdDBaseActorSang {
if (this.tmrApp) { if (this.tmrApp) {
ui.notifications.warn("Vous êtes déja dans les TMR....") ui.notifications.warn("Vous êtes déja dans les TMR....")
this.tmrApp.forceTMRDisplay() this.tmrApp.forceTMRDisplay()
return return false
} }
if (mode != 'visu' && this.isDemiReve()) { if (mode != 'visu' && this.isDemiReve()) {
ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation") ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
mode = "visu"; // bascule le mode en visu automatiquement mode = "visu"; // bascule le mode en visu automatiquement
} }
if (mode == 'visu') { if (mode == 'visu') {
await this._doDisplayTMR(mode) await this._doDisplayTMR(mode)
return false
} }
else { else {
const rencontre = this.getRencontreTMREnAttente(); const rencontre = this.getRencontreTMREnAttente();
@@ -2370,6 +2444,7 @@ export class RdDActor extends RdDBaseActorSang {
buttonLabel: 'Monter dans les TMR', buttonLabel: 'Monter dans les TMR',
onAction: async () => await this._doDisplayTMR(mode) onAction: async () => await this._doDisplayTMR(mode)
}) })
return true
} }
} }
@@ -2392,7 +2467,7 @@ export class RdDActor extends RdDBaseActorSang {
let tmrFormData = { let tmrFormData = {
mode: mode, mode: mode,
fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance), fatigue: RdDUtility.calculFatigueHtml(fatigue, endurance),
draconic: this.getDraconicList(), draconic: this.getDraconics(),
sort: this.itemTypes['sort'], sort: this.itemTypes['sort'],
signes: this.itemTypes['signedraconique'], signes: this.itemTypes['signedraconique'],
caracReve: parseInt(this.system.carac.reve.value), caracReve: parseInt(this.system.carac.reve.value),
@@ -2407,6 +2482,29 @@ export class RdDActor extends RdDBaseActorSang {
await this.tmrApp.onDeplacement() 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) { async rollSoins(blesse, blessureId) {
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId); const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
@@ -2414,14 +2512,17 @@ export class RdDActor extends RdDBaseActorSang {
if (!blessure.system.premierssoins.done) { if (!blessure.system.premierssoins.done) {
const tache = await this.getTacheBlessure(blesse, blessure); const tache = await this.getTacheBlessure(blesse, blessure);
return await this.rollTache(tache.id, { return await this.rollTache(tache.id, {
onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r) onRollAutomate: async r => blesse.onRollTachePremiersSoins(blessureId, r),
title: 'Premiers soins',
forced: true
}); });
} }
if (!blessure.system.soinscomplets.done) { else if (!blessure.system.soinscomplets.done) {
const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0); const diff = blessure.system.difficulte + (blessure.system.premierssoins.bonus ?? 0);
return await this.rollCaracCompetence("dexterite", "Chirurgie", diff, { return await this.rollCaracCompetence(CARACS.DEXTERITE, "Chirurgie", diff, {
title: "Soins complets", title: "Soins complets",
onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r) onRollAutomate: r => blesse.onRollSoinsComplets(blessureId, r),
forced: true
}) })
} }
} }
@@ -2436,6 +2537,7 @@ export class RdDActor extends RdDBaseActorSang {
}) })
} }
const blessure = this.getItem(blessureId, 'blessure') const blessure = this.getItem(blessureId, 'blessure')
if (blessure && !blessure.system.premierssoins.done) { if (blessure && !blessure.system.premierssoins.done) {
const tache = rollData.tache; const tache = rollData.tache;
if (rollData.rolled.isETotal) { if (rollData.rolled.isETotal) {
@@ -2916,7 +3018,9 @@ export class RdDActor extends RdDBaseActorSang {
break break
case ITEM_TYPES.race: case ITEM_TYPES.race:
await this.onCreateOwnedRace(item, options, id) await this.onCreateOwnedRace(item, options, id)
break
} }
await super.onCreateItem(item, options, id)
await item.onCreateItemTemporel(this); await item.onCreateItemTemporel(this);
await item.onCreateDecoupeComestible(this); await item.onCreateDecoupeComestible(this);
} }
@@ -3050,24 +3154,11 @@ export class RdDActor extends RdDBaseActorSang {
async _rollArtV2(oeuvreId) { async _rollArtV2(oeuvreId) {
const oeuvre = this.items.get(oeuvreId) const oeuvre = this.items.get(oeuvreId)
const rollData = { const rollData = {
title: `Interpretation de ${oeuvre.name} par ${this.name}`, ids: { actorId: this.id },
type: { selected: { oeuvre: { key: oeuvre.id } },
allowed: ["oeuvre"], type: { allowed: [PART_OEUVRE], current: PART_OEUVRE, },
current: "oeuvre",
},
selected: {
oeuvre: { key: oeuvre.id },
},
ids: {
actorId: this.id
} }
} await RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
await RollDialog.create(rollData, {
onRollDone: (dialog) => {
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
}
})
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -3163,14 +3254,26 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollRecetteCuisine(id) { async rollRecetteCuisine(id) {
const oeuvre = this.getRecetteCuisine(id); const recette = this.getRecetteCuisine(id);
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: recette.id }
}
}
RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
const artData = { const artData = {
verbe: 'Cuisiner', verbe: 'Cuisiner',
compName: 'cuisine', compName: 'cuisine',
proportions: 1, proportions: 1,
ajouterEquipement: false ajouterEquipement: false
}; };
await this._rollArtV1(artData, 'odoratgout', oeuvre, r => this._resultRecetteCuisine(r)); await this._rollArtV1(artData, 'odoratgout', recette, r => this._resultRecetteCuisine(r));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -3203,6 +3306,18 @@ export class RdDActor extends RdDBaseActorSang {
} }
async preparerNourriture(item) { async preparerNourriture(item) {
if (item.getUtilisationCuisine() == 'brut' && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: [PART_CUISINE], current: PART_CUISINE },
selected: {
cuisine: { key: item.id }
}
}
RollDialog.create(rollData, { onRollDone: RollDialog.onRollDoneClose })
return
}
if (item.getUtilisationCuisine() == 'brut') { if (item.getUtilisationCuisine() == 'brut') {
const nourriture = { const nourriture = {
name: 'Plat de ' + item.name, name: 'Plat de ' + item.name,
@@ -3213,7 +3328,7 @@ export class RdDActor extends RdDBaseActorSang {
exotisme: item.system.exotisme, exotisme: item.system.exotisme,
ingredients: item.name ingredients: item.name
} }
}; }
const artData = { const artData = {
verbe: 'Préparer', verbe: 'Préparer',
compName: 'cuisine', compName: 'cuisine',

View File

@@ -1,4 +1,4 @@
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; import { ENTITE_INCARNE, renderTemplate, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js"; import { RdDResolutionTable } from "../rdd-resolution-table.js";
@@ -11,7 +11,7 @@ import { ITEM_TYPES } from "../constants.js";
import { StatusEffects, STATUSES } from "../settings/status-effects.js"; import { StatusEffects, STATUSES } from "../settings/status-effects.js";
import { Targets } from "../targets.js"; import { Targets } from "../targets.js";
import { RdDConfirm } from "../rdd-confirm.js"; import { RdDConfirm } from "../rdd-confirm.js";
import { RdDCarac } from "../rdd-carac.js"; import { CARACS, RdDCarac } from "../rdd-carac.js";
import { RdDRollResult } from "../rdd-roll-result.js"; import { RdDRollResult } from "../rdd-roll-result.js";
import { RdDItemArme } from "../item/arme.js"; import { RdDItemArme } from "../item/arme.js";
@@ -23,8 +23,12 @@ import { RdDCombat } from "../rdd-combat.js";
import { RdDEmpoignade } from "../rdd-empoignade.js"; import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDPossession } from "../rdd-possession.js"; import { RdDPossession } from "../rdd-possession.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, POSSESSION_SANS_DRACONIC } from "../item/base-items.js";
import { RollDataAjustements } from "../rolldata-ajustements.js"; import { RollDataAjustements } from "../rolldata-ajustements-v1.js";
import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs"; import { MappingCreatureArme } from "../item/mapping-creature-arme.mjs";
import RollDialog from "../roll/roll-dialog.mjs";
import { ATTAQUE_ROLL_TYPES, DEFAULT_ROLL_TYPES, DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_COMP, ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE } from "../roll/roll-constants.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "../settings/options-avancees.js";
import { PART_COMP } from "../roll/roll-part-comp.mjs";
/** /**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets) * Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
@@ -242,10 +246,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (this.isEffectAllowed(statusId)) { if (this.isEffectAllowed(statusId)) {
const effect = this.getEffectByStatus(statusId); const effect = this.getEffectByStatus(statusId);
if (!status && effect) { if (!status && effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]); await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id], { render: true})
} }
if (status && !effect) { if (status && !effect) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]); await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true})
} }
} }
} }
@@ -377,9 +381,22 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCarac(caracName, options = {}) { async rollCarac(caracName, options = {}) {
if (Grammar.equalsInsensitive(caracName, 'taille')) { if (Grammar.equalsInsensitive(caracName, CARACS.TAILLE)) {
return return
} }
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
ids: { actorId: this.id },
type: { allowed: DEFAULT_ROLL_TYPES, current: PART_COMP },
selected: {
carac: { key: caracName },
comp: options.resistance ? { key: undefined, forced: true } : undefined
}
}
RollDialog.create(rollData, options)
return
}
foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false }) foundry.utils.mergeObject(options, { resistance: false, diff: 0 }, { overwrite: false })
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName) let selectedCarac = this.getCaracByName(caracName)
@@ -407,9 +424,33 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCompetenceV2(rollData) {
rollData.ids = rollData?.ids ?? {}
rollData.type = rollData.type ?? { allowed: DEFAULT_ROLL_TYPES }
rollData.ids.actorId = this.id
await RollDialog.create(rollData)
}
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) { async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName); const competence = this.getCompetence(idOrName);
if (competence.type != ITEM_TYPES.competencecreature && OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
const rollData = {
selected: {
comp: { key: competence.name },
diff: { type: DIFF.LIBRE, value: competence.system.default_diffLibre ?? 0 }
}
}
if (options.arme) {
rollData.selected.attaque = { arme: { id: options.arme.id }, comp: { id: competence.id } }
rollData.type = { allowed: ATTAQUE_ROLL_TYPES }
}
await this.rollCompetenceV2(rollData)
return
}
let rollData = { let rollData = {
carac: this.system.carac, carac: this.system.carac,
competence: competence, competence: competence,
@@ -427,7 +468,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme) RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
} }
}); });
return; return
} }
// Transformer la competence de créature // Transformer la competence de créature
MappingCreatureArme.setRollDataCreature(rollData) MappingCreatureArme.setRollDataCreature(rollData)
@@ -449,6 +490,46 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
} }
rollAttaque(token) {
token = token ?? RdDUtility.getSelectedToken(this)
if (Targets.hasTargets()) {
Targets.selectOneTargetToken(target => {
if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée!!!!`)
return
}
RdDCombat.rddCombatTarget(target, this, token).attaqueV2();
})
}
else {
return RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
content: `<p>Voulez vous faire une attaque sans choisir de cible valide?
<br>Tous les jets de combats devront être gérés à la main
</p>`,
title: 'Ne pas utiliser les automatisation de combat',
buttonLabel: "Pas d'automatisation",
onAction: async () => {
this.rollCompetenceV2({
ids: {
actorId: this.id,
actorTokenId: token?.id,
},
selected: {
conditions: { value: 0 }
},
type: {
allowed: [ROLL_TYPE_COMP, ROLL_TYPE_ATTAQUE, ROLL_TYPE_OEUVRE, ROLL_TYPE_TACHE, ROLL_TYPE_JEU],
current: ROLL_TYPE_COMP
}
})
}
})
}
}
/** -------------------------------------------- /** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature * @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession * @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession

View File

@@ -116,6 +116,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
blessure: blessure blessure: blessure
}); });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async santeIncDec(name, inc, isCritique = false) { async santeIncDec(name, inc, isCritique = false) {
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) { if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
@@ -161,7 +162,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) { if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin()); sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
} }
await this.update({ "system.sante": sante }) await this.update({ "system.sante": sante }, { render: true })
if (this.isDead()) { if (this.isDead()) {
await this.setEffect(STATUSES.StatusComma, true); await this.setEffect(STATUSES.StatusComma, true);
} }
@@ -179,6 +180,26 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques)); 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) { async ajouterBlessure(encaissement, attackerToken = undefined) {
@@ -195,7 +216,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
const endActuelle = this.getEnduranceActuelle(); const endActuelle = this.getEnduranceActuelle();
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken); const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
if (blessure.isCritique()) { if (blessure.isCritique()) {
encaissement.endurance = endActuelle; encaissement.endurance = endActuelle
} }
if (blessure.isMort()) { if (blessure.isMort()) {

View File

@@ -56,10 +56,8 @@ export class RdDBaseActorSheet extends foundry.appv1.sheets.ActorSheet {
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires); this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs); formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature) formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
.forEach(it => { .forEach(it => it.isdommages = it.isDommages()
const competenceCreature = new RdDItemCompetenceCreature(it.toObject(), { parent: it.parent }); )
it.isdommages = competenceCreature.isDommages();
})
return formData; return formData;
} }

View File

@@ -1,6 +1,6 @@
import { ChatVente } from "../achat-vente/chat-vente.js"; import { ChatVente } from "../achat-vente/chat-vente.js";
import { ChatUtility } from "../chat-utility.js"; import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js"; import { renderTemplate, SYSTEM_SOCKET_ID } from "../constants.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { Monnaie } from "../item-monnaie.js"; import { Monnaie } from "../item-monnaie.js";
import { ITEM_TYPES } from "../constants.js"; import { ITEM_TYPES } from "../constants.js";
@@ -10,6 +10,7 @@ import { RdDConfirm } from "../rdd-confirm.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js"; import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDItem } from "../item.js"; import { RdDItem } from "../item.js";
import { STATUSES } from "../settings/status-effects.js";
export class RdDBaseActor extends Actor { export class RdDBaseActor extends Actor {
@@ -45,8 +46,10 @@ export class RdDBaseActor extends Actor {
} }
static init() { static init() {
Handlebars.registerHelper('actor-isFeminin', actor => actor.isFeminin())
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id)) Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id)) Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("updateItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onUpdateItem(item, options, id))
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id)) Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId)) Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
} }
@@ -218,6 +221,7 @@ export class RdDBaseActor extends Actor {
isHautRevant() { return false } isHautRevant() { return false }
isVehicule() { return false } isVehicule() { return false }
isPersonnage() { return false } isPersonnage() { return false }
isFeminin() { return false }
getItem(id, type = undefined) { getItem(id, type = undefined) {
const item = this.items.get(id); const item = this.items.get(id);
if (type == undefined || (item?.type == type)) { if (type == undefined || (item?.type == type)) {
@@ -243,8 +247,13 @@ export class RdDBaseActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { } async onPreUpdateItem(item, change, options, id) { }
async onCreateItem(item, options, id) { } async onCreateItem(item, options, id) { }
async onUpdateItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { } async onUpdateActor(update, options, actorId) { }
async onDeleteItem(item, options, id) { async onDeleteItem(item, options, id) {
if (item.isInventaire()) { if (item.isInventaire()) {
await this._removeItemFromConteneur(item) await this._removeItemFromConteneur(item)
@@ -738,7 +747,7 @@ export class RdDBaseActor extends Actor {
name: this.getAlias(), name: this.getAlias(),
system: { description: this.system.description } system: { description: this.system.description }
} }
foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData) renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.hbs', chatData)
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride))); .then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
} }
@@ -769,11 +778,15 @@ export class RdDBaseActor extends Actor {
return this.itemTypes[ITEM_TYPES.possession] return this.itemTypes[ITEM_TYPES.possession]
.map(p => { .map(p => {
return { return {
name: p.name, label: p.name,
action: 'possession', action: 'possession',
possessionid: p.system.possessionid, possessionid: p.system.possessionid,
} }
}) })
} }
listActionsCombat() {
const possessions = this.listActionsPossessions()
return possessions.length > 0 ? possessions : this.listActions({})
} }
}

View File

@@ -1,5 +1,5 @@
import { Grammar } from "../../grammar.js" import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item/arme.js" import { EMPOIGNADE, RdDItemArme } from "../../item/arme.js"
import { RdDItemCompetence } from "../../item-competence.js" import { RdDItemCompetence } from "../../item-competence.js"
import { RdDItemSort } from "../../item-sort.js" import { RdDItemSort } from "../../item-sort.js"
import { ITEM_TYPES } from "../../constants.js" import { ITEM_TYPES } from "../../constants.js"
@@ -141,7 +141,7 @@ export class Mapping {
static prepareArmes(actor) { static prepareArmes(actor) {
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme) const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
armes.push(RdDItemArme.corpsACorps(actor)); armes.push(RdDItemArme.pugilat(actor));
armes.push(RdDItemArme.empoignade(actor)); armes.push(RdDItemArme.empoignade(actor));
return armes.map(arme => [ return armes.map(arme => [
arme.system.unemain ? Mapping.prepareArme(actor, arme, '(1 main)') : undefined, arme.system.unemain ? Mapping.prepareArme(actor, arme, '(1 main)') : undefined,
@@ -175,7 +175,7 @@ export class Mapping {
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme)) const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
switch (arme.system.mortalite) { switch (arme.system.mortalite) {
case 'non-mortel': return `(${dommages})` case 'non-mortel': return `(${dommages})`
case 'empoignade': return '-' case EMPOIGNADE: return '-'
} }
return dommages return dommages
} }
@@ -274,11 +274,10 @@ export class Mapping {
} }
static getDescription(actor) { static getDescription(actor) {
const sexe = actor.system.sexe const naissance = actor.isFeminin() ? 'née' : 'né'
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ') const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
const heure = actor.system.heure const heure = actor.system.heure
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}` const hn = `${naissance} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
const age = (actor.system.age && actor.system.age >0) ? `${actor.system.age} ans` : undefined const age = (actor.system.age && actor.system.age >0) ? `${actor.system.age} ans` : undefined
const taille = actor.system.taille const taille = actor.system.taille
const poids = actor.system.poids const poids = actor.system.poids

View File

@@ -20,14 +20,15 @@ const PATHS = [
const RANDOM_VALUES = { const RANDOM_VALUES = {
'system.sexe': { 'masculin': 1, 'féminin': 1 }, 'system.sexe': { 'masculin': 1, 'féminin': 1 },
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 }, '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.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, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 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 { export class AppPersonnageAleatoire extends FormApplication {
static preloadHandlebars() { static preloadHandlebars() {
foundry.applications.handlebars.loadTemplates([ foundry.applications.handlebars.loadTemplates([
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs', '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.current = foundry.utils.duplicate(actor)
this.checked = { this.checked = {
'name': false, 'name': false,
'system.sexe': true, 'system.sexe': (this.actor.system.sexe ?? '') == '',
'system.age': true, 'system.age': this.actor.system.age == 0,
'system.taille': true, 'system.taille': (this.actor.system.taille ?? '') == '',
'system.poids': true, 'system.poids': (this.actor.system.poids ?? '') == '',
'system.main': true, 'system.main': (this.actor.system.main ?? '') == '',
'system.heure': true, 'system.heure': (this.actor.system.heure ?? '') == '',
'system.cheveux': true, 'system.cheveux': (this.actor.system.cheveux ?? '') == '',
'system.yeux': true '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("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("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("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.random").click(async event => await this.onRandom(event))
this.html.find("a.reset").click(async event => await this.onReset(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()) 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") const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value return fields[0].attributes['data-path'].value
} }
async onSexe(sexe) {
this.current['system.sexe'] = sexe
this.render()
}
async onChange(event) { async onChange(event) {
const path = this.getPath(event.currentTarget) 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 variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`) const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100 const cm = total % 100
const dm = cm < 10 ? '0' : ''
const m = (total - cm) / 100 const m = (total - cm) / 100
return `${m}m${cm}` return `${m}m${dm}${cm}`
} }

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "../../constants.js";
export class TextRollManager { export class TextRollManager {

View File

@@ -1,5 +1,5 @@
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js"; import { RdDTextEditor } from "./apps/rdd-text-roll-editor.js";
@@ -106,6 +106,25 @@ export class ChatUtility {
return await ChatMessage.create(messageData) 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) { static getOwners(document) {
return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user] return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user]
} }
@@ -190,8 +209,8 @@ export class ChatUtility {
if (rddTimestamp) { if (rddTimestamp) {
const timestamp = new RdDTimestamp(rddTimestamp); const timestamp = new RdDTimestamp(rddTimestamp);
const timestampData = timestamp.toCalendrier(); const timestampData = timestamp.toCalendrier();
const dateHeure = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData); const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
$(html).find('header.message-header .message-sender').after(dateHeure) $(html).find('header.message-header .message-timestamp').after(dateHeure)
} }
} }

View File

@@ -1,5 +1,6 @@
import { RdDBaseActor } from "../actor/base-actor.js"; import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js"; import { ChatUtility } from "../chat-utility.js";
import { renderTemplate } from "../constants.js";
const INFO_COEUR = 'info-coeur'; const INFO_COEUR = 'info-coeur';

View File

@@ -9,6 +9,8 @@ export const ENTITE_INCARNE = 'incarne'
export const ENTITE_NONINCARNE = 'nonincarne' export const ENTITE_NONINCARNE = 'nonincarne'
export const ENTITE_BLURETTE = 'blurette' export const ENTITE_BLURETTE = 'blurette'
export const renderTemplate = foundry.applications.handlebars.renderTemplate
export const RDD_CONFIG = { export const RDD_CONFIG = {
niveauEthylisme: [ niveauEthylisme: [
{ value: "1", label: "Aucun" }, { value: "1", label: "Aucun" },
@@ -31,26 +33,32 @@ export const RDD_CONFIG = {
"blurette": "Blurette" "blurette": "Blurette"
}, },
heuresRdD: [ heuresRdD: [
{value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"}, { value: "vaisseau", label: "Vaisseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd01.webp" },
{value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"}, { value: "sirene", label: "Sirène", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd02.webp" },
{value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"}, { value: "faucon", label: "Faucon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd03.webp" },
{value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"}, { value: "couronne", label: "Couronne", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd04.webp" },
{value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"}, { value: "dragon", label: "Dragon", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd05.webp" },
{value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"}, { value: "epees", label: "Epées", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd06.webp" },
{value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"}, { value: "lyre", label: "Lyre", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd07.webp" },
{value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"}, { value: "serpent", label: "Serpent", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd08.webp" },
{value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"}, { value: "poissonacrobate", label: "Poisson Acrobate", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd09.webp" },
{value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"}, { value: "araignee", label: "Araignée", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd10.webp" },
{value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"}, { value: "roseau", label: "Roseau", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd11.webp" },
{value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"} { value: "chateaudormant", label: "Chateau Dormant", img: "systems/foundryvtt-reve-de-dragon/icons/heures/hd12.webp" }
], ],
raretes: [ raretes: [
{ value: "Commune", label: "Commune" }, { value: "Commune", label: "Commune" },
{ value: "Frequente", label: "Fréquente" }, { value: "Frequente", label: "Fréquente" },
{ value: "Rare", label: "Rare" }, { value: "Rare", label: "Rare" },
{ value: "Rarissime", label: "Rarissime" } { value: "Rarissime", label: "Rarissime" }
] ],
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: 'rapidite', descr: 'en rapidité', img: 'systems/foundryvtt-reve-de-dragon/assets/ui/part-rapidite.svg'},
} }
}
export const ACTOR_TYPES = { export const ACTOR_TYPES = {
personnage: 'personnage', personnage: 'personnage',
@@ -107,13 +115,3 @@ export const ITEM_TYPES = {
extraitpoetique: 'extraitpoetique', extraitpoetique: 'extraitpoetique',
} }
export const CATEGORIES_COMPETENCES = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconic" },
"melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" }
}

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js"
export class DialogChoixXpCarac extends Dialog { export class DialogChoixXpCarac extends Dialog {

View File

@@ -1,4 +1,4 @@
import { SYSTEM_RDD } from "./constants.js"; import { renderTemplate, SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";

View File

@@ -1,4 +1,5 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js"; import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog { export class DialogConsommer extends Dialog {

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js"
export class DialogSelect extends Dialog { export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } } static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }

View File

@@ -1,4 +1,4 @@
import { Misc } from "./misc.js"; import { renderTemplate } from "./constants.js";
export class DialogSplitItem extends Dialog { export class DialogSplitItem extends Dialog {

View File

@@ -1,4 +1,4 @@
import { HIDE_DICE, SHOW_DICE } from "./constants.js"; import { HIDE_DICE, renderTemplate, SHOW_DICE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
/** /**

View File

@@ -1,4 +1,4 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES, renderTemplate } from "../constants.js"
import { RdDItemSort } from "../item-sort.js" import { RdDItemSort } from "../item-sort.js"
import { Misc } from "../misc.js" import { Misc } from "../misc.js"

View File

@@ -1,7 +1,65 @@
export const MAP_PHASE = {
possession: { label: "possession", rang: 10 },
draconic: { label: "draconic", rang: 9 },
tir: { label: "tir", rang: 8 },
lancer: { label: "lancer", rang: 7 },
arme: { label: "mêlée", rang: 5 },
pugilat: { label: "pugilat", rang: 4 },
naturelle: { label: "créature", rang: 4 },
empoignade: { label: "empoignade", rang: 3 },
autre: { label: "autre action", rang: 2 },
demi: { label: "demi-surprise", rang: 0 },
totale: { label: "surprise totale", rang: -1 },
}
export const PHASE = Object.values(MAP_PHASE)
export class RdDInitiative { export class RdDInitiative {
static calculInitiative(niveau, caracValue, bonus = 0) { static getRollInitiative(caracValue, niveau, bonus = 0) {
let base = niveau + Math.floor(caracValue / 2) + bonus; const base = RdDInitiative.ajustementInitiative(caracValue, niveau, bonus)
return "1d6" + (base >= 0 ? "+" : "") + base; return "1d6" + (base >= 0 ? "+" : "") + base
}
static ajustementInitiative(caracValue, niveau, bonus) {
return niveau + Math.floor(caracValue / 2) + bonus
}
static formule(phase, carac, niveau, bonusMalus) {
const ajustement = RdDInitiative.ajustementInitiative(carac, niveau, bonusMalus)
return { phase, ajustement }
}
static phaseArme(categorie, arme) {
switch (categorie) {
case "tir":
case "lancer":
return MAP_PHASE[categorie]
default:
switch (arme.system.cac) {
case "empoignade":
case "pugilat":
case "naturelle":
return MAP_PHASE[arme.system.cac]
default:
return MAP_PHASE['arme']
}
}
}
static phase(keyOrRang) {
return MAP_PHASE[keyOrRang] ?? PHASE.find(it => it.rang == keyOrRang) ?? MAP_PHASE.autre
}
static async roll(formule) {
const sign = formule.ajustement >= 0 ? "+" : ""
const roll = new Roll(`1d6 + ${sign} + ${formule.ajustement}`)
await roll.evaluate()
const value = Math.max(roll.total, 0)
return {
roll: roll,
value: value,
init: formule.phase.rang + value / 100,
label: formule.phase.label
}
} }
} }

View File

@@ -10,15 +10,15 @@ export class RdDItemCompetenceCreature extends RdDItem {
static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" } static get defaultIcon() { return "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp" }
isAttaque() { return this.getCategorieAttaque() != undefined }
isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' } isParade() { return this.system.iscombat && (this.system.categorie_parade ?? '') != '' }
isBouclier() { return this.system.categorie_parade.includes('bouclier') } isBouclier() { return this.system.categorie_parade.includes('bouclier') }
attaqueCreature() { attaqueCreature() {
const categorieAttaque = this.getCategorieAttaque() const categorieAttaque = this.getCategorieAttaque()
if (categorieAttaque != undefined) { if (categorieAttaque != undefined) {
const initative = RdDInitiative.calculInitiative(this.system.niveau, this.system.carac_value); const initative = RdDInitiative.getRollInitiative(this.system.carac_value, this.system.niveau);
const attaque = { const attaque = {
name: this.name, label: this.name,
action: this.isCompetencePossession() ? 'possession' : 'attaque', action: this.isCompetencePossession() ? 'possession' : 'attaque',
initOnly: false, initOnly: false,
arme: new RdDItemArme({ arme: new RdDItemArme({
@@ -51,10 +51,6 @@ export class RdDItemCompetenceCreature extends RdDItem {
return undefined; return undefined;
} }
isAttaque() {
return this.getCategorieAttaque() != undefined
}
getCategorieAttaque() { getCategorieAttaque() {
switch (this.system.categorie) { switch (this.system.categorie) {
case "melee": case "melee":

View File

@@ -148,10 +148,17 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static incrementBonusCase(actor, sort, coord) { static incrementBonusCase(actor, sort, coord) {
if (TMRUtility.isFleuve(coord)) { let bonuscase = RdDItemSort.calculBonuscase(sort, coord)
coord = FLEUVE_COORD;
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
} }
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase);
static calculBonuscase(sort, coord) {
if (TMRUtility.isFleuve(coord)) {
coord = FLEUVE_COORD
}
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
const existing = list.find(it => it.case == coord) const existing = list.find(it => it.case == coord)
const bonus = Number(existing?.bonus ?? 0) + 1 const bonus = Number(existing?.bonus ?? 0) + 1
if (existing) { if (existing) {
@@ -160,11 +167,9 @@ export class RdDItemSort extends Item {
else { else {
list.push({ case: coord, bonus: 1 }) list.push({ case: coord, bonus: 1 })
} }
return RdDItemSort.bonuscasesToString(list)
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCaseBonus(sort, coord) { static getCaseBonus(sort, coord) {
const search = TMRUtility.isFleuve(coord) const search = TMRUtility.isFleuve(coord)
@@ -189,4 +194,22 @@ export class RdDItemSort extends Item {
.map(it => it.split(':')) .map(it => it.split(':'))
.map(it => { return { case: it[0], bonus: it[1] } }); .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
}
} }

View File

@@ -1,4 +1,4 @@
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES, renderTemplate } from "./constants.js";
import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js"; import { BASE_CORPS_A_CORPS, BASE_ESQUIVE, CATEGORIES_COMPETENCES, CATEGORIES_COMPETENCES_CREATURES } from "./item/base-items.js";
import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js"; import { ITEM_ACTIONS, DEFAULT_ACTIONS, COMMON_ACTIONS } from "./item/item-actions.js";

View File

@@ -4,6 +4,7 @@ import { BASE_CORPS_A_CORPS } from "./base-items.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { RdDInitiative } from "../initiative.mjs"; import { RdDInitiative } from "../initiative.mjs";
import { MappingCreatureArme } from "./mapping-creature-arme.mjs"; import { MappingCreatureArme } from "./mapping-creature-arme.mjs";
import { Misc } from "../misc.js";
const nomCategorieParade = { const nomCategorieParade = {
"sans-armes": "Sans arme", "sans-armes": "Sans arme",
@@ -21,11 +22,16 @@ const nomCategorieParade = {
export const ATTAQUE_TYPE = { export const ATTAQUE_TYPE = {
UNE_MAIN: '(1 main)', UNE_MAIN: '(1 main)',
DEUX_MAINS: '(2 mains)', DEUX_MAINS: '(2 mains)',
CORPS_A_CORPS: '(corps à corps)',
COMPETENCE: 'competence', COMPETENCE: 'competence',
TIR: '(tir)', TIR: '(tir)',
LANCER: '(lancer)' LANCER: '(lancer)'
} }
export const CORPS_A_CORPS = 'Corps à corps'
export const PUGILAT = 'pugilat'
export const EMPOIGNADE = 'empoignade'
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemArme extends RdDItem { export class RdDItemArme extends RdDItem {
@@ -62,7 +68,7 @@ export class RdDItemArme extends RdDItem {
case ITEM_TYPES.competencecreature: case ITEM_TYPES.competencecreature:
return MappingCreatureArme.armeCreature(arme); return MappingCreatureArme.armeCreature(arme);
} }
return RdDItemArme.corpsACorps(); return RdDItemArme.pugilat();
} }
static getCompetenceArme(arme, maniement) { static getCompetenceArme(arme, maniement) {
@@ -76,6 +82,7 @@ export class RdDItemArme extends RdDItem {
case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains() case ATTAQUE_TYPE.DEUX_MAINS: return arme.competence2Mains()
case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir case ATTAQUE_TYPE.TIR: case 'tir': return arme.system.tir
case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer; case ATTAQUE_TYPE.LANCER: case 'lancer': return arme.system.lancer;
case ATTAQUE_TYPE.CORPS_A_CORPS: return CORPS_A_CORPS
} }
} }
return undefined return undefined
@@ -244,47 +251,41 @@ export class RdDItemArme extends RdDItem {
} }
isAttaque() { isAttaque() {
return this.system.resistance > 0 || this.system.portee_courte > 0 return this.system.resistance > 0 || (this.system.tir != '' && this.system.portee_courte > 0)
} }
static corpsACorps(actor) { static pugilat(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS return RdDItemArme.$corpsACorps(actor, 'Pugilat', PUGILAT)
let melee = actor ? actor.system.carac['melee'].value : 0 }
static empoignade(actor) {
return RdDItemArme.$corpsACorps(actor, 'Empoignade', EMPOIGNADE)
}
static $corpsACorps(actor, name, cac, system) {
const competence = actor?.getCompetenceCorpsACorps() ?? BASE_CORPS_A_CORPS
const melee = actor ? actor.system.carac['melee'].value : 0
return new RdDItemArme({ return new RdDItemArme({
_id: competence.id, _id: Misc.fakeId(cac),
name: 'Corps à corps', name: name,
type: ITEM_TYPES.arme, type: ITEM_TYPES.arme,
img: competence.img, img: competence.img,
system: { system: {
initiative: RdDInitiative.calculInitiative(competence.system.niveau, melee), initiative: RdDInitiative.getRollInitiative(melee, competence.system.niveau),
equipe: true, equipe: true,
rapide: true, rapide: true,
force: 0, force: 0,
dommages: "0", dommages: "0",
dommagesReels: 0, dommagesReels: 0,
mortalite: 'non-mortel', mortalite: cac == EMPOIGNADE ? EMPOIGNADE : 'non-mortel',
competence: 'Corps à corps', competence: CORPS_A_CORPS,
resistance: 1, resistance: 1,
baseInit: 4, baseInit: cac == EMPOIGNADE ? 3 : 4,
cac: 'pugilat', cac: cac,
deuxmains: true, deuxmains: true,
categorie_parade: 'sans-armes' categorie_parade: 'sans-armes'
} }
}) })
} }
static mainsNues(actor) {
const mainsNues = RdDItemArme.corpsACorps(actor)
mainsNues.name = 'Mains nues'
return mainsNues;
}
static empoignade(actor) {
const empoignade = RdDItemArme.corpsACorps(actor)
empoignade.name = 'Empoignade'
empoignade.system.cac = 'empoignade'
empoignade.system.baseInit = 3
empoignade.system.mortalite = 'empoignade'
return empoignade
}
} }

View File

@@ -209,6 +209,9 @@ export class RdDItemBlessure extends RdDItem {
isCritique() { isCritique() {
return this.system.gravite > 4 && this.system.gravite <= 6 return this.system.gravite > 4 && this.system.gravite <= 6
} }
isBleeding() {
return this.system.gravite > 2 && !this.system.premierssoins.done
}
isMort() { isMort() {
return this.system.gravite > 6 return this.system.gravite > 6
} }

View File

@@ -3,7 +3,6 @@ import { RdDInitiative } from "../initiative.mjs";
export class MappingCreatureArme { export class MappingCreatureArme {
/* -------------------------------------------- */ /* -------------------------------------------- */
static setRollDataCreature(rollData) { static setRollDataCreature(rollData) {
const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name); const code = Grammar.toLowerCaseNoAccentNoSpace(rollData.competence.name);
@@ -26,7 +25,7 @@ export class MappingCreatureArme {
competence: item.name, competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "", cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau, niveau: item.system.niveau,
initiative: RdDInitiative.calculInitiative(item.system.niveau, item.system.carac_value), initiative: RdDInitiative.getRollInitiative(item.system.carac_value, item.system.niveau),
equipe: true, equipe: true,
resistance: 100, resistance: 100,
dommagesReels: item.system.dommages, dommagesReels: item.system.dommages,

View File

@@ -6,8 +6,8 @@ const tableEffets = [
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur}, { code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force}, { code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase }, { code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete }, { code: "part+tete", resultat: "succes", description: "Tête de dragon sur particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere }, { code: "part+xp", resultat: "succes", description: "Expérience sur particulière", method: EffetsRencontre.experience_particuliere },
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil }, { code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 }, { code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
@@ -19,7 +19,7 @@ const tableEffets = [
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire }, { code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire }, { code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu }, { code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue }, { code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon", method: EffetsRencontre.rdd_echec_queue },
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 }, { code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force }, { code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },

View File

@@ -35,8 +35,12 @@ export class Misc {
} }
static inRange(value, min, max) { static inRange(value, min, max) {
if (min > max) {
return Misc.inRange(value, max, min)
}
return Math.max(min, Math.min(value, max)) return Math.max(min, Math.min(value, max))
} }
static sum() { static sum() {
return (a, b) => Number(a) + Number(b); return (a, b) => Number(a) + Number(b);
} }
@@ -61,6 +65,10 @@ export class Misc {
return 0; return 0;
} }
static fakeId(base) {
return (base + foundry.utils.randomID(16)).substring(0, 16)
}
static typeName(type, subType) { static typeName(type, subType) {
return subType ? game.i18n.localize(`TYPES.${type}.${subType}`) return subType ? game.i18n.localize(`TYPES.${type}.${subType}`)
: ''; : '';
@@ -111,6 +119,10 @@ export class Misc {
list.forEach(it => addToObj(obj, it)) list.forEach(it => addToObj(obj, it))
return obj; return obj;
} }
static indexed(list, index = 'index') {
let i = 0;
return list.map(it => { it[index] = i++; return it })
}
static concat(lists) { static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []); return lists.reduce((a, b) => a.concat(b), []);

View File

@@ -47,7 +47,7 @@ export class RdDBonus {
penetration: RdDBonus._peneration(rollData), penetration: RdDBonus._peneration(rollData),
dmgTactique: RdDBonus.dmgBonus(rollData.tactique), dmgTactique: RdDBonus.dmgBonus(rollData.tactique),
dmgParticuliere: RdDBonus._dmgParticuliere(rollData), dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used), dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris?.used),
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee), mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme), dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme),
dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise) dmgForceInsuffisante: Math.min(0, actor.getForce() - forceRequise)
@@ -56,20 +56,19 @@ export class RdDBonus {
return dmg; return dmg;
} }
static dmgRollV2(rollData, current) { static dmgRollV2(rollData, attaque) {
const actor = rollData.active.actor const actor = rollData.active.actor
const attaque = current.attaque
const arme = attaque.arme const arme = attaque.arme
const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme) const dmgArme = RdDBonus.dmgArme(arme, attaque.dommagesArme)
const dmg = { const dmg = {
total: 0, total: 0,
dmgArme: dmgArme, dmgArme: dmgArme,
penetration: arme.penetration(), penetration: arme?.penetration() ?? 0,
diff: attaque.diff, diff: attaque.diff,
dmgTactique: current.tactique?.dmg ?? 0, dmgTactique: attaque.tactique?.dmg ?? 0,
dmgParticuliere: 0, // TODO RdDBonus._dmgParticuliere(rollData), dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0, dmgSurprise: rollData.opponent?.surprise?.dmg ?? 0,
mortalite: RdDBonus.mortalite(current.dmg?.mortalite, arme.system.mortalite, rollData.opponent?.actor?.isEntite()), mortalite: RdDBonus.mortalite(attaque.dmg?.mortalite, arme?.system.mortalite, rollData.opponent?.actor?.isEntite()),
dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise), dmgActor: RdDBonus.bonusDmg(actor, attaque.carac.key, dmgArme, attaque.forceRequise),
dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise), dmgForceInsuffisante: Math.min(0, actor.getForce() - attaque.forceRequise),
dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0 dmgDiffLibre: ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(attaque.diff ?? 0) : 0

View File

@@ -1,5 +1,5 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { ENTITE_BLURETTE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { ENTITE_BLURETTE, HIDE_DICE, renderTemplate, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js"; import { RdDBonus } from "./rdd-bonus.js";
@@ -10,15 +10,15 @@ import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Targets } from "./targets.js"; import { Targets } from "./targets.js";
import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDItemArme } from "./item/arme.js"; import { EMPOIGNADE, RdDItemArme } from "./item/arme.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDInitiative } from "./initiative.mjs"; import { MAP_PHASE, RdDInitiative } from "./initiative.mjs";
import RollDialog from "./roll/roll-dialog.mjs"; import RollDialog from "./roll/roll-dialog.mjs";
import { PART_DEFENSE } from "./roll/roll-part-defense.mjs"; import { PART_DEFENSE } from "./roll/roll-part-defense.mjs";
import { RollDialogAdapter } from "./roll/roll-dialog-adapter.mjs"; import { DIFF, ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs";
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll/roll-constants.mjs"; import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs"; import { MappingCreatureArme } from "./item/mapping-creature-arme.mjs";
import { RollBasicParts } from "./roll/roll-basic-parts.mjs";
/* -------------------------------------------- */ /* -------------------------------------------- */
const premierRoundInit = [ const premierRoundInit = [
@@ -67,7 +67,7 @@ export class RdDCombatManager extends Combat {
if (Misc.isFirstConnectedGM()) { if (Misc.isFirstConnectedGM()) {
await this.finDeRound({ terminer: true }) await this.finDeRound({ terminer: true })
ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`) ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`)
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined) game.messages.filter(m => ChatUtility.getMessageData(m, 'rollData') != undefined && ChatUtility.getMessageData(m, 'rollData') != undefined)
.forEach(it => it.delete()) .forEach(it => it.delete())
RdDEmpoignade.deleteAllEmpoignades() RdDEmpoignade.deleteAllEmpoignades()
} }
@@ -106,14 +106,18 @@ export class RdDCombatManager extends Combat {
return combatant.actor return combatant.actor
} }
static calculAjustementInit(actor, arme) { static bonusArme(arme) {
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0 return (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
const etatGeneral = actor.getEtatGeneral() ?? 0
return efficacite + etatGeneral
} }
/************************************************************************************/ static etatGeneral(actor) {
return actor.getEtatGeneral() ?? 0;
}
/** ***********************************************************************************
* @override lance l'initiative de plusieurs combattants (tous/ous les PNJs) en une fois
*/
async rollInitiative(ids, messageOptions = {}) { async rollInitiative(ids, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions) console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
ids = typeof ids === "string" ? [ids] : ids ids = typeof ids === "string" ? [ids] : ids
@@ -121,18 +125,17 @@ export class RdDCombatManager extends Combat {
return this return this
} }
async rollInitRdD(id, formula, messageOptions = {}) { async rollInitRdD(id, formule, messageOptions = {}) {
const combatant = this.combatants.get(id); const combatant = this.combatants.get(id);
const actor = RdDCombatManager.getActorCombatant(combatant) const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor) { if (actor) {
const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor) formule = formule ?? RdDCombatManager.getFirstInitRollFormula(actor)
const roll = combatant.getInitiativeRoll(rollFormula); const init = await RdDInitiative.roll(formule)
if (!roll.total) {
await roll.evaluate(); await this.updateEmbeddedDocuments("Combatant", [{
} _id: combatant._id || combatant.id,
const total = Math.max(roll.total, 0.00); initiative: init.init, 'system.init': init
console.log("Compute init for", rollFormula, roll, total, combatant); }])
await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]);
// Send a chat message // Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode"); let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
@@ -144,10 +147,10 @@ export class RdDCombatManager extends Combat {
alias: combatant.token?.name, alias: combatant.token?.name,
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
}, },
flavor: `${combatant.token?.name} a fait son jet d'Initiative (${messageOptions.info})<br>` flavor: `${combatant.token?.name} a une initiatyive de ${init.value} : ${messageOptions.info}<br>`
}, },
messageOptions); messageOptions);
roll.toMessage(messageData, { rollMode, create: true }); init.roll.toMessage(messageData, { rollMode, create: true });
RdDCombatManager.processPremierRoundInit(); RdDCombatManager.processPremierRoundInit();
} }
@@ -159,16 +162,11 @@ export class RdDCombatManager extends Combat {
if (actions.length > 0) { if (actions.length > 0) {
const action = actions[0] const action = actions[0]
const init = RdDCombatManager.getInitData(actor, action) const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action) const ajustement = RdDCombatManager.bonusArme(action.arme) + RdDCombatManager.etatGeneral(actor)
return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement); return RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
} }
let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined); return RdDInitiative.formule(MAP_PHASE['autre'], 10, 0, actor.getEtatGeneral() ?? 0);
return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement);
}
static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDInitiative.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -180,7 +178,6 @@ export class RdDCombatManager extends Combat {
for (let combatant of game.combat.combatants) { for (let combatant of game.combat.combatants) {
if (combatant.initiativeData?.arme?.type == "arme") { if (combatant.initiativeData?.arme?.type == "arme") {
// TODO: get init data premier round // TODO: get init data premier round
const initiativeData = combatant.initiativeData;
const action = combatant.initiativeData.arme; const action = combatant.initiativeData.arme;
const fromArme = Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround) const fromArme = Grammar.toLowerCaseNoAccentNoSpace(action.system.initpremierround)
const initData = premierRoundInit.find(it => fromArme.includes(initData.pattern)) const initData = premierRoundInit.find(it => fromArme.includes(initData.pattern))
@@ -200,10 +197,27 @@ export class RdDCombatManager extends Combat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId); static applyInitiativeCommand(combatantId, command, commandValue) {
let initValue = combatant.initiative + incDecValue; switch (command) {
game.combat.setInitiative(combatantId, initValue); case 'delta': return RdDCombatManager.incDecInit(combatantId, commandValue);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
}
}
static async incDecInit(combatantId, incDecValue) {
const combatant = game.combat.combatants.get(combatantId)
if (combatant?.initiative && incDecValue != 0) {
const value = combatant.system.init.value + incDecValue
const newInit = combatant.initiative + incDecValue / 100;
await game.combat.updateEmbeddedDocuments("Combatant", [{
_id: combatantId,
initiative: newInit,
'system.init.value': value,
'system.init.init': newInit,
}])
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -220,56 +234,42 @@ export class RdDCombatManager extends Combat {
} }
} }
options = [ options = [
{ name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +0.01); } }, { name: "Incrémenter initiative", condition: true, icon: '<i class="fa-solid fa-plus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), +1); } },
{ name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -0.01); } } { name: "Décrémenter initiative", condition: true, icon: '<i class="fa-solid fa-minus"></i>', callback: target => { RdDCombatManager.incDecInit(target.data('combatant-id'), -1); } }
].concat(options); ].concat(options);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async rollInitiativeAction(combatantId, action) { static async rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId) const combatant = game.combat.combatants.get(combatantId)
const actor = RdDCombatManager.getActorCombatant(combatant) const actor = RdDCombatManager.getActorCombatant(combatant)
if (actor == undefined) { return [] }
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0 if (actor == undefined) { return }
const init = RdDCombatManager.getInitData(actor, action) const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action.arme) const ajustement = RdDCombatManager.bonusArme(actor, action.arme) + RdDCombatManager.etatGeneral(actor)
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement); const formule = RdDInitiative.formule(init.phase, init.carac, init.niveau, ajustement);
await game.combat.rollInitRdD(combatantId, rollFormula, init); await game.combat.rollInitRdD(combatantId, formule, init);
combatant.initiativeData combatant.initiativeData = { action, formule } // pour reclasser l'init au round 0
} }
static getInitData(actor, action) { static getInitData(actor, action) {
if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } } if (actor.getSurprise() == "totale") { return { phase: MAP_PHASE['totale'], info: "Surprise Totale", carac: 0, niveau: 0 } }
if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } } if (actor.getSurprise() == "demi") { return { phase: MAP_PHASE['demi'], info: "Demi Surprise", carac: 0, niveau: 0 } }
if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } } if (action.action == 'autre') { return { phase: MAP_PHASE['autre'], info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } } if (action.action == 'possession') { return { phase: MAP_PHASE['possession'], info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } } if (action.action == 'haut-reve') { return { phase: MAP_PHASE['draconic'], info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
const comp = action.comp const comp = action.comp
return { return {
offset: RdDCombatManager.initOffset(comp?.system.categorie, action.arme), phase: RdDInitiative.phaseArme(comp?.system.categorie, action.arme),
info: action.name + " / " + comp.name, info: action.label,
carac: actor.getCaracInit(comp), carac: actor.getCaracInit(comp),
niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6) niveau: comp?.system.niveau ?? (['(lancer)', '(tir)'].includes(action.main) ? -8 : -6)
} }
} }
static initOffset(categorie, arme) {
switch (categorie) {
case "tir": return 8
case "lancer": return 7
default:
switch (arme.system.cac) {
case "empoignade": return 3
case "pugilat": return 4
case "naturelle": return 4
default: return 5
}
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static displayInitiativeMenu(html, combatantId) { static displayInitiativeMenu(html, combatantId) {
const combatant = game.combat.combatants.get(combatantId) const combatant = game.combat.combatants.get(combatantId)
@@ -297,13 +297,8 @@ export class RdDCombatManager extends Combat {
? possessions ? possessions
: actor.listActions({ isEquipe: true }) : actor.listActions({ isEquipe: true })
for (let index = 0; index < actions.length; index++) { return Misc.indexed(actions)
actions[index].index = index
} }
return actions
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -383,10 +378,15 @@ export class RdDCombat {
let defenderToken = canvas.tokens.get(msg.defenderToken.id) let defenderToken = canvas.tokens.get(msg.defenderToken.id)
if (defenderToken && Misc.isFirstConnectedGM()) { if (defenderToken && Misc.isFirstConnectedGM()) {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id) const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme) rddCombat?.removeChatMessageActionsPasseArme(msg.paramChatDefense.attackerRoll.passeArme)
if (msg.defenderRoll.v2) {/* TODO: delete roll V1 */
RollDialog.loadRollData(msg.paramChatDefense)
rddCombat?._chatMessageDefenseV2(msg.paramChatDefense)
} else {
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll) rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
} }
} }
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static _callJetDeVie(event) { static _callJetDeVie(event) {
@@ -464,8 +464,8 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onEvent(button, event) { async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event); const chatMessage = ChatUtility.getChatMessage(event);
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll'); const defenderRoll = ChatUtility.getMessageData(chatMessage, 'rollData');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll'); const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'rollData');
console.log('RdDCombat', attackerRoll, defenderRoll); console.log('RdDCombat', attackerRoll, defenderRoll);
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
@@ -560,7 +560,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isEchecTotal(rollData) { 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 à 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 // TODO: en cas de demi-surprise en défense, pas de changement à la règle de base
return rollData.rolled.isETotal return rollData.rolled.isETotal
@@ -574,7 +574,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isParticuliere(rollData) { static isParticuliere(rollData) {
if (rollData.ids /* roll V2*/) { if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isPart return rollData.rolled.isPart
} }
if (rollData.attackerRoll || !rollData.ajustements.surprise.used) { if (rollData.attackerRoll || !rollData.ajustements.surprise.used) {
@@ -585,7 +585,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isReussite(rollData) { static isReussite(rollData) {
if (rollData.ids /* roll V2*/) { if (rollData.v2 /* roll V2*/) {
return rollData.rolled.isSuccess return rollData.rolled.isSuccess
} }
if (!rollData.ajustements.surprise.used) { if (!rollData.ajustements.surprise.used) {
@@ -665,12 +665,97 @@ export class RdDCombat {
return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 }; return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
} }
async attaqueV2() {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return
}
await this.doRollAttaque({
ids: {
actorId: this.attackerId,
actorTokenId: this.attackerTokenId,
opponentId: this.defender.id,
opponentTokenId: this.defenderTokenId,
},
type: { allowed: ['attaque'], current: 'attaque' },
passeArme: foundry.utils.randomID(16),
})
}
async doRollAttaque(rollData, callbacks = []) {
// TODO V2 await this.proposerAjustementTirLancer(rollData)
await RollDialog.create(rollData, {
onRollDone: RollDialog.onRollDoneClose,
callbacks: [
async (roll) => await this.onAttaqueV2(roll),
...callbacks
]
})
}
async onAttaqueV2(attackerRoll) {
if (!this.defender || !attackerRoll.rolled.isSuccess || attackerRoll.particulieres?.length > 1) {
return
}
if (!await this.attacker.accorder(this.defender, 'avant-defense')) {
return;
}
RollDialog.loadRollData(attackerRoll)
const surpriseDefender = this.defender.getSurprise(true);
const paramChatDefense = {
attackerRoll: attackerRoll,
isPossession: this.isPossession(attackerRoll),
defender: this.defender,
attacker: this.attacker,
attackerId: this.attackerId,
attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
surprise: surpriseDefender,
}
if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefenseV2(paramChatDefense);
}
else {
this._socketSendMessageDefense(paramChatDefense, {});
}
}
async _chatMessageDefenseV2(paramDemandeDefense) {
const attackerRoll = paramDemandeDefense.attackerRoll;
RollBasicParts.loadSurprises(attackerRoll)
attackerRoll.passeArme = attackerRoll.passeArme ?? foundry.utils.randomID(16)
attackerRoll.dmg = RdDBonus.dmgRollV2(attackerRoll, attackerRoll.current.attaque)
// attackerRoll.current.attaque.dmg = attackerRoll.dmg
// attaque.dmg = attackerRoll.current.attaque.dmg
const attaque = RollDialog.saveParts(attackerRoll)
const defense = {
attackerRoll: attaque,
ids: RollBasicParts.reverseIds(attaque),
passeArme: attaque.passeArme ?? foundry.utils.randomID(16)
}
const choixDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', attackerRoll)
});
// flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'rollData', defense)
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async attaque(competence, arme) { async attaque(competence, arme) {
if (!await this.attacker.accorder(this.defender, 'avant-attaque')) { if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return return
} }
if (arme.system.cac == 'empoignade') { if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
return this.attacker.rollCompetence(competence.name, { arme: arme })
}
if (arme.system.cac == EMPOIGNADE) {
RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender) RdDEmpoignade.onAttaqueEmpoignade(this.attacker, this.defender)
return return
} }
@@ -723,9 +808,9 @@ export class RdDCombat {
} }
else { else {
// sans armes: à mains nues // sans armes: à mains nues
rollData.arme = RdDItemArme.corpsACorps(this.attacker) rollData.arme = RdDItemArme.pugilat(this.attacker)
rollData.arme.system.niveau = competence.system.niveau rollData.arme.system.niveau = competence.system.niveau
rollData.arme.system.initiative = RdDInitiative.calculInitiative(competence.system.niveau, this.attacker.system.carac['melee'].value); rollData.arme.system.initiative = RdDInitiative.getRollInitiative(this.attacker.system.carac['melee'].value, competence.system.niveau);
} }
return rollData; return rollData;
} }
@@ -776,7 +861,7 @@ export class RdDCombat {
passeArme: rollData.passeArme passeArme: rollData.passeArme
}) })
}); });
ChatUtility.setMessageData(choixParticuliere, 'attacker-roll', rollData); ChatUtility.setMessageData(choixParticuliere, 'rollData', rollData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -802,7 +887,10 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
isPossession(attackerRoll) { isPossession(attackerRoll) {
return attackerRoll.selectedCarac.label.toLowerCase() == 'possession'; const carac = attackerRoll.v2
? attackerRoll.current.carac?.label
: attackerRoll.selectedCarac.label
return carac?.toLowerCase() == 'possession';
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -852,10 +940,10 @@ export class RdDCombat {
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)), speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker?.getAlias(), alias: this.attacker?.getAlias(),
whisper: ChatUtility.getOwners(this.defender), whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.hbs', paramDemandeDefense), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense-v1.hbs', paramDemandeDefense),
}); });
// flag pour garder les jets d'attaque/defense // flag pour garder les jets d'attaque/defense
ChatUtility.setMessageData(choixDefense, 'defender-roll', defenderRoll); ChatUtility.setMessageData(choixDefense, 'rollData', defenderRoll);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -869,7 +957,7 @@ export class RdDCombat {
defenderToken: this.defenderToken, defenderToken: this.defenderToken,
defenderRoll: defenderRoll, defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense, paramChatDefense: paramChatDefense,
rollMode: true rollMode: true,
} }
}); });
} }
@@ -906,7 +994,7 @@ export class RdDCombat {
essais: attackerRoll.essais essais: attackerRoll.essais
}) })
}); });
ChatUtility.setMessageData(choixEchecTotal, 'attacker-roll', attackerRoll); ChatUtility.setMessageData(choixEchecTotal, 'rollData', attackerRoll);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -968,6 +1056,7 @@ export class RdDCombat {
async defenseV2(attackerRoll) { async defenseV2(attackerRoll) {
// this._prepareParade(attackerRoll, arme, competence); // this._prepareParade(attackerRoll, arme, competence);
RollDialog.loadRollData(attackerRoll)
await this.doRollDefense({ await this.doRollDefense({
ids: { ids: {
actorId: this.defender.id, actorId: this.defender.id,
@@ -975,19 +1064,15 @@ export class RdDCombat {
opponentTokenId: this.attackerTokenId, opponentTokenId: this.attackerTokenId,
opponentId: this.attackerId, opponentId: this.attackerId,
}, },
type: { allowed: ['defense'], current: 'defense' }, type: { allowed: [ROLL_TYPE_DEFENSE], current: ROLL_TYPE_DEFENSE },
attackerRoll: RollDialogAdapter.mapActionAttaque(attackerRoll), attackerRoll: attackerRoll,
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
}) })
} }
async doRollDefense(rollData, callbacks = []) { async doRollDefense(rollData, callbacks = []) {
await RollDialog.create(rollData, { await RollDialog.create(rollData, {
onRollDone: (dialog) => { onRollDone: RollDialog.onRollDoneClose,
if (!OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
},
customChatMessage: true,
callbacks: [ callbacks: [
async (roll) => { async (roll) => {
this.removeChatMessageActionsPasseArme(roll.passeArme); this.removeChatMessageActionsPasseArme(roll.passeArme);
@@ -1034,22 +1119,17 @@ export class RdDCombat {
if (RdDCombat.isReussite(rollData)) { if (RdDCombat.isReussite(rollData)) {
if (isParade) { if (isParade) {
await this.computeDeteriorationArme(rollData) await this.computeDeteriorationArme(rollData)
if (RdDCombat.isParticuliere(rollData)) {
await this.infoAttaquantDesarme(rollData)
}
} }
if (RdDCombat.isParticuliere(rollData)) {
await this._onDefenseParticuliere(rollData, isEsquive)
}
} }
this.removeChatMessageActionsPasseArme(rollData.passeArme) this.removeChatMessageActionsPasseArme(rollData.passeArme)
} }
async _onDefenseParticuliere(rollData, isEsquive) { async infoAttaquantDesarme(rollData) {
if (isEsquive) { if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
ChatUtility.createChatWithRollMode(
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
this.defender)
}
else if (/*TODO: parade?*/!rollData.attackerRoll?.particuliere) {
// TODO: attaquant doit jouer résistance et peut être désarmé p132 // TODO: attaquant doit jouer résistance et peut être désarmé p132
ChatUtility.createChatWithRollMode( ChatUtility.createChatWithRollMode(
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` }, { content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },

View File

@@ -19,6 +19,7 @@ import { TMRUtility } from "./tmr-utility.js";
import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js"; import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRollResult } from "./rdd-roll-result.js";
import { renderTemplate } from "./constants.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
@@ -460,12 +461,7 @@ export class RdDCommands {
async supprimerSignesDraconiquesEphemeres() { async supprimerSignesDraconiquesEphemeres() {
if (game.user.isGM) { if (game.user.isGM) {
game.actors.forEach(actor => { game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere);
if (ephemeres.length > 0) {
actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id));
}
});
} }
else { else {
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe"); ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe");

View File

@@ -1,5 +1,5 @@
import { STATUSES } from "./settings/status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES, renderTemplate } from "./constants.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { RdDRollResult } from "./rdd-roll-result.js"; import { RdDRollResult } from "./rdd-roll-result.js";
import { RdDRoll } from "./rdd-roll.js"; import { RdDRoll } from "./rdd-roll.js";

View File

@@ -1,4 +1,4 @@
import { ATTAQUE_TYPE, RdDItemArme } from "./item/arme.js"; import { ATTAQUE_TYPE, EMPOIGNADE, PUGILAT, RdDItemArme } from "./item/arme.js";
import { ITEM_TYPES } from "./constants.js"; import { ITEM_TYPES } from "./constants.js";
export class RdDHotbar { export class RdDHotbar {
@@ -28,8 +28,8 @@ export class RdDHotbar {
return ' ' + maniement return ' ' + maniement
case 'tir': return ' (tir)'; case 'tir': return ' (tir)';
case 'lancer': return ' (lancer)'; case 'lancer': return ' (lancer)';
case 'pugilat': return ' (pugilat)'; case PUGILAT: return ' (pugilat)';
case 'empoignade': return ' (empoignade)'; case EMPOIGNADE: return ' (empoignade)';
} }
return '' return ''
} }
@@ -63,8 +63,8 @@ export class RdDHotbar {
case ITEM_TYPES.competence: case ITEM_TYPES.competence:
await this.createItemMacro(item, slot++, 'competence') await this.createItemMacro(item, slot++, 'competence')
if (item.isCorpsACorps()) { if (item.isCorpsACorps()) {
await this.createItemMacro(item, slot++, 'pugilat') await this.createItemMacro(item, slot++, PUGILAT)
await this.createItemMacro(item, slot++, 'empoignade') await this.createItemMacro(item, slot++, EMPOIGNADE)
} }
else if (item.isCompetenceArme()) { else if (item.isCompetenceArme()) {
ui.notifications.info(`${item.name} est une compétence d'arme, la macro n'est pas liée à un arme.<br> ui.notifications.info(`${item.name} est une compétence d'arme, la macro n'est pas liée à un arme.<br>
@@ -121,9 +121,9 @@ export class RdDHotbar {
case ITEM_TYPES.competence: case ITEM_TYPES.competence:
if (item.isCorpsACorps()) { if (item.isCorpsACorps()) {
switch (categorieArme) { switch (categorieArme) {
case 'pugilat': case PUGILAT:
return actor.rollArme(RdDItemArme.corpsACorps(actor)); return actor.rollArme(RdDItemArme.pugilat(actor));
case 'empoignade': case EMPOIGNADE:
return actor.rollArme(RdDItemArme.empoignade(actor)); return actor.rollArme(RdDItemArme.empoignade(actor));
} }
} }

View File

@@ -1,4 +1,5 @@
import { ChatUtility } from "./chat-utility.js" import { ChatUtility } from "./chat-utility.js"
import { renderTemplate } from "./constants.js"
const vents = [ const vents = [
{ min: 0, max: 0, valeur: 'Calme' }, { min: 0, max: 0, valeur: 'Calme' },

View File

@@ -1,5 +1,6 @@
import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDBaseActor } from "./actor/base-actor.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";

View File

@@ -1,3 +1,4 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
@@ -66,9 +67,9 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _computeCell(niveau, percentage) { static _computeCell(level, percentage) {
return { return {
niveau: niveau, level: level,
score: percentage, score: percentage,
norm: Math.min(99, percentage), norm: Math.min(99, percentage),
sign: this._reussiteSignificative(percentage), sign: this._reussiteSignificative(percentage),
@@ -155,6 +156,11 @@ export class RdDResolutionTable {
} }
} }
/* -------------------------------------------- */
static replaceParticuliereDemiSurprise(chances){
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'part'), { overwrite: true });
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static significativeRequise(chances) { static significativeRequise(chances) {
chances.roll = Math.min(chances.part + 1, chances.sign) chances.roll = Math.min(chances.part + 1, chances.sign)
@@ -188,7 +194,7 @@ export class RdDResolutionTable {
static computeReussite(chances, roll, diviseur) { static computeReussite(chances, roll, diviseur) {
const reussite = reussites.find(x => x.condition(chances, roll)) const reussite = reussites.find(x => x.condition(chances, roll))
if (diviseur > 1 && reussite.isSuccess) { if (diviseur > 1 && reussite.isSuccess) {
if (chances > roll * diviseur) { if (chances.norm < roll * diviseur) {
return reussiteInsuffisante return reussiteInsuffisante
} }
} }
@@ -236,7 +242,7 @@ export class RdDResolutionTable {
maxCarac = Math.min(maxCarac, minCarac + 20); maxCarac = Math.min(maxCarac, minCarac + 20);
minLevel = Math.max(minLevel, -10); minLevel = Math.max(minLevel, -10);
maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes); maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes);
return await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', { return await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.hbs', {
carac: carac, carac: carac,
difficulte: level, difficulte: level,
min: minLevel, min: minLevel,

View File

@@ -1,4 +1,4 @@
import { ENTITE_BLURETTE, ENTITE_INCARNE } from "./constants.js"; import { ENTITE_BLURETTE, ENTITE_INCARNE, renderTemplate } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
/** /**

View File

@@ -25,7 +25,7 @@ export class RdDRollDialogEthylisme extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
this.html.find(".force-alcool").change((event) => { this.html.find(".force-alcool").change((event) => {
this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value); this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value);

View File

@@ -1,5 +1,7 @@
import { renderTemplate } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRollResult } from "./rdd-roll-result.js";
const titleTableDeResolution = 'Table de résolution'; const titleTableDeResolution = 'Table de résolution';
/** /**
@@ -20,7 +22,7 @@ export class RdDRollResolutionTable extends Dialog {
RdDRollResolutionTable.resolutionTable.render(true); RdDRollResolutionTable.resolutionTable.render(true);
} }
else{ else{
RdDRollResolutionTable.resolutionTable.bringToTop(); RdDRollResolutionTable.resolutionTable.bringToFront();
} }
} }
@@ -68,7 +70,7 @@ export class RdDRollResolutionTable extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre)); this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
@@ -98,14 +100,14 @@ export class RdDRollResolutionTable extends Dialog {
async onLancer() { async onLancer() {
await RdDResolutionTable.rollData(this.rollData); await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled); console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled);
await RdDResolutionTable.displayRollData(this.rollData); await RdDRollResult.displayRollData(this.rollData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async onLancerFermer() { async onLancerFermer() {
await RdDResolutionTable.rollData(this.rollData); await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled); console.log("RdDRollResolutionTable -=>", this.rollData, this.rollData.rolled);
await RdDResolutionTable.displayRollData(this.rollData); await RdDRollResult.displayRollData(this.rollData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@@ -1,4 +1,5 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { renderTemplate } from "./constants.js";
export class RdDRollResult { export class RdDRollResult {
@@ -13,6 +14,6 @@ export class RdDRollResult {
static async buildRollDataHtml(rollData, template = 'chat-resultat-general.hbs') { static async buildRollDataHtml(rollData, template = 'chat-resultat-general.hbs') {
rollData.show = rollData.show || {}; rollData.show = rollData.show || {};
return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData); return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/${template}`, rollData);
} }
} }

View File

@@ -1,4 +1,4 @@
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemSort } from "./item-sort.js"; import { RdDItemSort } from "./item-sort.js";
@@ -8,8 +8,8 @@ import { RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { ACTOR_TYPES } from "./constants.js"; import { ACTOR_TYPES, renderTemplate } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js"; import { EMPOIGNADE } from "./item/arme.js";
/** /**
* Extend the base Dialog entity to select roll parameters * Extend the base Dialog entity to select roll parameters
@@ -23,7 +23,7 @@ export class RdDRoll extends Dialog {
RdDRoll._ensureCorrectAction(action); RdDRoll._ensureCorrectAction(action);
RdDRoll._setDefaultOptions(actor, rollData); RdDRoll._setDefaultOptions(actor, rollData);
const html = await foundry.applications.handlebars.renderTemplate(dialogConfig.html, rollData); const html = await renderTemplate(dialogConfig.html, rollData);
let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => { } }; let options = { classes: ["rdd-roll-dialog"], width: 650, height: 'fit-content', 'z-index': 99999, close: html => { } };
if (dialogConfig.close) { if (dialogConfig.close) {
@@ -128,7 +128,7 @@ export class RdDRoll extends Dialog {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html; this.html = html;
this.bringToTop(); this.bringToFront();
console.log('RdDRoll.activateListeners', this.rollData); console.log('RdDRoll.activateListeners', this.rollData);
@@ -334,10 +334,8 @@ export class RdDRoll extends Dialog {
// Mise à jour valeurs // Mise à jour valeurs
this.html.find(".dialog-roll-title").text(this._getTitle(rollData)); this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == 'non-mortel'); this.html.find("input.check-mortalite").prop('checked', rollData.dmg.mortalite == 'non-mortel');
this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == 'empoignade' ? 'empoignade' : Misc.toSignedString(rollData.dmg.total)); this.html.find("label.dmg-arme-actor").text(rollData.dmg.mortalite == EMPOIGNADE ? EMPOIGNADE : Misc.toSignedString(rollData.dmg.total));
this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite); this.html.find("label.arme-mortalite").text(rollData.dmg.mortalite);
// this.html.find("[name='dmg-arme-actor']").text(rollData.dmg.mortalite == 'empoignade'? 'empoignade': Misc.toSignedString(rollData.dmg.total) );
// this.html.find("[name='arme-mortalite']").text(rollData.dmg.mortalite);
this.html.find("div.placeholder-ajustements").empty().append(adjustements); this.html.find("div.placeholder-ajustements").empty().append(adjustements);
this.html.find("div.placeholder-resolution").empty().append(resolutionTable) this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
} }
@@ -345,7 +343,7 @@ export class RdDRoll extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async buildAjustements(rollData) { async buildAjustements(rollData) {
return await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData); return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.hbs`, rollData);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@@ -1,5 +1,5 @@
import { SHOW_DICE, SYSTEM_RDD } from "./constants.js"; import { renderTemplate, SHOW_DICE, SYSTEM_RDD } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements-v1.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js"; import { COORD_TMR_INCONNU, TMRUtility } from "./tmr-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
@@ -47,7 +47,7 @@ export class RdDTMRDialog extends Dialog {
static async create(actor, tmrData) { static async create(actor, tmrData) {
await PixiTMR.init() await PixiTMR.init()
let html = await foundry.applications.handlebars.renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.hbs', tmrData);
if (tmrData.mode != 'visu' && !game.user.isGM) { if (tmrData.mode != 'visu' && !game.user.isGM) {
ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() }); ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() });
} }
@@ -82,7 +82,7 @@ export class RdDTMRDialog extends Dialog {
this.subdialog = undefined this.subdialog = undefined
this.displaySize = undefined this.displaySize = undefined
if (!this.viewOnly && !game.user.isGM) { 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 = []; this.callbacksOnAnimate = [];
const displaySize = TMR_DISPLAY_SIZE.clamp(game.settings.get(SYSTEM_RDD, TMR_DISPLAY_SIZE.code) ?? TMR_DISPLAY_SIZE.def); 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(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor())); 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 // Roll Sort
this.html.find('.lancer-sort').click(event => this.lancerUnSort()); this.html.find('.lancer-sort').click(event => this.lancerUnSort());
@@ -169,26 +173,26 @@ export class RdDTMRDialog extends Dialog {
async forceTMRDisplay() { async forceTMRDisplay() {
if (this.rendered) { if (this.rendered) {
this.bringToTop() this.bringToFront()
this.bringSubDialogToTop(); this.bringSubDialogToFront();
} }
} }
bringSubDialogToTop() { bringSubDialogToFront() {
if (this.subdialog?.bringToTop && this.subdialog?.element && this.subdialog?.element[0]) { if (this.subdialog?.bringToFront && this.subdialog?.element && this.subdialog?.element[0]) {
this.subdialog.bringToTop(); this.subdialog.bringToFront();
} }
} }
async restoreTMRAfterAction() { async restoreTMRAfterAction() {
this.subdialog = undefined this.subdialog = undefined
await this.maximize() await this.maximize()
this.bringToTop() this.bringToFront()
} }
forceTMRContinueAction() { forceTMRContinueAction() {
ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR'); ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR');
this.bringSubDialogToTop(); this.bringSubDialogToFront();
return false return false
} }
@@ -343,19 +347,8 @@ export class RdDTMRDialog extends Dialog {
this.forceTMRContinueAction() this.forceTMRContinueAction()
return false return false
} }
this.descenteTMR = true; this.descenteTMR = true
if (this.actor.tmrApp) { await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue)
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.pixiTMR.close(); this.pixiTMR.close();
this.pixiTMR = undefined this.pixiTMR = undefined
await super.close(); await super.close();
@@ -412,7 +405,7 @@ export class RdDTMRDialog extends Dialog {
async $ignorerRencontre() { async $ignorerRencontre() {
if (this.currentRencontre) { if (this.currentRencontre) {
console.log("-> ignorer", 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() await this.$deleteRencontreTMRAtPosition()
this.updateTokens(); this.updateTokens();
this.$updateValuesDisplay(); this.$updateValuesDisplay();
@@ -508,7 +501,7 @@ export class RdDTMRDialog extends Dialog {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getOwners(this.actor), whisper: ChatUtility.getOwners(this.actor),
content: await foundry.applications.handlebars.renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.hbs`, rencData)
}); });
this.$updateValuesDisplay(); this.$updateValuesDisplay();
@@ -578,29 +571,6 @@ export class RdDTMRDialog extends Dialog {
}, 500); }, 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) { async manageRencontre(tmr) {
if (this.viewOnly) { if (this.viewOnly) {
@@ -676,14 +646,14 @@ export class RdDTMRDialog extends Dialog {
? TMRUtility.getTMRType(tmr.coord) + " ??" ? TMRUtility.getTMRType(tmr.coord) + " ??"
: tmr.label + " (" + tmr.coord + ")"); : tmr.label + " (" + tmr.coord + ")");
this.setTMRPendingAction({ bringToTop: () => { } }) this.setTMRPendingAction({ bringToFront: () => { } })
const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE }); const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE });
this.restoreTMRAfterAction() this.restoreTMRAfterAction()
if (myRoll == 7) { 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()) return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre())
} else { } else {
this._tellToUser(myRoll + ": Pas de rencontre en " + coordTMR); ChatUtility.tellToUser(myRoll + ": Pas de rencontre en " + coordTMR);
return undefined; return undefined;
} }
} }

View File

@@ -1,6 +1,9 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { renderTemplate } from "./constants.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { OptionsAvancees, ROLL_DIALOG_V2 } from "./settings/options-avancees.js";
import { Targets } from "./targets.js"; import { Targets } from "./targets.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -30,47 +33,92 @@ export class RdDTokenHud {
const combatant = game.combat.combatants.find(c => c.tokenId == tokenId) const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false }) const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (actor) { if (actor) {
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
await RdDTokenHud.addExtensionHudCombat(html, combatant, actor, token)
}
else {
const actions = RdDCombatManager.listActionsActorCombatant(actor) const actions = RdDCombatManager.listActionsActorCombatant(actor)
// initiative // initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions) await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
// combat // combat
await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions.filter(it => !it.initOnly)) await RdDTokenHud.addExtensionHudAttaques(html, combatant, token, actions.filter(it => !it.initOnly))
}
}
} }
} }
static async addExtensionHudCombat(html, combatant, actor, token) {
const actionsActor = actor.listActionsCombat();
const ajustements = combatant?.initiative ?
[
{ label: 'Initiative +1', action: 'delta', value: 1 },
{ label: 'Initiative -1', action: 'delta', value: -1 }
] : []
const autres = [{ label: "Autre action", action: 'autre' }]
const actions = Misc.indexed(actionsActor.concat(ajustements).concat(autres))
const hudData = { combatant, token, actions };
const hud = $(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/hud-actor-combat.hbs', hudData))
$(html).find('div.col.left').append(hud)
const list = hud.find('div.rdd-hud-list')
RdDTokenHud.setupHudToggle(hud, list)
const selectInitiative = list.find('select[name="initiative"]');
selectInitiative.change(event => {
const action = actions.find(it => it.index == event.currentTarget.value)
console.log('select initiative', combatant.id, action)
if (action) {
switch (action.action) {
case 'delta':
RdDCombatManager.incDecInit(combatant.id, action.value);
break
case 'autre':
RdDCombatManager.rollInitiativeAction(combatant.id,
{ label: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
break
default:
RdDCombatManager.rollInitiativeAction(combatant.id, action)
}
selectInitiative.select("")
}
})
list.find('.rdd-attaque-v2').click(event => combatant.actor.rollAttaque(token))
} }
static async addExtensionHudInit(html, combatant, actions) { static async addExtensionHudInit(html, combatant, actions) {
const hudData = { const hudData = {
combatant, actions, combatant, actions,
commandes: [ commandes: [
{ name: "Autre action", command: 'autre' }, { label: "Autre action", command: 'autre' },
{ name: 'Initiative +1', command: 'inc', value: 0.01 }, { label: 'Initiative +1', command: 'delta', value: 1 },
{ name: 'Initiative -1', command: 'dec', value: -0.01 }] { label: 'Initiative -1', command: 'deltac', value: -1 }]
}; };
const controlIconCombat = $(html).find('.control-icon[data-action=combat]'); const controlIconCombat = $(html).find('.control-icon[data-action=combat]');
await RdDTokenHud._configureSubMenu(controlIconCombat, await RdDTokenHud._configureSubMenu(it => controlIconCombat.after(it),
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.hbs', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.hbs',
hudData, hudData,
(event) => { (event) => {
let initCommand = event.currentTarget.attributes['data-command']?.value; let initCommand = event.currentTarget.attributes['data-command']?.value
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value; let initCommandValue = Number(event.currentTarget.attributes['data-command-value']?.value ?? 0)
let combatantId = event.currentTarget.attributes['data-combatant-id']?.value
if (initCommand) { if (initCommand) {
RdDTokenHud._initiativeCommand(initCommand, combatantId); RdDCombatManager.applyInitiativeCommand(combatantId, initCommand, initCommandValue)
} else { } else {
let index = event.currentTarget.attributes['data-action-index'].value; let index = event.currentTarget.attributes['data-action-index'].value
let action = hudData.actions[index]; let action = hudData.actions[index]
RdDCombatManager.rollInitiativeAction(combatantId, action); RdDCombatManager.rollInitiativeAction(combatantId, action)
} }
}); })
} }
static async addExtensionHudCombat(html, combatant, token, actions) { static async addExtensionHudAttaques(html, combatant, token, actions) {
const hudData = { combatant, token, actions, commandes: [] }; const hudData = { combatant, token, actions, commandes: [] };
const controlIconTarget = $(html).find('.control-icon[data-action=target]'); const divColLeft = $(html).find('div.col.left');
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs', hudData, await RdDTokenHud._configureSubMenu(it => divColLeft.append(it),
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.hbs',
hudData,
(event) => { (event) => {
const actionIndex = event.currentTarget.attributes['data-action-index']?.value; const actionIndex = event.currentTarget.attributes['data-action-index']?.value;
const action = hudData.actions[actionIndex]; const action = hudData.actions[actionIndex];
@@ -90,7 +138,7 @@ export class RdDTokenHud {
const hudSoins = { blessures: target.actor.blessuresASoigner() ?? [] }; const hudSoins = { blessures: target.actor.blessuresASoigner() ?? [] };
if (hudSoins.blessures.length > 0) { if (hudSoins.blessures.length > 0) {
const controlIconTarget = $(html).find('.control-icon[data-action=combat]'); const controlIconTarget = $(html).find('.control-icon[data-action=combat]');
await RdDTokenHud._configureSubMenu(controlIconTarget, await RdDTokenHud._configureSubMenu(it => controlIconTarget.after(it),
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-soins.hbs', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-soins.hbs',
hudSoins, hudSoins,
(event) => { (event) => {
@@ -101,15 +149,6 @@ export class RdDTokenHud {
} }
} }
static _initiativeCommand(initCommand, combatantId) {
switch (initCommand) {
case 'inc': return RdDCombatManager.incDecInit(combatantId, 0.01);
case 'dec': return RdDCombatManager.incDecInit(combatantId, -0.01);
case 'autre': return RdDCombatManager.rollInitiativeAction(combatantId,
{ name: "Autre action", action: 'autre', system: { initOnly: true, competence: "Autre action" } });
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) { static async addTokenHudExtensions(app, html, tokenId) {
console.log(`Adding token HUD extensions for token ${tokenId}`); console.log(`Adding token HUD extensions for token ${tokenId}`);
@@ -129,20 +168,24 @@ export class RdDTokenHud {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) { static async _configureSubMenu(callInsertion, template, hudData, onMenuItem) {
const hud = $(await foundry.applications.handlebars.renderTemplate(template, hudData)); const hud = $(await renderTemplate(template, hudData));
const list = hud.find('div.rdd-hud-list'); const list = hud.find('div.rdd-hud-list');
RdDTokenHud._toggleHudListActive(hud, list); RdDTokenHud.setupHudToggle(hud, list)
hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list));
list.find('.rdd-hud-menu').click(onMenuItem); list.find('.rdd-hud-menu').click(onMenuItem);
insertionPoint.after(hud); callInsertion(hud);
} }
static _toggleHudListActive(hud, list) { static setupHudToggle(hud, list) {
hud.toggleClass('active'); function toggleHudList(hud, list) {
HtmlUtility.showControlWhen(list, hud.hasClass('active')); hud.toggleClass('active')
HtmlUtility.showControlWhen(list, hud.hasClass('active'))
} }
toggleHudList(hud, list)
$(hud).find('img.rdd-hud-togglebutton').click(event => toggleHudList(hud, list))
}
} }

View File

@@ -301,6 +301,8 @@ export class RdDUtility {
Handlebars.registerHelper('json-stringify', object => JSON.stringify(object)) Handlebars.registerHelper('json-stringify', object => JSON.stringify(object))
// math // math
Handlebars.registerHelper('math-sum', (...values) => values.slice(0, -1).reduce(Misc.sum(), 0))
Handlebars.registerHelper('math-abs', diff => Math.abs(parseInt(diff)))
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('repeat', function (n, block) { Handlebars.registerHelper('repeat', function (n, block) {
let accum = ''; let accum = '';

View File

@@ -1,9 +1,17 @@
import { ChatUtility } from "../chat-utility.js" 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 { RdDCarac } from "../rdd-carac.js"
import { RdDCombat } from "../rdd-combat.js" import { RdDCombat } from "../rdd-combat.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { RdDResolutionTable } from "../rdd-resolution-table.js" import { RdDResolutionTable } from "../rdd-resolution-table.js"
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 { export default class ChatRollResult {
static init() { static init() {
@@ -14,14 +22,18 @@ export default class ChatRollResult {
static onReady() { static onReady() {
foundry.applications.handlebars.loadTemplates({ 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-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-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-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', 'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
}) })
} }
async display(roll) { async display(roll, impacts) {
this.prepareDisplay(roll) this.prepareDisplay(roll)
const chatMessage = await ChatUtility.createChatWithRollMode( const chatMessage = await ChatUtility.createChatWithRollMode(
@@ -31,18 +43,19 @@ export default class ChatRollResult {
roll.active.actor, roll.active.actor,
roll.current?.rollmode?.key roll.current?.rollmode?.key
) )
const save = RollDialog.saveParts(roll) const save = RollDialog.saveParts(roll, impacts)
ChatUtility.setMessageData(chatMessage, 'rollData', save)
await this.saveChatMessageRoll(chatMessage, save)
return chatMessage return chatMessage
} }
prepareDisplay(roll) { prepareDisplay(roll) {
roll.done = roll.done || {} roll.done = roll.done ?? {}
roll.show = roll.show || {} roll.show = roll.show ?? {}
roll.show.chance = this.isAppelChancePossible(roll) roll.show.chance = this.isAppelChancePossible(roll)
roll.show.encaissement = this.isShowEncaissement(roll) roll.show.encaissement = this.isShowEncaissement(roll)
roll.show.recul = this.getReculChoc(roll) roll.show.recul = this.getRecul(roll)
roll.show.maladresse = this.getMaladresse(roll)
} }
isAppelChancePossible(roll) { isAppelChancePossible(roll) {
@@ -52,11 +65,35 @@ export default class ChatRollResult {
} }
isShowEncaissement(roll) { isShowEncaissement(roll) {
return roll.rolled.isEchec && switch (roll.type.current) {
roll.attackerRoll?.dmg.mortalite != 'empoignade' case ROLL_TYPE_DEFENSE:
return roll.rolled.isEchec && roll.attackerRoll?.dmg.mortalite != EMPOIGNADE
}
return false
} }
getReculChoc(roll, defender = roll.active.actor, attacker = roll.opponent.actor) { 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) {
case ROLL_TYPE_DEFENSE:
{
const attaque = roll.attackerRoll const attaque = roll.attackerRoll
if (attaque && if (attaque &&
(roll.rolled.isEchec || !roll.current.defense.isEsquive) && (roll.rolled.isEchec || !roll.current.defense.isEsquive) &&
@@ -71,12 +108,25 @@ export default class ChatRollResult {
diff: taille - impact diff: taille - impact
} }
} }
break
}
case ROLL_TYPE_ATTAQUE:
{
const attaque = roll
if (attaque.particuliere == 'force' || 'charge' == attaque.tactique?.key) {
return {
raison: 'charge' == attaque.tactique?.key ? 'charge' : 'particulière en force',
}
}
}
}
return undefined return undefined
} }
async buildRollHtml(roll) { 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
return await foundry.applications.handlebars.renderTemplate(template, roll) const html = await renderTemplate(template, roll)
return await RdDTextEditor.enrichHTML(html, undefined, { showLink: false })
} }
async chatListeners(html) { async chatListeners(html) {
@@ -84,7 +134,11 @@ export default class ChatRollResult {
$(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event)) $(html).on("click", '.appel-destinee', event => this.onClickAppelDestinee(event))
$(html).on("click", '.encaissement', event => this.onClickEncaissement(event)) $(html).on("click", '.encaissement', event => this.onClickEncaissement(event))
$(html).on("click", '.resister-recul', event => this.onClickRecul(event)) $(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) { getCombat(roll) {
@@ -92,15 +146,24 @@ export default class ChatRollResult {
case ROLL_TYPE_DEFENSE: case ROLL_TYPE_DEFENSE:
return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId) return RdDCombat.rddCombatForAttackerAndDefender(roll.ids.opponentId, roll.ids.opponentTokenId, roll.ids.actorTokenId)
case ROLL_TYPE_ATTAQUE: 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 return undefined
} }
async saveChatMessageRoll(chatMessage, savedRoll) {
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
}
loadChatMessageRoll(chatMessage) {
return ChatUtility.getMessageData(chatMessage, 'rollData')
}
async updateChatMessage(chatMessage, savedRoll) { async updateChatMessage(chatMessage, savedRoll) {
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll) await this.saveChatMessageRoll(chatMessage, savedRoll)
const copy = foundry.utils.duplicate(savedRoll) const copy = foundry.utils.duplicate(savedRoll)
RollDialog.loadRollData(copy) RollDialog.loadRollData(copy)
savedRoll.dmg = copy.current.attaque?.dmg
this.prepareDisplay(copy) this.prepareDisplay(copy)
chatMessage.update({ content: await this.buildRollHtml(copy) }) chatMessage.update({ content: await this.buildRollHtml(copy) })
chatMessage.render(true) chatMessage.render(true)
@@ -108,7 +171,7 @@ export default class ChatRollResult {
onClickAppelChance(event) { onClickAppelChance(event) {
const chatMessage = ChatUtility.getChatMessage(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) const actor = game.actors.get(savedRoll.ids.actorId)
actor.rollAppelChance( actor.rollAppelChance(
() => this.onAppelChanceSuccess(savedRoll, chatMessage), () => this.onAppelChanceSuccess(savedRoll, chatMessage),
@@ -116,10 +179,13 @@ export default class ChatRollResult {
event.preventDefault() event.preventDefault()
} }
onAppelChanceSuccess(savedRoll, chatMessage) { async onAppelChanceSuccess(savedRoll, chatMessage) {
const reRoll = foundry.utils.duplicate(savedRoll) const reRoll = foundry.utils.duplicate(savedRoll)
console.log('onAppelChanceSuccess savedRoll', savedRoll)
reRoll.type.retry = true reRoll.type.retry = true
await this.updateChatMessage(chatMessage, reRoll)
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)] const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
// TODO: annuler les effets // TODO: annuler les effets
switch (reRoll.type.current) { switch (reRoll.type.current) {
case ROLL_TYPE_DEFENSE: case ROLL_TYPE_DEFENSE:
@@ -142,7 +208,7 @@ export default class ChatRollResult {
onClickAppelDestinee(event) { onClickAppelDestinee(event) {
const chatMessage = ChatUtility.getChatMessage(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) const actor = game.actors.get(savedRoll.ids.actorId)
actor.appelDestinee(async () => { actor.appelDestinee(async () => {
@@ -155,7 +221,7 @@ export default class ChatRollResult {
async onClickEncaissement(event) { async onClickEncaissement(event) {
const chatMessage = ChatUtility.getChatMessage(event) const chatMessage = ChatUtility.getChatMessage(event)
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData') const savedRoll = this.loadChatMessageRoll(chatMessage)
const attaque = savedRoll.attackerRoll const attaque = savedRoll.attackerRoll
const defender = game.actors.get(savedRoll.ids.actorId) const defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId) const attacker = game.actors.get(savedRoll.ids.opponentId)
@@ -169,7 +235,7 @@ export default class ChatRollResult {
async onClickRecul(event) { async onClickRecul(event) {
const chatMessage = ChatUtility.getChatMessage(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 defender = game.actors.get(savedRoll.ids.actorId)
const attacker = game.actors.get(savedRoll.ids.opponentId) const attacker = game.actors.get(savedRoll.ids.opponentId)
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme) savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
@@ -177,4 +243,40 @@ export default class ChatRollResult {
await this.updateChatMessage(chatMessage, savedRoll) await this.updateChatMessage(chatMessage, savedRoll)
} }
async onClickChoixParticuliere(event) {
const choix = event.currentTarget.attributes['data-particuliere'].value
const chatMessage = ChatUtility.getChatMessage(event)
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)
}
async onClickFaireGouter(event) {
const chatMessage = ChatUtility.getChatMessage(event)
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)
}
} }

View File

@@ -1,28 +1,29 @@
import { ActorToken } from "../actor-token.mjs" import { TokenActor } from "../technical/actor-token.mjs"
import { StatusEffects } from "../settings/status-effects.js" import { StatusEffects } from "../settings/status-effects.js"
import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { ROLL_TYPE_ATTAQUE, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_ATTAQUE } from "./roll-part-attaque.mjs" import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
import { PART_DEFENSE } from "./roll-part-defense.mjs" import { PART_DEFENSE } from "./roll-part-defense.mjs"
export class RollBasicParts { export class RollBasicParts {
restore(rollData) { static restore(rollData) {
rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id rollData.ids.sceneId = rollData.ids.sceneId ?? canvas.scene.id
rollData.active = RollBasicParts.$getActor(rollData) rollData.active = RollBasicParts.getTokenActor(rollData)
rollData.opponent = RollBasicParts.$getOpponent(rollData) rollData.opponent = RollBasicParts.getTokenActorOpponent(rollData)
if (rollData.type.opposed == undefined) { if (rollData.type.opposed == undefined) {
rollData.type.opposed = rollData.opponent != null rollData.type.opposed = rollData.opponent != null
} }
} }
loadSurprises(rollData, type) { static loadSurprises(rollData, type = rollData.type.current) {
if (!rollData.type.passif) { if (!rollData.type.passif) {
this.loadSurprise(rollData.active, this.getForceRequiseActiveActor(rollData, type)) RollBasicParts.loadSurprise(rollData.active, RollBasicParts.getForceRequiseActiveActor(rollData, type))
this.loadSurprise(rollData.opponent, 0) RollBasicParts.loadSurprise(rollData.opponent, 0)
} }
} }
loadSurprise(who, forceRequise) { static loadSurprise(who, forceRequise) {
if (who?.actor) { if (who?.actor) {
foundry.utils.mergeObject(who, foundry.utils.mergeObject(who,
StatusEffects.getActorEffetSurprise(who.actor, forceRequise), StatusEffects.getActorEffetSurprise(who.actor, forceRequise),
@@ -30,15 +31,16 @@ export class RollBasicParts {
} }
} }
getForceRequiseActiveActor(rollData, type) { static getForceRequiseActiveActor(rollData, type) {
switch (type) { switch (type) {
case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].attaque.forceRequise case ROLL_TYPE_ATTAQUE: return rollData.current[PART_ATTAQUE].forceRequise
case ROLL_TYPE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise case ROLL_TYPE_DEFENSE: return rollData.current[PART_DEFENSE].forceRequise
default: return 0 default: return 0
} }
} }
initFrom(rollData) { static initFrom(rollData) {
const isOpposed = rollData.type.opposed && rollData.opponent
return { return {
selected: {}, selected: {},
type: rollData.type, type: rollData.type,
@@ -46,36 +48,46 @@ export class RollBasicParts {
sceneId: rollData.ids.sceneId, sceneId: rollData.ids.sceneId,
actorId: rollData.active.id, actorId: rollData.active.id,
actorTokenId: rollData.active.tokenId, actorTokenId: rollData.active.tokenId,
opponentId: rollData.type.opposed ? rollData.opponent.id : undefined, opponentId: isOpposed ? rollData.opponent.id : undefined,
opponentTokenId: rollData.type.opposed ? rollData.opponent.tokenId : undefined, opponentTokenId: isOpposed ? rollData.opponent.tokenId : undefined,
} }
} }
} }
static $getActor(rollData) { static reverseIds(rollData) {
return {
sceneId: rollData.ids.sceneId,
actorId: rollData.ids.opponentId,
actorTokenId: rollData.ids.opponentTokenId,
opponentId: rollData.ids.actorId,
opponentTokenId: rollData.actorTokenId
}
}
static getTokenActor(rollData) {
if (rollData.ids.actorTokenId) { if (rollData.ids.actorTokenId) {
return ActorToken.fromTokenId(rollData.ids.actorTokenId, rollData.ids.sceneId) return TokenActor.fromTokenId(rollData.ids.actorTokenId, rollData.ids.sceneId)
} }
else { else {
const actorId = rollData.ids.actorId ?? (canvas.tokens.controlled.length == 1 const actorId = rollData.ids.actorId ?? (canvas.tokens.controlled.length == 1
/** TODO: jets de plusieurs personnages??? */ /** TODO: jets de plusieurs personnages??? */
? canvas.tokens.controlled[0] ? canvas.tokens.controlled[0]
: undefined) : undefined)
return ActorToken.fromActorId(actorId, () => { throw new Error("Pas d'acteur sélectionné") }) return TokenActor.fromActorId(actorId, () => { throw new Error("Pas d'acteur sélectionné") })
} }
} }
static $getOpponent(rollData) { static getTokenActorOpponent(rollData) {
if (rollData.ids.opponentTokenId) { if (rollData.ids.opponentTokenId) {
return ActorToken.fromTokenId(rollData.ids.opponentTokenId, rollData.ids.sceneId) return TokenActor.fromTokenId(rollData.ids.opponentTokenId, rollData.ids.sceneId)
} }
else if (rollData.ids.opponentId) { else if (rollData.ids.opponentId) {
return ActorToken.fromActorId(rollData.ids.opponentId) return TokenActor.fromActorId(rollData.ids.opponentId)
} }
else { else {
const targets = Array.from(game.user.targets) const targets = Array.from(game.user.targets)
if (targets.length == 1) { if (targets.length == 1) {
return ActorToken.fromToken(targets[0]) return TokenActor.fromToken(targets[0])
} }
else { else {
return undefined return undefined

View File

@@ -1,6 +1,7 @@
export const ROLL_TYPE_ATTAQUE = 'attaque' export const ROLL_TYPE_ATTAQUE = 'attaque'
export const ROLL_TYPE_COMP = 'comp' export const ROLL_TYPE_COMP = 'comp'
export const ROLL_TYPE_CUISINE = 'cuisine'
export const ROLL_TYPE_DEFENSE = 'defense' export const ROLL_TYPE_DEFENSE = 'defense'
export const ROLL_TYPE_JEU = 'jeu' export const ROLL_TYPE_JEU = 'jeu'
export const ROLL_TYPE_MEDITATION = 'meditation' export const ROLL_TYPE_MEDITATION = 'meditation'
@@ -8,6 +9,12 @@ export const ROLL_TYPE_OEUVRE = 'oeuvre'
export const ROLL_TYPE_SORT = 'sort' export const ROLL_TYPE_SORT = 'sort'
export const ROLL_TYPE_TACHE = 'tache' export const ROLL_TYPE_TACHE = 'tache'
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 DIFF = { export const DIFF = {
LIBRE: 'libre', LIBRE: 'libre',
ATTAQUE: 'attaque', ATTAQUE: 'attaque',

View File

@@ -6,6 +6,10 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { PART_OEUVRE } from "./roll-part-oeuvre.mjs"; import { PART_OEUVRE } from "./roll-part-oeuvre.mjs";
import { RdDItemArme } from "../item/arme.js"; import { RdDItemArme } from "../item/arme.js";
import { RdDBonus } from "../rdd-bonus.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_DEFENSE, ROLL_TYPE_OEUVRE } from "./roll-constants.mjs";
import { PART_ATTAQUE } from "./roll-part-attaque.mjs";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RollDialogAdapter { export class RollDialogAdapter {
@@ -15,21 +19,22 @@ export class RollDialogAdapter {
carac: rollData.current.carac.value, carac: rollData.current.carac.value,
diff: rollData.current.totaldiff, diff: rollData.current.totaldiff,
bonus: rollData.current.bonus, bonus: rollData.current.bonus,
sign: rollData.current.sign,
showDice: rollData.options.showDice, showDice: rollData.options.showDice,
rollMode: rollData.current.rollmode.key rollMode: rollData.current.rollmode.key
}) })
const rolled = await RollDialogAdapter.rollChances(rollData, chances) const rolled = await RollDialogAdapter.rollChances(rollData, chances)
RollDialogAdapter.adjustRollDataForV1(rollData, rolled, rollTitle) RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle)
RollDialogAdapter.adjustRollDataForV1(rollData)
RollDialogAdapter.adjustAttaqueParticuliere(rollData)
RollDialogAdapter.adjustAttaqueDmg(rollData)
RollDialogAdapter.adjustDemiSurprise(rollData)
return rolled return rolled
} }
static computeChances({ carac, diff, bonus, sign, showDice, rollMode }) { static computeChances({ carac, diff, bonus, showDice, rollMode }) {
const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff)) const chances = foundry.utils.duplicate(RdDResolutionTable.computeChances(carac, diff))
RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff) RdDResolutionTable._updateChancesWithBonus(chances, bonus, diff)
RdDResolutionTable._updateChancesFactor(chances, sign)
chances.showDice = showDice chances.showDice = showDice
chances.rollMode = rollMode chances.rollMode = rollMode
return chances return chances
@@ -37,58 +42,112 @@ export class RollDialogAdapter {
static async rollChances(rollData, chances) { static async rollChances(rollData, chances) {
const rolled = await RdDResolutionTable.rollChances(chances, const rolled = await RdDResolutionTable.rollChances(chances,
rollData.current.sign, rollData.current.sign.diviseur,
rollData.current.resultat) rollData.current.resultat)
rolled.caracValue = rollData.current.carac.value rolled.caracValue = rollData.current.carac.value
rolled.finalLevel = rollData.current.totaldiff rolled.finalLevel = rollData.current.totaldiff
rolled.bonus = rollData.current.bonus ?? 0 rolled.bonus = rollData.current.bonus ?? 0
rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur) rolled.factorHtml = Misc.getFractionOneN(rollData.current.sign.diviseur)
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rolled.caracValue, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
}
return rolled return rolled
} }
static adjustRollDataForV1(rollData, rolled, rollTitle) { static setRollDataRolled(rollData, rolled, rollTitle) {
rollData.rolled = rolled
rollData.choix = rollData.choix ?? {}
rollData.show = rollData.show ?? {}
rollData.show.title = rollTitle
}
static adjustRollDataForV1(rollData) {
const rolled = rollData.rolled
// temporaire pour être homogène roll v1 // temporaire pour être homogène roll v1
rollData.alias = rollData.active.actor.getAlias() rollData.alias = rollData.active.actor.getAlias()
// pour experience // pour experience
rollData.finalLevel = rollData.current.totaldiff rollData.finalLevel = rollData.current.totaldiff
if (rollData.use == undefined) { rollData.use = {} } if (rollData.use == undefined) { rollData.use = {} }
if (rollData.show == undefined) { rollData.show = {} }
if (rollData.ajustements == undefined) { if (rollData.ajustements == undefined) {
rollData.ajustements = {} rollData.ajustements = {}
} }
rollData.selectedCarac = rollData.active.actor.system.carac[rollData.current.carac.key] rollData.selectedCarac = rollData.active.actor.getCaracByName(rollData.current.carac.key)
const compKey = rollData.current.comp?.key const compKey = rollData.current.comp?.key
if (compKey) { if (compKey) {
rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp rollData.competence = rollData.refs[PART_COMP].all.find(it => it.key == compKey)?.comp
rollData.jetResistance = rollData.type.jetResistance rollData.jetResistance = rollData.type.jetResistance
} }
if (rollData.type.current == ROLL_TYPE_OEUVRE) {
const oeuvreKey = rollData.current.oeuvre?.key const oeuvreKey = rollData.current.oeuvre?.key
if (oeuvreKey) { if (rollData.type.current == ROLL_TYPE_OEUVRE && oeuvreKey) {
const oeuvreCurrent = rollData.current[PART_OEUVRE]; const oeuvreCurrent = rollData.current[PART_OEUVRE];
rollData.oeuvre = oeuvreCurrent.oeuvre rollData.oeuvre = oeuvreCurrent.oeuvre
// rollData.oeuvre = rollData.refs[PART_OEUVRE].oeuvres.find(it => it.key == oeuvreKey)?.oeuvre
rollData.art = oeuvreCurrent.art.type rollData.art = oeuvreCurrent.art.type
} }
}
// pour appel moral // pour appel moral
rollData.diviseurSignificative = rollData.current.sign rollData.diviseurSignificative = rollData.current.sign
if (rollData.current[PART_APPELMORAL]?.checked) { if (rollData.current[PART_APPELMORAL]?.checked) {
rollData.use.moral = true rollData.use.moral = true
} }
rollData.rolled = rolled
if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) { if (ReglesOptionnelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = this.findNiveauNecessaire(carac, rolled.roll) rolled.niveauNecessaire = RdDResolutionTable.findNiveauNecessaire(rollData.selectedCarac.value, rolled.roll)
rolled.ajustementNecessaire = rolled.niveauNecessaire - diff rolled.ajustementNecessaire = rolled.niveauNecessaire - diff
} }
rollData.ajustements = rollData.ajustements.map(aj => { rollData.ajustements = rollData.ajustements.map(aj => { return { label: aj.label, value: aj.value } })
return {
used: true,
label: aj.label,
value: aj.diff,
descr: aj.diff == undefined ? aj.label : undefined
} }
})
rollData.show.title = rollTitle 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
}
const attaque = rollData.current.attaque;
const choix = []
const isEmpoignade = attaque.dmg.mortalite == 'empoignade';
const isCharge = attaque.tactique == 'charge'
/* TODO: cas de créatures faisant des lancers, Glou, Glipzouk */
const isMeleeDiffNegative = (attaque.comp.type == ITEM_TYPES.competencecreature || rollData.current.carac.key == CARACS.MELEE)
&& rollData.current.diff.value < 0
// force toujours, sauf empoignade
if (!isEmpoignade) {
choix.push(RDD_CONFIG.particuliere.force)
}
// finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
if (!isCharge && (isEmpoignade || isMeleeDiffNegative)) {
choix.push(RDD_CONFIG.particuliere.finesse)
}
// rapidité seulement en mêlée, si l'arme le permet, et si la difficulté libre est de -1 minimum
if (!isCharge && !isEmpoignade && isMeleeDiffNegative && attaque.arme.system.rapide) {
choix.push(RDD_CONFIG.particuliere.rapidite)
}
if (choix.length == 1) {
rollData.particuliere = choix[0].key
}
rollData.particulieres = choix
} }
static mapActionAttaque(attackerRoll) { static mapActionAttaque(attackerRoll) {
@@ -99,7 +158,6 @@ export class RollDialogAdapter {
return { return {
// correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque) // correspond à l'attaque de RollPartAttaque (dans rollDta.current.attaque)
label: label, label: label,
attaque: {
// correspond aux actions d'attaques dans RdDActor.listActionsAttaque // correspond aux actions d'attaques dans RdDActor.listActionsAttaque
name: label, name: label,
// action: 'attaque', // action: 'attaque',
@@ -109,7 +167,6 @@ export class RollDialogAdapter {
equipe: attackerRoll.arme.system.equipe, equipe: attackerRoll.arme.system.equipe,
// carac: { key: caracCode, value: caracValue }, // carac: { key: caracCode, value: caracValue },
// dommagesArme: dommagesArme, // dommagesArme: dommagesArme,
},
diff: attackerRoll.diffLibre, diff: attackerRoll.diffLibre,
particuliere: attackerRoll.particuliere, particuliere: attackerRoll.particuliere,
tactique: RdDBonus.find(attackerRoll.tactique), tactique: RdDBonus.find(attackerRoll.tactique),

View File

@@ -39,26 +39,29 @@ import { RollDialogAdapter } from "./roll-dialog-adapter.mjs";
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"; import { ROLLDIALOG_SECTION } from "./roll-part.mjs";
import { ROLL_TYPE_COMP } from "./roll-constants.mjs"; import { ROLL_TYPE_COMP } from "./roll-constants.mjs";
import ChatRollResult from "./chat-roll-result.mjs"; import ChatRollResult from "./chat-roll-result.mjs";
import { renderTemplate } from "../constants.js";
import { RollTypeCuisine } from "./roll-type-cuisine.mjs";
import { RollPartCuisine } from "./roll-part-cuisine.mjs";
import { OptionsAvancees, ROLL_DIALOG_V2_TEST } from "../settings/options-avancees.js";
import { ActorImpacts } from "../technical/actor-impacts.mjs";
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api
const doNothing = (dialog) => { }
const ALL_ROLL_TYPES = [ export const ALL_ROLL_TYPES = [
new RollTypeComp(), new RollTypeComp(),
new RollTypeTache(), new RollTypeTache(),
new RollTypeAttaque(), new RollTypeAttaque(),
new RollTypeDefense(), new RollTypeDefense(),
new RollTypeSort(), new RollTypeSort(),
new RollTypeMeditation(), new RollTypeMeditation(),
new RollTypeCuisine(),
new RollTypeOeuvre(), new RollTypeOeuvre(),
new RollTypeJeu(), new RollTypeJeu(),
// new RollTypeResistance ?? // new RollTypeResistance ??
// new RollTypeFixedCarac ?? // new RollTypeFixedCarac ??
] ]
const BASIC_PARTS = new RollBasicParts()
const ROLL_PARTS = [ const ROLL_PARTS = [
new RollPartActor(), new RollPartActor(),
new RollPartAction(), new RollPartAction(),
@@ -72,6 +75,7 @@ const ROLL_PARTS = [
new RollPartMeditation(), new RollPartMeditation(),
new RollPartSort(), new RollPartSort(),
new RollPartTache(), new RollPartTache(),
new RollPartCuisine(),
new RollPartOeuvre(), new RollPartOeuvre(),
new RollPartJeu(), new RollPartJeu(),
@@ -169,6 +173,15 @@ const ROLL_PARTS = [
/* -------------------------------------------- */ /* -------------------------------------------- */
export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2) export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2)
{ {
static onCloseDoNothing() {
}
static onRollDoneDoNothing(dialog, roll) {
dialog.render()
}
static onRollDoneClose(dialog, roll) {
if (roll.type.retry || !OptionsAvancees.isUsing(ROLL_DIALOG_V2_TEST))
dialog.close()
}
static init() { static init() {
} }
@@ -186,7 +199,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
ChatRollResult.onReady() 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)) foundry.applications.handlebars.loadTemplates(ROLL_PARTS.map(p => p.template))
ROLL_PARTS.forEach(p => p.onReady()) ROLL_PARTS.forEach(p => p.onReady())
@@ -224,6 +237,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
static async create(rollData, rollOptions = {}) { static async create(rollData, rollOptions = {}) {
const rollDialog = new RollDialog(rollData, rollOptions) const rollDialog = new RollDialog(rollData, rollOptions)
rollDialog.render(true) rollDialog.render(true)
return rollDialog
} }
static get PARTS() { static get PARTS() {
@@ -256,13 +270,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
rollData.selected = rollData.selected ?? {} rollData.selected = rollData.selected ?? {}
rollData.type = rollData.type ?? {} rollData.type = rollData.type ?? {}
rollData.type.retry = rollData.type.retry ?? false rollData.type.retry = rollData.type.retry ?? false
BASIC_PARTS.restore(rollData) RollBasicParts.restore(rollData)
const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code const potential = ALL_ROLL_TYPES.find(m => m.code == rollData.type.current)?.code
const allowed = rollData.type.retry && potential const allowed = rollData.type.retry && potential
? [potential] ? [potential]
: (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code)) : (rollData.type.allowed ?? ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)).map(m => m.code) ?? [ROLL_TYPE_COMP])
const rollType = allowed.find(c => c == rollData.type.current) ?? (allowed.length > 0 ? allowed[0].code : ROLL_TYPE_COMP); const rollType = allowed.find(c => c == rollData.type.current) ?? allowed[0]
rollData.type.allowed = allowed rollData.type.allowed = allowed
rollData.type.current = rollType rollData.type.current = rollType
@@ -272,29 +286,37 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") } rollData.options = rollData.options ?? { rollMode: game.settings.get("core", "rollMode") }
ROLL_PARTS.forEach(p => p.initialize(rollData)) ROLL_PARTS.forEach(p => p.initialize(rollData))
ROLL_PARTS.forEach(p => p.restore(rollData))
ROLL_PARTS.filter(p => p.isValid(rollData)) ROLL_PARTS.filter(p => p.isValid(rollData))
.forEach(p => { .forEach(p => {
p.restore(rollData)
p.loadRefs(rollData) p.loadRefs(rollData)
p.prepareContext(rollData) p.prepareContext(rollData)
}) })
return rollData return rollData
} }
static saveParts(rollData) { static saveParts(rollData, impacts) {
const target = BASIC_PARTS.initFrom(rollData) const target = RollBasicParts.initFrom(rollData)
ROLL_PARTS.filter(p => p.isActive(rollData)) ROLL_PARTS.filter(p => p.isActive(rollData))
.forEach(p => p.storeClean(rollData, target)) .forEach(p => p.storeClean(rollData, target))
target.attackerRoll = rollData.attackerRoll target.attackerRoll = rollData.attackerRoll
target.rolled = rollData.rolled target.rolled = rollData.rolled
target.result = rollData.result target.result = rollData.result
target.done = target.done ?? {} target.done = rollData.done ?? {}
target.dmg = rollData.dmg
if (impacts) {
target.reverse = {
active: impacts.active?.reverseImpacts(),
opponent: impacts.opponent?.reverseImpacts()
}
}
return target return target
} }
constructor(rollData, rollOptions) { constructor(rollData, rollOptions) {
super() super()
this.hooks = []
this.rollData = RollDialog.$prepareRollData(rollData) this.rollData = RollDialog.$prepareRollData(rollData)
this.rollOptions = { this.rollOptions = {
callbacks: [ callbacks: [
@@ -302,13 +324,28 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
async r => await r.active.actor.appliquerAppelMoral(r), async r => await r.active.actor.appliquerAppelMoral(r),
...(rollOptions.callbacks ?? []) ...(rollOptions.callbacks ?? [])
], ],
customChatMessage: rollOptions.customChatMessage, onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing,
onRollDone: rollOptions.onRollDone ?? doNothing onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing
} }
this.chatRollResult = new ChatRollResult(); this.chatRollResult = new ChatRollResult()
this.selectType() 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() { selectType() {
const selectedType = this.getSelectedType(); const selectedType = this.getSelectedType();
this.rollData.type.label = selectedType.title(this.rollData) this.rollData.type.label = selectedType.title(this.rollData)
@@ -324,16 +361,16 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return ROLL_PARTS.filter(p => p.isActive(rollData)) return ROLL_PARTS.filter(p => p.isActive(rollData))
} }
// get title() {
// return this.rollData.title ?? `Jet de dés de ${this.rollData.active.actor.name}`
// }
rollTitle(rollData) { rollTitle(rollData) {
return rollData.label ?? ROLL_PARTS const title = rollData.label ?? ROLL_PARTS
.filter(it => it.section == ROLLDIALOG_SECTION.ACTION) .filter(it => it.section == ROLLDIALOG_SECTION.ACTION)
.filter(it => it.isActive(rollData)) .filter(it => it.isActive(rollData))
.map(it => it.title(rollData)) .map(it => it.title(rollData))
.reduce(Misc.joining(' ')) .reduce(Misc.joining(' '));
if (this.rollOptions.title) {
return `${this.rollOptions.title} ${title}`
}
return title
} }
async _onRender(context, options) { async _onRender(context, options) {
@@ -364,11 +401,11 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return RollDialog.getActiveParts(rollData) return RollDialog.getActiveParts(rollData)
.map(p => p.getAjustements(rollData)) .map(p => p.getAjustements(rollData))
.reduce((a, b) => a.concat(b)) .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) { async buildHTMLTable(carac, diff) {
return await foundry.applications.handlebars.renderTemplate('roll-table', { carac, diff }) return await renderTemplate('roll-table', { carac, diff })
} }
async _prepareContext() { async _prepareContext() {
@@ -376,7 +413,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData)) const types = ALL_ROLL_TYPES.filter(m => m.isAllowed(rollData) && m.visible(rollData))
.map(m => m.toTypeData(rollData)) .map(m => m.toTypeData(rollData))
BASIC_PARTS.loadSurprises(rollData, this.getSelectedType().code) RollBasicParts.loadSurprises(rollData, this.getSelectedType().code)
rollData.type.label = this.getSelectedType()?.title(rollData) rollData.type.label = this.getSelectedType()?.title(rollData)
//TOCHECK: set type.label ? //TOCHECK: set type.label ?
const visibleRollParts = RollDialog.getActiveParts(rollData) const visibleRollParts = RollDialog.getActiveParts(rollData)
@@ -386,7 +423,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
visibleRollParts.forEach(p => p.prepareContext(rollData)) visibleRollParts.forEach(p => p.prepareContext(rollData))
RollDialog.calculAjustements(rollData) RollDialog.calculAjustement(rollData)
const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData()) const templates = RollDialog.getActiveParts(rollData).map(p => p.toTemplateData())
const context = await super._prepareContext() const context = await super._prepareContext()
@@ -408,12 +445,11 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
} }
} }
static calculAjustements(rollData) { static calculAjustement(rollData) {
rollData.ajustements = RollDialog.getAjustements(rollData) rollData.ajustements = RollDialog.getAjustements(rollData)
rollData.ajustements.forEach(it => it.isDiff = it.diff != undefined)
rollData.current.totaldiff = rollData.ajustements rollData.current.totaldiff = rollData.ajustements
.map(adj => adj.diff) .filter(a => a.value != undefined)
.filter(d => d != undefined) .map(a => a.value)
.reduce(Misc.sum(), 0) .reduce(Misc.sum(), 0)
} }
@@ -421,34 +457,52 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current) 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() { async roll() {
// ROLL_PARTS.filter(p => p.isActive(this.rollData))
// .forEach(p => p.validate(this.rollData))
const roll = RollDialog.saveParts(this.rollData) const roll = RollDialog.saveParts(this.rollData)
RollDialog.loadRollData(roll) RollDialog.loadRollData(roll)
const selectedRollType = this.getSelectedType(roll);
selectedRollType.onSelect(roll)
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1 roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1
roll.rolled = await this.$rollDice(roll) roll.choix = {}
roll.result = this.getSelectedType(roll).getResult(roll) roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll))
console.info('RollDialog.roll:', roll)
await Promise.all(this.rollOptions.callbacks.map(async callback => await callback(roll)))
await this.chatRollResult.display(roll)
this.rollOptions.onRollDone(this) const impacts = new ActorImpacts(roll.active)
roll.result = selectedRollType.getResult(roll, impacts)
console.info('RollDialog.roll:', roll)
const callbacks = [
...this.rollOptions.callbacks,
...selectedRollType.callbacks(this.rollOptions),
]
await Promise.all(callbacks.map(async callback => await callback(roll)))
await impacts.applyImpacts()
selectedRollType.onApplyImpacts(roll, impacts)
await this.chatRollResult.display(roll, impacts)
this.rollOptions.onRollDone(this, roll)
} }
static loadRollData(roll) { static loadRollData(roll) {
RollDialog.$prepareRollData(roll) RollDialog.$prepareRollData(roll)
RollDialog.calculAjustements(roll) RollDialog.calculAjustement(roll)
roll.v2 = true roll.v2 = true
return roll
} }
async defaultCallback(rollData, rolled) { async defaultCallback(roll, rolled) {
await rollData.active.actor.appliquerAjoutExperience(rollData) await roll.active.actor.appliquerAjoutExperience(roll)
await rollData.active.actor.appliquerAppelMoral(rollData) await roll.active.actor.appliquerAppelMoral(roll)
} }
async $rollDice(rollData) {
return await RollDialogAdapter.rollDice(rollData, this.rollTitle(rollData))
}
} }

View File

@@ -1,8 +1,8 @@
import { RdDBonus } from "../rdd-bonus.js" import { RdDBonus } from "../rdd-bonus.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
import { PART_DIFF } from "./roll-part-diff.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs" import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
@@ -23,7 +23,8 @@ export class RollPartAttaque extends RollPartSelect {
refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor)) refs.attaques = attaques.map(it => RollPartAttaque.$extractAttaque(it, rollData.active.actor))
refs.tactiques = TACTIQUES refs.tactiques = TACTIQUES
if (refs.attaques.length > 0) { if (refs.attaques.length > 0) {
this.$selectAttaque(rollData) const attaque = this.findAttaque(refs.attaques, this.getSaved(rollData))
this.$selectAttaque(rollData, attaque?.key)
} }
} }
@@ -33,19 +34,26 @@ export class RollPartAttaque extends RollPartSelect {
} }
restore(rollData) { restore(rollData) {
const saved = this.getSaved(rollData)
super.restore(rollData) super.restore(rollData)
if (saved.dmg) {
this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg this.getCurrent(rollData).dmg = this.getSaved(rollData).dmg
} }
}
findAttaque(attaques, saved) {
return attaques.find(at => at.arme.id == saved?.arme?.id &&
at.comp.id == saved?.comp?.id
)
}
choices(refs) { return refs.attaques } choices(refs) { return refs.attaques }
static $extractAttaque(attaque, actor) { static $extractAttaque(attaque, actor) {
return { attaque.key = `${attaque.action}::${attaque.label}`
key: `${attaque.action}::${attaque.name}`, attaque.tactique = TACTIQUES[0]
label: attaque.name, attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
attaque: attaque, return attaque
tactique: TACTIQUES[0],
}
} }
prepareContext(rollData) { prepareContext(rollData) {
@@ -55,14 +63,9 @@ export class RollPartAttaque extends RollPartSelect {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
const ajustements = [] const tactique = current.tactique ? [{ label: current.tactique.label, value: current.tactique.attaque }] : []
if (current.tactique) { const surprise = rollData.opponent?.surprise ? [{ label: rollData.opponent.surprise.label, value: rollData.opponent.surprise.attaque }] : []
ajustements.push({ label: current.tactique.label, diff: current.tactique.attaque }) return [...tactique, ...surprise]
}
if (rollData.opponent?.surprise) {
ajustements.push({ label: rollData.opponent.surprise.label, diff: rollData.opponent.surprise.attaque })
}
return ajustements
} }
@@ -100,8 +103,14 @@ export class RollPartAttaque extends RollPartSelect {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
switch (part.code) { switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current.attaque.carac.key]) case PART_CARAC: return part.filterCaracs(rollData, [current.carac.key])
case PART_COMP: return part.filterComps(rollData, [current.attaque.comp?.name]) case PART_COMP: return part.filterComps(rollData, [current.comp.name])
case PART_DIFF: {
if (current.initialDiff) {
part.setDiff(rollData, { type: DIFF.ATTAQUE, value: current.initialDiff })
current.initialDiff = undefined
}
}
} }
} }
return undefined return undefined

View File

@@ -28,16 +28,14 @@ export class RollPartCheckbox extends RollPart {
/* TODO: user setting? */ /* TODO: user setting? */
current.checked = true current.checked = true
} }
if (current.value == undefined) {
current.value = this.getCheckboxValue(rollData) current.value = this.getCheckboxValue(rollData)
}
current.icon = this.getCheckboxIcon(rollData) current.icon = this.getCheckboxIcon(rollData)
} }
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.checked) { if (current.checked) {
return [{ label: this.getCheckboxLabelAjustement(rollData), diff: current.value }] return [{ label: this.getCheckboxLabelAjustement(rollData), value: current.value }]
} }
return [] return []
} }

View File

@@ -47,7 +47,7 @@ export class RollPartCoeur extends RollPartSelect {
if (current.key != '') { if (current.key != '') {
return [{ return [{
label: "Coeur pour " + current.label, label: "Coeur pour " + current.label,
diff: current.value value: current.value
}] }]
} }
return [] return []

View File

@@ -17,7 +17,13 @@ export class RollPartComp extends RollPartSelect {
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
const selected = this.getSelected(rollData)
refs.all = this.$getActorComps(rollData) refs.all = this.$getActorComps(rollData)
.filter(comp => !selected.forced ||
(selected.key ?
Grammar.includesLowerCaseNoAccent(comp.name, selected.key)
: comp.key == '')
)
refs.comps = refs.all refs.comps = refs.all
this.$selectComp(rollData) this.$selectComp(rollData)
} }
@@ -26,7 +32,7 @@ export class RollPartComp extends RollPartSelect {
$getActorComps(rollData) { $getActorComps(rollData) {
const competences = (rollData.active.actor?.getCompetences() ?? []) const competences = (rollData.active.actor?.getCompetences() ?? [])
.map(RollPartComp.$extractComp) .map(RollPartComp.extractComp)
.sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label))) .sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label)))
/* TODO: filter competences */ /* TODO: filter competences */
const listCompetences = [ const listCompetences = [
@@ -36,7 +42,7 @@ export class RollPartComp extends RollPartSelect {
return listCompetences return listCompetences
} }
static $extractComp(comp) { static extractComp(comp) {
return { return {
key: comp.name, key: comp.name,
label: comp.name, label: comp.name,
@@ -45,13 +51,16 @@ export class RollPartComp extends RollPartSelect {
} }
} }
filterComps(rollData, allowed = []) { filterComps(rollData, allowed = [], sorting = undefined) {
const sans = allowed.includes('')
allowed = allowed.filter(it => it != undefined) allowed = allowed.filter(it => it != undefined)
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
refs.comps = allowed.length > 0 refs.comps = allowed.length > 0
// ? refs.all.filter(it => allowed.includes(Grammar.toLowerCaseNoAccent(it.label))) ? refs.all.filter(it => allowed.includes(it.label) || (sans && it.key == ''))
? refs.all.filter(it => allowed.includes(it.label))
: refs.all : refs.all
if (sorting && refs.comps.length > 0) {
refs.comps.sort(sorting)
}
this.$selectComp(rollData) this.$selectComp(rollData)
} }
@@ -60,7 +69,7 @@ export class RollPartComp extends RollPartSelect {
} }
setSpecialComp(rollData, comps) { setSpecialComp(rollData, comps) {
this.getRefs(rollData).comps = comps.map(RollPartComp.$extractComp) this.getRefs(rollData).comps = comps.map(RollPartComp.extractComp)
.sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label))) .sort(Misc.ascending(it => Grammar.toLowerCaseNoAccentNoSpace(it.label)))
} }

View File

@@ -57,7 +57,7 @@ export class RollPartConditions extends RollPart {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.value != 0) { if (current.value != 0) {
return [{ label: DESCR_CONDITIONS, diff: current.value }] return [{ label: DESCR_CONDITIONS, value: current.value }]
} }
return [] return []
} }

View File

@@ -0,0 +1,174 @@
import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_CUISINE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_CUISINE = "cuisine"
export class RollPartCuisine extends RollPartSelect {
onReady() {
foundry.applications.handlebars.loadTemplates({ 'roll-oeuvre-recettecuisine': `systems/foundryvtt-reve-de-dragon/templates/roll/roll-oeuvre-recettecuisine.hbs` })
}
get code() { return PART_CUISINE }
get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_CUISINE) }
restore(rollData) {
super.restore(rollData)
this.$restoreSavedOptions(rollData)
}
store(rollData, targetData) {
const current = this.getCurrent(rollData)
this.setSaved(targetData, {
key: current.key,
fabriquer: current.fabriquer,
proportions: current.proportions,
value: current.value,
})
}
loadRefs(rollData) {
const refs = this.getRefs(rollData)
const actor = rollData.active.actor
refs.cuisine = actor.getCompetence('Cuisine')
const recettes = actor.items
.filter(it => it.type == ITEM_TYPES.recettecuisine)
.map(RollPartCuisine.$extractPreparationRecette)
const ingredientsBruts = actor.items
.filter(it => it.getUtilisationCuisine() == 'brut')
.map(RollPartCuisine.$extractPreparationBrut)
refs.preparations = [RollPartCuisine.$preparationBasique(), ...recettes, ...ingredientsBruts]
refs.preparations.forEach(p => p.comp = refs.cuisine)
if (refs.preparations.length > 0) {
this.$selectPreparation(rollData)
this.$restoreSavedOptions(rollData)
}
}
$restoreSavedOptions(rollData) {
const saved = this.getSaved(rollData)
const current = this.getCurrent(rollData)
if (saved.fabriquer != undefined) {
current.fabriquer = saved.fabriquer
}
if (saved.proportions != undefined) {
current.proportions = saved.proportions
}
if (saved.value != undefined) {
current.value = saved.value
}
}
choices(refs) { return refs.preparations }
static $preparationBasique() {
return {
key: '',
label: "Improvisation du moment",
img: RollPartCuisine.$getImgIngredient(),
sust: 1,
exotisme: 0,
ingredients: "Ce qu'il y a sous la main",
proportions: 8,
proportionsMax: 50,
value: 0,
fabriquer: false,
}
}
static $extractPreparationRecette(recette) {
const proportions = recette.system.sust ?? 1
return {
key: recette.id,
label: recette.name,
img: 'systems/foundryvtt-reve-de-dragon/icons/cuisine/ragout.svg',
sust: 1,
exotisme: recette.system.exotisme,
ingredients: recette.system.ingredients,
proportions: proportions,
proportionsMax: proportions * 10,
value: -recette.system.niveau,
recette: recette,
fabriquer: true,
}
}
static $extractPreparationBrut(ingredient) {
return {
key: ingredient.id,
label: ingredient.name + ' cuisiné',
img: RollPartCuisine.$getImgIngredient(ingredient.type),
sust: ingredient.system.sust ?? 1,
exotisme: ingredient.system.exotisme,
ingredients: ingredient.name,
proportions: Math.min(10, ingredient.system.quantite),
proportionsMax: Math.min(50, ingredient.system.quantite),
value: 0,
ingredient: ingredient,
fabriquer: true,
}
}
static $getImgIngredient(type = ITEM_TYPES.ingredient) {
switch (type) {
case ITEM_TYPES.herbe:
case ITEM_TYPES.plante:
return `systems/foundryvtt-reve-de-dragon/icons/cuisine/${type}.svg`
case ITEM_TYPES.faune:
return 'systems/foundryvtt-reve-de-dragon/icons/cuisine/gibier.svg'
}
return 'systems/foundryvtt-reve-de-dragon/icons/cuisine/ragout.svg'
}
$selectPreparation(rollData, key) {
this.selectByKey(rollData, key, 0)
}
async _onRender(rollDialog, context, options) {
const current = this.getCurrent(rollDialog.rollData)
const selectPreparation = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-preparation"]`)
const inputDiff = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="diff-var"]`)
const checkboxFabriquer = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="fabriquer"]`)
const inputProportions = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="proportions"]`)
selectPreparation.addEventListener("change", e => {
const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex
this.$selectPreparation(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render()
})
checkboxFabriquer?.addEventListener("change", e => {
current.fabriquer = e.currentTarget.checked
})
inputDiff?.addEventListener("change", e => {
current.value = parseInt(e.currentTarget.value)
})
inputProportions?.addEventListener("change", e => {
current.proportions = parseInt(e.currentTarget.value)
})
}
impactOtherPart(part, rollData) {
if (this.visible(rollData)) {
switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [CARACS.ODORATGOUT])
case PART_COMP: return part.filterComps(rollData, [this.getRefs(rollData).cuisine.name])
}
}
return undefined
}
}

View File

@@ -1,9 +1,6 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js" import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
import { RdDBonus } from "../rdd-bonus.js"
import { CARACS } from "../rdd-carac.js" import { CARACS } from "../rdd-carac.js"
import { StatusEffects } from "../settings/status-effects.js"
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
@@ -34,7 +31,7 @@ export class RollPartDefense extends RollPartSelect {
.map(it => RollPartDefense.$extractEsquive(it, defenseur)) .map(it => RollPartDefense.$extractEsquive(it, defenseur))
const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier())) const parades = defenseur.items.filter(it => it.isParade() && (!refs.isDistance || it.isBouclier()))
.map(it => RollPartDefense.$extractParade(it, attackerRoll?.attaque.arme, defenseur)) .map(it => RollPartDefense.$extractParade(it, attackerRoll?.arme, defenseur))
refs.defenses = [...esquives, ...parades].filter(it => it != undefined) refs.defenses = [...esquives, ...parades].filter(it => it != undefined)
this.$selectDefense(rollData) this.$selectDefense(rollData)
@@ -113,21 +110,24 @@ export class RollPartDefense extends RollPartSelect {
isArmeDisparate(rollData) { isArmeDisparate(rollData) {
const armeDefense = this.getCurrent(rollData).arme const armeDefense = this.getCurrent(rollData).arme
if (armeDefense) { if (armeDefense) {
const armeAttaque = rollData.attackerRoll?.attaque.arme const armeAttaque = rollData.attackerRoll?.current.attaque.arme
return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign' return RdDItemArme.defenseArmeParade(armeAttaque, armeDefense) == 'sign'
} }
return false return false
} }
getDiffDefense(rollData) { getDiffDefense(rollData) {
const current = this.getCurrent(rollData)
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
if (refs.isDistance || !rollData.attackerRoll) { if (refs.isDistance || !rollData.attackerRoll) {
// Déterminer la difficulté de parade // TODO: Déterminer la difficulté de parade
return { diff: 0, type: DIFF.LIBRE } return { diff: 0, type: DIFF.LIBRE }
} }
else { 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 }
} }
} }
} }

View File

@@ -1,10 +1,15 @@
import { DIFF, DIFFS, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_SORT, ROLL_TYPE_TACHE } from "./roll-constants.mjs"; import { DIFF, DIFFS, ROLL_TYPE_CUISINE, ROLL_TYPE_MEDITATION, ROLL_TYPE_OEUVRE, ROLL_TYPE_SORT, ROLL_TYPE_TACHE } from "./roll-constants.mjs";
import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs"; import { ROLLDIALOG_SECTION, RollPart } from "./roll-part.mjs";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
export const PART_DIFF = "diff" export const PART_DIFF = "diff"
const EXCLUDED_ROLL_TYPES = [ROLL_TYPE_TACHE, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT, ROLL_TYPE_OEUVRE] const EXCLUDED_ROLL_TYPES = [
ROLL_TYPE_TACHE,
ROLL_TYPE_MEDITATION,
ROLL_TYPE_SORT,
ROLL_TYPE_CUISINE,
ROLL_TYPE_OEUVRE]
export class RollPartDiff extends RollPart { export class RollPartDiff extends RollPart {
@@ -51,17 +56,17 @@ export class RollPartDiff extends RollPart {
) )
} }
setDiff(rollData, diffDefense) { setDiff(rollData, diff) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
current.value = diffDefense.diff current.value = diff.diff ?? current.value
current.type = diffDefense.type current.type = diff.type ?? current.type
} }
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
return [{ return [{
label: current.label, label: current.label,
diff: current.value value: current.value
}] }]
} }

View File

@@ -1,15 +1,16 @@
import { Grammar } from "../grammar.js"
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { CARACS } from "../rdd-carac.js" import { CARACS } from "../rdd-carac.js"
import { ROLL_TYPE_JEU } from "./roll-constants.mjs" import { ROLL_TYPE_JEU } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP, RollPartComp } from "./roll-part-comp.mjs"
import { RollPartSelect } from "./roll-part-select.mjs" import { RollPartSelect } from "./roll-part-select.mjs"
import { ROLLDIALOG_SECTION } from "./roll-part.mjs" import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
import { RdDItem } from "../item.js"
import { Misc } from "../misc.js"
export const PART_JEU = "jeu" export const PART_JEU = "jeu"
const COMPETENCE_JEU = 'Jeu' export const COMPETENCE_JEU = 'Jeu'
export class RollPartJeu extends RollPartSelect { export class RollPartJeu extends RollPartSelect {
@@ -21,8 +22,12 @@ export class RollPartJeu extends RollPartSelect {
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
refs.jeux = rollData.active.actor.itemTypes[ITEM_TYPES.jeu] const actor = rollData.active.actor
.map(it => RollPartJeu.$extractJeu(it, rollData.active.actor)) const compJeu = actor.getCompetence(COMPETENCE_JEU)
refs.jeux = actor.itemTypes[ITEM_TYPES.jeu]
.map(it => RollPartJeu.$extractJeu(it, compJeu))
if (refs.jeux.length > 0) { if (refs.jeux.length > 0) {
this.$selectJeu(rollData) this.$selectJeu(rollData)
} }
@@ -30,18 +35,17 @@ export class RollPartJeu extends RollPartSelect {
choices(refs) { return refs.jeux } choices(refs) { return refs.jeux }
static $extractJeu(jeu, actor) { static $extractJeu(jeu, compJeu) {
const comp = actor.getCompetence(COMPETENCE_JEU)
const caracs = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim()) const caracs = jeu.system.caraccomp.toLowerCase().split(/[.,:\/-]/).map(it => it.trim())
const base = RollPartJeu.$getJeuBase(jeu, comp, caracs) const base = RollPartJeu.$getJeuBase(jeu, compJeu, caracs)
return { return {
key: jeu.id, key: jeu.id,
label: jeu.name, label: jeu.name,
caracs: caracs, caracs: caracs,
jeu: jeu, jeu: jeu,
value: (base ?? comp).system.niveau, value: 0,
base: base, base: base,
comp: comp comp: compJeu
} }
} }
@@ -49,10 +53,10 @@ export class RollPartJeu extends RollPartSelect {
if (jeu.system.base < comp.system.niveau) { if (jeu.system.base < comp.system.niveau) {
return undefined return undefined
} }
return { return new RdDItem({
id: comp.id, id: comp.id,
name: `Jeu ${jeu.name}`, name: `Jeu ${Misc.lowerFirst(jeu.name)}`,
type: comp.type, type: ITEM_TYPES.competence,
img: comp.img, img: comp.img,
system: foundry.utils.mergeObject( system: foundry.utils.mergeObject(
{ {
@@ -61,9 +65,9 @@ export class RollPartJeu extends RollPartSelect {
default_carac: caracs.length > 0 ? caracs[0] : CARACS.CHANCE default_carac: caracs.length > 0 ? caracs[0] : CARACS.CHANCE
}, },
comp.system, comp.system,
{ inplace: true, overwrite: false } { overwrite: false }
) )
} })
} }
prepareContext(rollData) { prepareContext(rollData) {
@@ -77,6 +81,15 @@ export class RollPartJeu extends RollPartSelect {
$selectJeu(rollData, key) { $selectJeu(rollData, key) {
this.selectByKey(rollData, key, 0) this.selectByKey(rollData, key, 0)
if (rollData.type.current == ROLL_TYPE_JEU) {
RollPartJeu.forceCompJeu(rollData)
}
}
static forceCompJeu(rollData) {
const jeu = rollData.current[PART_JEU].base ?? rollData.current[PART_JEU].comp
rollData.refs[PART_COMP].comps = [jeu].map(it => RollPartComp.extractComp(it))
rollData.current[PART_COMP] = rollData.refs[PART_COMP].comps[0]
} }
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {

View File

@@ -11,26 +11,41 @@ import { ROLLDIALOG_SECTION } from "./roll-part.mjs"
export const PART_MEDITATION = "meditation" export const PART_MEDITATION = "meditation"
const COMPORTEMENTS = ['isComportement', 'isHeure', 'isPurification', 'isVeture']
export class RollPartMeditation extends RollPartSelect { export class RollPartMeditation extends RollPartSelect {
get code() { return PART_MEDITATION } get code() { return PART_MEDITATION }
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
store(rollData, targetData) {
const current = this.getCurrent(rollData)
this.setSaved(targetData, {
key: current.key,
isComportement: current.isComportement,
isHeure: current.isHeure,
isPurification: current.isPurification,
isVeture: current.isVeture
})
}
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_MEDITATION) } visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_MEDITATION) }
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
foundry.utils.mergeObject(refs, refs.meditations = rollData.active.actor.itemTypes[ITEM_TYPES.meditation]
{
meditations: rollData.active.actor.itemTypes[ITEM_TYPES.meditation]
.map(it => RollPartMeditation.$extractMeditation(it, rollData.active.actor)) .map(it => RollPartMeditation.$extractMeditation(it, rollData.active.actor))
}
)
if (refs.meditations.length > 0) { if (refs.meditations.length > 0) {
this.$selectMeditation(rollData) this.$selectMeditation(rollData)
this.$selectConditionMeditation(rollData)
const selected = this.getSelected(rollData)
const current = this.getCurrent(rollData)
COMPORTEMENTS.filter(it => selected[it]).forEach(it => current[it] = selected[it])
} }
} }
choices(refs) { return refs.meditations } choices(refs) { return refs.meditations }
static $extractMeditation(meditation, actor) { static $extractMeditation(meditation, actor) {
@@ -48,12 +63,7 @@ export class RollPartMeditation extends RollPartSelect {
getMalusConditions(rollData) { getMalusConditions(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
const conditionsManquantes = [ const conditionsManquantes = COMPORTEMENTS.filter(it => !current[it]).length
current.isComportement,
current.isHeure,
current.isPurification,
current.isVeture
].filter(it => !it).length
return -2 * conditionsManquantes return -2 * conditionsManquantes
} }
@@ -62,22 +72,28 @@ export class RollPartMeditation extends RollPartSelect {
} }
getAjustements(rollData) { getAjustements(rollData) {
const malusEchecs = { label: "Méditation", diff: this.getMalusEchecs(rollData) } const malus = this.getMalusEchecs(rollData)
const malusConditions = { label: "Conditions", diff: this.getMalusConditions(rollData) } const malusEchecs = malusEchecs == 0 ? [] : [{ label: "Méditation", value: malus }]
return [malusConditions, ...(malusEchecs.diff == 0 ? [] : [malusEchecs])] const malusConditions = { label: "Conditions", value: this.getMalusConditions(rollData) }
return [malusConditions, ...malusEchecs]
} }
$selectMeditation(rollData, key) { $selectMeditation(rollData, key) {
const previous = this.getCurrent(rollData) const previous = this.getCurrent(rollData)
const current = this.selectByKey(rollData, key, 0) const current = this.selectByKey(rollData, key, 0)
if (current.key != previous.key) { if (current.key != previous.key) {
const heureMonde = RdDTimestamp.getWorldTime().heure this.$selectConditionMeditation(rollData)
const heureMeditation = RdDTimestamp.findHeure(current.meditation.system.heure)?.heure
current.isHeure = heureMeditation == heureMonde
current.isTMR = Grammar.equalsInsensitive(current.meditation.system.tmr, TMRUtility.getTMRType(rollData.active.actor.system.reve.tmrpos.coord))
} }
} }
$selectConditionMeditation(rollData) {
const current = this.getCurrent(rollData)
current.heureMonde = RdDTimestamp.getWorldTime().heure
current.heureMeditation = RdDTimestamp.findHeure(current.meditation.system.heure)?.heure
current.isHeure = current.heureMeditation == current.heureMonde
current.isTMR = Grammar.equalsInsensitive(current.meditation.system.tmr, TMRUtility.getTMRType(rollData.active.actor.system.reve.tmrpos.coord))
}
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const selectMeditation = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-meditation"]`) const selectMeditation = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-meditation"]`)
@@ -88,10 +104,7 @@ export class RollPartMeditation extends RollPartSelect {
rollDialog.render() rollDialog.render()
}) })
this.setupListenerCondition(rollDialog, 'isComportement') COMPORTEMENTS.forEach(it => this.setupListenerCondition(rollDialog, it))
this.setupListenerCondition(rollDialog, 'isHeure')
this.setupListenerCondition(rollDialog, 'isPurification')
this.setupListenerCondition(rollDialog, 'isVeture')
} }
setupListenerCondition(rollDialog, inputName) { setupListenerCondition(rollDialog, inputName) {

View File

@@ -11,6 +11,7 @@ export const PART_OEUVRE = "oeuvre"
const ARTS = [ const ARTS = [
{ type: ITEM_TYPES.oeuvre, action: "interpréte l'oeuvre", competence: it => it.system.competence, caracs: it => [it.system.default_carac] }, { type: ITEM_TYPES.oeuvre, action: "interpréte l'oeuvre", competence: it => it.system.competence, caracs: it => [it.system.default_carac] },
{ type: ITEM_TYPES.musique, action: "joue le morceau:", competence: it => 'Musique', caracs: it => [CARACS.OUIE] },
{ type: ITEM_TYPES.chant, action: "chante", competence: it => 'Chant', caracs: it => [CARACS.OUIE] }, { type: ITEM_TYPES.chant, action: "chante", competence: it => 'Chant', caracs: it => [CARACS.OUIE] },
{ {
type: ITEM_TYPES.danse, action: "danse:", competence: it => 'Danse', caracs: it => { type: ITEM_TYPES.danse, action: "danse:", competence: it => 'Danse', caracs: it => {
@@ -20,8 +21,6 @@ const ARTS = [
return caracs return caracs
} }
}, },
{ type: ITEM_TYPES.musique, action: "joue le morceau:", competence: it => 'Musique', caracs: it => [CARACS.OUIE] },
{ type: ITEM_TYPES.recettecuisine, action: "cuisine le plat:", competence: it => 'Cuisine', caracs: it => [CARACS.ODORATGOUT] },
] ]
export class RollPartOeuvre extends RollPartSelect { export class RollPartOeuvre extends RollPartSelect {

View File

@@ -16,7 +16,7 @@ export class RollPartSelect extends RollPart {
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current) { if (current) {
return [{ label: current.label, diff: current.value }] return [{ label: current.label, value: current.value }]
} }
return [] return []
} }
@@ -27,7 +27,7 @@ export class RollPartSelect extends RollPart {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
const newChoice = (choices.length == 0) const newChoice = (choices.length == 0)
? { key: '', value: defValue } ? { key: '', value: defValue }
: this.$getSelectedChoice(choices, key ?? current?.key ?? refs?.key ?? '') : this.$getSelectedChoice(choices, key ?? current?.key ?? refs?.key ?? choices[0].key)
this.setCurrent(rollData, newChoice) this.setCurrent(rollData, newChoice)
return newChoice return newChoice
} }

View File

@@ -76,8 +76,8 @@ export class RollPartSign extends RollPart {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.surprise == 'demi') { if (current.surprise == 'demi') {
return [ return [
{ label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur), diff: undefined }, { label: 'Significative requise ' + Misc.getFractionOneN(current.diviseur) },
...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it, diff: undefined } }) ...current.reasons.map(it => { return { label: '<i class="fa-solid fa-triangle-exclamation"></i> ' + it } })
] ]
} }
return [] return []

View File

@@ -11,19 +11,39 @@ import { CARACS } from "../rdd-carac.js"
export const PART_SORT = "sort" export const PART_SORT = "sort"
export class RollPartSort extends RollPartSelect { export class RollPartSort extends RollPartSelect {
onReady() { onReady() {
// TODO: utiliser un hook pour écouter les déplacements dans les TMRs? // TODO: utiliser un hook pour écouter les déplacements dans les TMRs?
} }
get code() { return PART_SORT } get code() { return PART_SORT }
get section() { return ROLLDIALOG_SECTION.CHOIX } get section() { return ROLLDIALOG_SECTION.CHOIX }
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() } isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) } 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) { loadRefs(rollData) {
const refs = this.getRefs(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.getDraconicList() const draconics = rollData.active.actor.getDraconics()
const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort] const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort]
.map(s => RollPartSort.$extractSort(s, coord, draconics)) .map(s => RollPartSort.$extractSort(s, coord, draconics))
@@ -31,7 +51,7 @@ export class RollPartSort extends RollPartSelect {
{ {
coord: coord, coord: coord,
tmr: TMRUtility.getTMR(coord), tmr: TMRUtility.getTMR(coord),
reve: rollData.active.actor.system.reve.reve.value, reve: this.getReveActuel(rollData),
draconics: draconics, draconics: draconics,
all: sorts, all: sorts,
sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord)) sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord))
@@ -39,10 +59,18 @@ export class RollPartSort extends RollPartSelect {
{ inplace: true } { inplace: true }
) )
if (refs.sorts.length > 0) { 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 } choices(refs) { return refs.sorts }
static $extractSort(sort, coord, draconics) { static $extractSort(sort, coord, draconics) {
@@ -54,37 +82,35 @@ export class RollPartSort extends RollPartSelect {
value: isDiffVariable ? -7 : parseInt(sort.system.difficulte), value: isDiffVariable ? -7 : parseInt(sort.system.difficulte),
ptreve: isReveVariable ? 1 : sort.system.ptreve, ptreve: isReveVariable ? 1 : sort.system.ptreve,
caseTMR: RdDItemSort.getCaseTMR(sort), caseTMR: RdDItemSort.getCaseTMR(sort),
bonusCase: RdDItemSort.getCaseBonus(sort, coord),
isDiffVariable: isDiffVariable, isDiffVariable: isDiffVariable,
isReveVariable: isReveVariable, isReveVariable: isReveVariable,
isReserve: false, isReserve: false,
sort: sort, sort: sort,
draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name) draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name),
} }
} }
getAjustements(rollData) { getAjustements(rollData) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current) { if (current) {
const reserve = current.isReserve ? const sort = { label: current.label, value: current.value }
[{ label: `Mise en réserve en ${current.coord}` }] : [] const reserve = current.isReserve ? [{ label: `Mise en réserve en ${this.getCoord(rollData)}` }] : []
const bonusCase = current.bonusCase ? const bonusCase = current.bonusCase ? [{ label: `Bonus case +${current.bonusCase}%` }] : []
[{ label: `Bonus case +${current.bonusCase}%` }] : [] const reve = { label: `Rêve ${current.ptreve}` }
return [ return [sort, ...bonusCase, reve, ...reserve]
{ label: current.label, diff: current.value },
{ label: `r${current.ptreve}` },
...bonusCase,
...reserve
]
} }
return [] return []
} }
$selectSort(rollData, key) { $selectSort(rollData, values) {
const previous = this.getCurrent(rollData) const current = this.selectByKey(rollData, values.key)
const current = this.selectByKey(rollData, key, -7) if (values.ptreve) {
if (current.key != previous.key) { } current.ptreve = values.ptreve
current.bonusCase = RdDItemSort.getCaseBonus(current.sort, }
rollData.active.actor.system.reve.tmrpos.coord) if (values.isReserve != undefined) {
current.isReserve = values.isReserve
}
} }
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
@@ -97,7 +123,7 @@ export class RollPartSort extends RollPartSelect {
selectSort.addEventListener("change", e => { selectSort.addEventListener("change", e => {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
const index = selectOptions.selectedIndex const index = selectOptions.selectedIndex
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value) this.$selectSort(rollDialog.rollData, { key: selectOptions[index]?.value })
rollDialog.render() rollDialog.render()
}) })

View File

@@ -1,5 +1,4 @@
import { ITEM_TYPES } from "../constants.js" import { ITEM_TYPES } from "../constants.js"
import { Grammar } from "../grammar.js"
import { ROLL_TYPE_TACHE } from "./roll-constants.mjs" import { ROLL_TYPE_TACHE } from "./roll-constants.mjs"
import { PART_CARAC } from "./roll-part-carac.mjs" import { PART_CARAC } from "./roll-part-carac.mjs"
import { PART_COMP } from "./roll-part-comp.mjs" import { PART_COMP } from "./roll-part-comp.mjs"
@@ -18,13 +17,19 @@ export class RollPartTache extends RollPartSelect {
loadRefs(rollData) { loadRefs(rollData) {
const refs = this.getRefs(rollData) const refs = this.getRefs(rollData)
refs.taches = rollData.active.actor.itemTypes[ITEM_TYPES.tache] 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) .filter(tache => tache.system.points_de_tache_courant < tache.system.points_de_tache)
.map(tache => RollPartTache.$extractTache(tache, rollData.active.actor)) .map(tache => RollPartTache.$extractTache(tache, rollData.active.actor))
refs.taches = refs.all
if (refs.taches.length > 0) { if (refs.taches.length > 0) {
this.$selectTache(rollData) this.$selectTache(rollData)
} }
} }
choices(refs) { return refs.taches } choices(refs) { return refs.taches }
static $extractTache(tache, actor) { static $extractTache(tache, actor) {
@@ -43,6 +48,8 @@ export class RollPartTache extends RollPartSelect {
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const selectTache = rollDialog.element.querySelector(`roll-section[name="${this.code}"] select[name="select-tache"]`) 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 => { selectTache.addEventListener("change", e => {
const selectOptions = e.currentTarget.options const selectOptions = e.currentTarget.options
@@ -50,16 +57,45 @@ export class RollPartTache extends RollPartSelect {
this.$selectTache(rollDialog.rollData, selectOptions[index]?.value) this.$selectTache(rollDialog.rollData, selectOptions[index]?.value)
rollDialog.render() 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) { impactOtherPart(part, rollData) {
if (this.visible(rollData)) { if (this.visible(rollData)) {
const current = this.getCurrent(rollData) const current = this.getCurrent(rollData)
if (current.tache) {
switch (part.code) { switch (part.code) {
case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac]) case PART_CARAC: return part.filterCaracs(rollData, [current?.tache.system.carac])
case PART_COMP: return part.filterComps(rollData, [current.comp?.name]) case PART_COMP: return part.filterComps(rollData, [current.comp?.name])
} }
} }
}
return undefined return undefined
} }

View File

@@ -15,10 +15,6 @@ export class RollPartTricher extends RollPart {
current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100) current.resultat = Misc.inRange(current.resultat == undefined ? -1 : current.resultat, -1, 100)
} }
getAjustements(rollData) {
return []
}
async _onRender(rollDialog, context, options) { async _onRender(rollDialog, context, options) {
const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`) const input = rollDialog.element.querySelector(`roll-section[name="${this.code}"] input[name="${this.code}"]`)

View File

@@ -6,6 +6,8 @@ export const ROLLDIALOG_SECTION = {
CONDITIONS: 'conditions', CONDITIONS: 'conditions',
AJUSTEMENTS: 'ajustements', AJUSTEMENTS: 'ajustements',
} }
export class RollPart { export class RollPart {
static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` } static settingKey(rollPart, key) { return `roll-part-${rollPart.code}.${key}` }
@@ -43,6 +45,7 @@ export class RollPart {
} }
/** les informations minimales représentant la sélection dans le rollData permettant de restaurer la fenêtre */ /** les informations minimales représentant la sélection dans le rollData permettant de restaurer la fenêtre */
getSelected(rollData) { return this.getSaved(rollData) }
getSaved(rollData) { getSaved(rollData) {
return rollData.selected[this.code] ?? {} return rollData.selected[this.code] ?? {}
} }
@@ -103,10 +106,9 @@ export class RollPart {
return { code: this.code, name: this.name, template: this.template, section: this.section } return { code: this.code, name: this.name, template: this.template, section: this.section }
} }
getAjustements(rollData) { getAjustements(rollData) { return [] }
return []
}
async _onRender(rollDialog, context, options) { } async _onRender(rollDialog, context, options) { }
getHooks() { return [] }
} }

View File

@@ -10,4 +10,5 @@ export class RollTypeAttaque extends RollType {
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.ATTAQUE) this.setDiffType(rollData, DIFF.ATTAQUE)
} }
} }

View File

@@ -1,4 +1,4 @@
import { ROLL_TYPE_COMP } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_COMP } from "./roll-constants.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
export class RollTypeComp extends RollType { export class RollTypeComp extends RollType {
@@ -7,4 +7,9 @@ export class RollTypeComp extends RollType {
title(rollData) { return `fait un jet ${rollData.type.opposed ? ' contre ' : ''}` } title(rollData) { return `fait un jet ${rollData.type.opposed ? ' contre ' : ''}` }
onSelect(rollData) {
this.setDiffType(rollData, DIFF.LIBRE)
}
} }

View File

@@ -0,0 +1,84 @@
import { ITEM_TYPES } from "../constants.js"
import { RollBasicParts } from "./roll-basic-parts.mjs"
import { DIFF, ROLL_TYPE_CUISINE } from "./roll-constants.mjs"
import { PART_CUISINE } from "./roll-part-cuisine.mjs"
import { RollType } from "./roll-type.mjs"
export class RollTypeCuisine extends RollType {
get code() { return ROLL_TYPE_CUISINE }
get name() { return `Interpréter une oeuvre` }
visible(rollData) { return rollData.active.actor.isPersonnage() }
title(rollData) {
const current = rollData.current[PART_CUISINE]
return current.recette ? `prépare une recette: ${current.label}` : `prépare: ${current.label}`
}
onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN)
}
getResult(rollData, impacts) {
const current = rollData.current[PART_CUISINE]
const diff = -current.value
const cuisine = rollData.refs[PART_CUISINE].cuisine
const qualite = rollData.rolled.ptQualite + (rollData.rolled.isSuccess ? diff : Math.min(diff, cuisine.system.niveau))
const result = {
qualite: qualite,
exotisme: Math.min(Math.min(qualite, current.exotisme ?? 0), 0),
messages: []
}
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.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.addDeleted('Item', current.ingredient)
result.messages.push(`Il n'y a plus de ${ingredient.name}`)
}
else {
impacts.addDelta('Item', current.ingredient, 'system.quantite', -current.proportions)
result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`)
}
}
return result
}
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.findCreatedId('Item', roll.result.plat.id)
}
}
$prepareNourriture(cuisinier, current, result) {
return {
id: foundry.utils.randomID(16),
name: current.label,
img: current.img,
type: ITEM_TYPES.nourritureboisson,
system: {
sust: current.sust,
cuisinier: cuisinier,
exotisme: result.exotisme,
encombrement: 0.1,
quantite: current.proportions,
qualite: result.qualite,
cout: result.qualite > 0 ? (result.qualite * 0.01) : 0.01,
}
}
}
async onFaireGouter(savedRoll) {
const actor = RollBasicParts.getTokenActor(savedRoll).actor
const platId = savedRoll.result.plat.id
const plat = actor.items.get(platId)
await plat?.proposerVente()
}
}

View File

@@ -1,6 +1,7 @@
import { PART_JEU } from "./roll-part-jeu.mjs" import { PART_JEU, RollPartJeu } from "./roll-part-jeu.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
import { ROLL_TYPE_JEU } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_JEU } from "./roll-constants.mjs"
export class RollTypeJeu extends RollType { export class RollTypeJeu extends RollType {
get code() { return ROLL_TYPE_JEU } get code() { return ROLL_TYPE_JEU }
@@ -14,4 +15,9 @@ export class RollTypeJeu extends RollType {
return `joue: ${rollData.current[PART_JEU].label}` return `joue: ${rollData.current[PART_JEU].label}`
} }
onSelect(rollData) {
this.setDiffType(rollData, DIFF.LIBRE)
RollPartJeu.forceCompJeu(rollData)
}
} }

View File

@@ -1,3 +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 { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs"
import { PART_MEDITATION } from "./roll-part-meditation.mjs" import { PART_MEDITATION } from "./roll-part-meditation.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
@@ -16,4 +18,26 @@ export class RollTypeMeditation extends RollType {
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) this.setDiffType(rollData, DIFF.AUCUN)
} }
callbacks(rollOptions) { return [RollTypeMeditation.$onRollMeditation] }
static async $onRollMeditation(rollData) {
const actor = rollData.active.actor
const meditation = rollData.current.meditation.meditation
const rolled = rollData.rolled
if (meditation && rolled) {
if (rolled.isSuccess) {
await actor.createEmbeddedDocuments('Item', [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)])
}
if (rolled.isEPart) {
await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }])
}
await actor.santeIncDec("fatigue", 2)
}
}
async onMonteeTMR(savedRoll, mode){
const actor = RollBasicParts.getTokenActor(savedRoll).actor
return actor?.displayTMR(mode)
}
} }

View File

@@ -16,11 +16,12 @@ export class RollTypeOeuvre extends RollType {
this.setDiffType(rollData, DIFF.AUCUN) this.setDiffType(rollData, DIFF.AUCUN)
} }
getResult(rollData){ getResult(rollData, impacts) {
const current = rollData.current[PART_OEUVRE] const current = rollData.current[PART_OEUVRE]
const qualite = rollData.rolled.isSuccess ? current.qualite : Math.min(current.qualite, current.comp.system.niveau) const qualite = rollData.rolled.isSuccess ? current.qualite : Math.min(current.qualite, current.comp.system.niveau)
return { return {
qualite: qualite + rollData.rolled.ptQualite qualite: qualite + rollData.rolled.ptQualite,
messages: []
} }
} }

View File

@@ -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 { 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" import { RollType } from "./roll-type.mjs"
export class RollTypeSort extends RollType { export class RollTypeSort extends RollType {
@@ -11,4 +16,69 @@ export class RollTypeSort extends RollType {
onSelect(rollData) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) 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
}
}
} }

View File

@@ -1,3 +1,5 @@
import { ITEM_TYPES } from "../constants.js"
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"
import { DIFF, ROLL_TYPE_TACHE } from "./roll-constants.mjs" import { DIFF, ROLL_TYPE_TACHE } from "./roll-constants.mjs"
import { PART_TACHE } from "./roll-part-tache.mjs" import { PART_TACHE } from "./roll-part-tache.mjs"
import { RollType } from "./roll-type.mjs" import { RollType } from "./roll-type.mjs"
@@ -10,10 +12,32 @@ export class RollTypeTache extends RollType {
title(rollData) { title(rollData) {
const current = rollData.current[PART_TACHE] const current = rollData.current[PART_TACHE]
const tache = current?.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) { onSelect(rollData) {
this.setDiffType(rollData, DIFF.AUCUN) this.setDiffType(rollData, DIFF.AUCUN)
} }
callbacks(rollOptions) { return [ async r => await RollTypeTache.$onRollTache(r, rollOptions)] }
static async $onRollTache(rollData, rollOptions) {
const actor = rollData.active.actor
const tache = rollData.current[PART_TACHE].tache
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
await actor.santeIncDec("fatigue", tache.system.fatigue)
}
rollData.current[PART_TACHE].tache = await tache.update({
'system.points_de_tache_courant': tache.system.points_de_tache_courant + rollData.rolled.ptTache,
'system.nb_jet_succes': tache.system.nb_jet_succes + (rollData.rolled.isSuccess ? 1 : 0),
'system.nb_jet_echec': tache.system.nb_jet_echec + (rollData.rolled.isSuccess ? 0 : 1),
'system.difficulte': tache.system.difficulte - (rollData.rolled.isETotal ? 1 : 0),
}, {render:true})
if (rollOptions?.onRollAutomate) {
await rollOptions.onRollAutomate(rollData)
}
}
} }

View File

@@ -18,7 +18,6 @@ export class RollType {
isAllowed(rollData) { return rollData.type.allowed == undefined || rollData.type.allowed.includes(this.code) } isAllowed(rollData) { return rollData.type.allowed == undefined || rollData.type.allowed.includes(this.code) }
visible(rollData) { return true } visible(rollData) { return true }
title(rollData) { return this.code } title(rollData) { return this.code }
isSelected(rollData) { return rollData.type.current == this.code } isSelected(rollData) { return rollData.type.current == this.code }
@@ -37,7 +36,6 @@ export class RollType {
this.setDiffType(rollData, type) this.setDiffType(rollData, type)
} }
typeFromOpponents(rollData) { typeFromOpponents(rollData) {
if (rollData.type.opposed) { if (rollData.type.opposed) {
if (rollData.type.resistance) { if (rollData.type.resistance) {
@@ -53,7 +51,16 @@ export class RollType {
this.setRollDataType(rollData) this.setRollDataType(rollData)
} }
getResult(rollData){ callbacks(rollOptions) { return [] }
return undefined
} /**
* Préparation des résultats d'un jet pour ce type de jet
*
* @param {*} rollData les données du jet, incluans la partie rolled
* @param {*} impacts une structure composée de deux ActorImpacts {active, opponent}
* pour stocker les effets sur ces deux participants au jey
* @returns undefined ou une structure contenant les informations requise pour afficher
*/
getResult(rollData, impacts) { return { messages: [] } }
onApplyImpacts(roll, impacts) { }
} }

Some files were not shown because too many files have changed in this diff Show More