Compare commits

...

139 Commits

Author SHA1 Message Date
b92003ac1f Merge pull request '12.0.19 - La témérité d'Astrobazzarh' (#720) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #720
2024-11-08 07:10:13 +01:00
a1e4bfb529 Fix: erreur droits sur scène
L'ajustement automatique de l'obscurité se déclenchait
pour les joueurs et échouaitn faute de droits sur la scènequand un joueur
2024-11-08 01:52:19 +01:00
b4f0be5d64 Version 12.0.19 2024-11-07 00:26:59 +01:00
5ff31d462f Fix initiative de masse
L'initiative de masse utilise la première compétence de combat trouvée
2024-11-07 00:16:12 +01:00
be1d109def Corrections actions combat créatures
Les actions de combat des créatures et leurs défenses sont
correctement filtrées
2024-11-06 23:24:53 +01:00
d91bee0f42 Merge pull request 'Version 12.0.18 - A la barbe d'Astrobazzarh' (#719) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #719
2024-11-05 20:27:55 +01:00
ed222c7b6d Version 12.0.18 2024-11-04 00:20:12 +01:00
70198a5727 Correction des armes de défense 2024-11-04 00:19:21 +01:00
bfe70c6634 Fix difficulté défense distance 2024-11-03 23:37:21 +01:00
09365eb744 Fix: reset des utilisations d'items 2024-11-03 23:31:56 +01:00
894d4f3941 Fix: jet d'endurance feuille simplifiée 2024-11-03 22:01:04 +01:00
6e234411ca Fix: Commande /astro 2024-11-03 22:01:04 +01:00
85acb5a255 Fix: message de tchat des commerces 2024-11-03 22:01:04 +01:00
6106e2a19e Fix changelog feuille PNJ 2024-11-03 22:01:04 +01:00
f896f1da6e Fix rename attackerToken
correction oubli sans gravité
2024-11-03 22:01:03 +01:00
9bb45c2349 PNJ: boutons des compteurs
Pas de bouton + au max de vie/endurance.
Pas de bouton - au min, de fatigue
2024-11-03 22:01:03 +01:00
5cab219e0e PNJ: affichage niveau d'esquive 2024-11-03 22:01:03 +01:00
2de9ea49c8 PNJ: ajout mains nues et empoignade 2024-11-03 22:01:03 +01:00
1760d26014 PNJ: support initiative 2024-11-03 22:01:03 +01:00
92185d4a5b Portrait dans les feuilles simplifiées 2024-11-03 22:01:03 +01:00
210b129934 Fix: niveau de compétence non défini
- quand le niveau de compétence n'était pas défini, la feuille de
personnage simplifiée et l'export scriptarium ne marchaient pas
- on pouvait saisitr une compétence avec un niveau non défini
2024-11-03 22:01:02 +01:00
b892068b38 Utilisation du nom du Nom du token
suite (pour les encaissements)
2024-11-03 22:01:02 +01:00
3906cb0a7b Localisation des blessures en regle optionnelle 2024-11-03 22:01:02 +01:00
5c58932a0d Amélioration message encaissement 2024-11-03 22:01:02 +01:00
3b06bd382b Afficher le nom du token au lieu du nom d'Acteur
Dans les messages d'automatisation de combat, le nom des
tokens est utilisé au lieu d'utiliser le nom de l'acteur.

Ceci permet de ne pas dévoiler un nom générique (Villageois)
si le token a un nom personnalisé.
2024-11-03 22:01:02 +01:00
b4a725ff12 Fix: Message uniquement MJ
L'utilisation de firstConnectedGM renvoie le GM, pas true si
un GM est connecté.
2024-11-03 22:01:01 +01:00
05df6a68cc Amelioration parser 2024-10-31 23:38:02 +01:00
025c3483a9 Amelioration parser 2024-10-31 23:36:16 +01:00
97138b25c7 Parser de personnage/creature, WIP 2024-10-30 22:45:47 +01:00
c0066f79c1 Move to v12.0.17 2024-10-26 10:56:52 +02:00
4db8bf95f9 Move to v12.0.16 2024-10-25 19:02:23 +02:00
a7e1ca0b07 Merge pull request 'Version 12.0.15' (#715) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #715
2024-10-17 07:53:59 +02:00
e2c4d93413 Version 12.0.15 2024-10-17 02:08:03 +02:00
3888efc6aa Correction dés dice-so-nice 2024-10-17 02:07:24 +02:00
5004774a15 Rendu des tables de compendiums 2024-10-16 23:32:19 +02:00
226afc1680 Fix: tooltip augmentation compétences 2024-10-16 23:32:19 +02:00
582df7e290 Simplify ChatMessage whispers
Les messages dans les TMRs sont envoyés au GM

Simplification des messages de tchat liés à un actor: on peut
utiliser les Owners (car les GMs sont owner).

Au lieu de passer le name de l'Actor (qui peut être incorrect si deux
actors ont le même, mais pas les mêmes propriétaires), on passe
directement l'actor pour déterminer mles destinataires de messages
2024-10-16 23:32:18 +02:00
501f1f2e4f Fix: Messages de maladies non publics
Les messages de maladies sont uniquement pour les "owners"
(ce qui inclut les MJs)
2024-10-16 23:32:18 +02:00
90d46c6a78 Init settings before sheets
Eviter que le chargement d'acteurs ait lieu avant le chargement
des settings
2024-10-14 03:47:13 +02:00
174ef4256a Merge pull request 'v11' (#714) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #714
2024-10-11 17:42:24 +02:00
be132a9ff1 Gestion esquive feuille simplifiée 2024-10-11 01:30:43 +02:00
b2037a852c Pas de lien sur la ligne titre 2024-10-11 01:25:08 +02:00
2137a6c403 Version 12.0.14 2024-10-11 01:20:01 +02:00
99f5578c4f Armes sur la fiche de PNJ 2024-10-11 01:19:28 +02:00
a6ae7babbe Feuille PNJ suite 2024-10-11 01:19:27 +02:00
814266e649 Fix carac roll 2024-10-10 23:17:55 +02:00
080d05d2cd Merge pull request 'Version 12.0.2' (#713) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #713
2024-10-06 17:03:41 +02:00
f8f889e9f9 Jets de vie/endurance/rêve actuel 2024-10-05 15:13:29 +02:00
ad80802af6 Remove log 2024-10-05 14:40:14 +02:00
0f7b9baf51 Amélioration liste de compétences 2024-10-05 14:39:56 +02:00
b866c95ebd Correction de la protection 2024-10-05 12:57:02 +02:00
689e287ac7 Bouton d'export si mode avancé 2024-10-05 12:50:29 +02:00
40b0d7e6dc Jets de carac/compétences sur feuille encart 2024-10-05 12:41:28 +02:00
d439d73636 Version 12.0.12 2024-10-05 00:42:32 +02:00
e91eea532d Ajout feuille encart
Feuille de PNJ au format des encarts Scriptarium.
Aucune possibilité de jets de dés pour l'instant.
2024-10-05 00:42:27 +02:00
f116003d6f Fix: vente depuis les compendiums/Objets
On peut de nouveau vendre des items sans propriétaire,
depuis les compendiums ou depuis l'onglet des Objets
2024-10-05 00:39:50 +02:00
c3a44665c5 Load handlebars dans app-personnage-aleatoire 2024-10-05 00:39:50 +02:00
40b57517d8 Merge pull request '12.0.11' (#712) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #712
2024-10-02 07:37:42 +02:00
e04586ba44 Ajout de génération aléatoire de description
Ajout d'un bouton pour générer aléatoirement les éléments de description:

- nom (pour le MJ seul)
- sexe
- age
- main directrice
- cheveux, yeux
- heure de naissance
- taille et poids (selon la caractéristique Taille)
2024-10-02 00:46:11 +02:00
611acd4d44 Version 12.0.11 2024-10-01 02:07:42 +02:00
9b37533bdf Correction nom classe (inutile) 2024-10-01 02:00:42 +02:00
50d923061b Ajout d'un champ pour les métiers 2024-10-01 01:59:51 +02:00
e89a8ba232 Ajout background system pour Foundry 2024-10-01 01:58:06 +02:00
b8f236fa97 Fix esquive avec armure
- ajout de champ sans armure/avec armure
- calcul correct avec armure
2024-09-28 17:45:31 +02:00
74b184aa32 Use windows-1252 encoding 2024-09-28 17:44:28 +02:00
9c17f85fa8 Fix: détermination niveau de base
simplification: déterminer les catégories en fonction du type d'Item
2024-09-27 22:40:08 +02:00
599fdc752d Fix naming + charset 2024-09-27 13:44:56 +02:00
fa890491e5 Fix wrong object import 2024-09-27 13:41:30 +02:00
80435b6bca Fix wrong object import 2024-09-27 13:21:42 +02:00
1a476bd5bc Fix wrong object import 2024-09-27 13:20:29 +02:00
8d6c4565a9 Merge pull request 'v12.0.9 - Le scriptorium d'Astrobazzarh' (#711) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #711
2024-09-27 10:16:54 +02:00
6819f1c2f5 Correction du mapping
- gestion des armes une/deux mains/lancées
- dommages des armes une/deux mains
- correction de la voie de draconic
- correction des bonus de cases
- correction des retours à la ligne
2024-09-27 02:36:54 +02:00
43607afc12 Correction du parser des bonus de case 2024-09-27 02:33:01 +02:00
538cf5bdbf Extraction des calculs de dommages
Préparation pour le Mapping des armes
2024-09-27 02:32:13 +02:00
75507f3eca Fix deprecation 2024-09-27 02:30:48 +02:00
a622814295 Amélioration message tchat de tirage 2024-09-26 00:55:37 +02:00
2aa8fcb980 Amélioration export voies draconiques 2024-09-26 00:55:08 +02:00
a65326d658 Version 12.0.9
Export format csv
2024-09-25 23:43:04 +02:00
b6a203b82a Export vers un fichier csv 2024-09-25 23:43:04 +02:00
7e8f642d87 Export csv pour Scriptarium
Activable dans les options avancées du système
Un menu contextuel permet d'écrire dans les logs
2024-09-25 23:43:04 +02:00
91be2761f5 Passage html -> hbs 2024-09-25 23:43:03 +02:00
2ac39e3428 Ajout de la taille (manquante) 2024-09-25 23:43:03 +02:00
a162001ba4 Cleanup 2024-09-25 23:43:03 +02:00
52e1f9dfbf Rename TYPES en ITEM_TYPES
Pour ajouter les ACTOR_TYPES
2024-09-25 23:43:03 +02:00
c586a90690 Merge pull request 'Version 12.0.8 - La quincaillerie d'Astrobazzarh' (#710) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #710
2024-09-06 15:14:23 +02:00
16e40b0ed8 12.0.8 - La quincaillerie d'Astrobazzarh
- le propriétaire est indiqué dans les feuilles d'équipements/
   compétences/...
- Ecaille d'efficacité
  - l'écaille d'efficacité est prise en compte même si on n'utilise
     pas le ciblage en combat
  - l'écaille d'efficacité est prise en compte pour l'initiative
- Corrections
  - l'état général est pris en compte pour les initiatives
  - le tooltip de l'initiative affiche correctement l'initiative
2024-09-06 00:49:39 +02:00
427a950954 L'initiative utilise l'écaille d'efficacité 2024-09-06 00:47:32 +02:00
a7b20bdd35 Ecaille d'efficacité sans cible
L'écaille d'efficacité est prise en compte si on n'utilise pas
l'automatisation de combat avec une cible
2024-09-06 00:45:49 +02:00
3b18e0b919 Ajout du propriétaire sur les Items 2024-09-05 23:54:02 +02:00
ff8a5d7ba3 Fix tooltip initiative 2024-09-05 23:54:02 +02:00
3aa8c0f0af Fix weapon in the HUD 2024-09-01 20:39:25 +02:00
8d9f09c18c Fix warnings 2024-09-01 20:22:52 +02:00
9d654246c2 Merge pull request '12.0.7 - La propriété d'Astrobazzarh' (#709) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #709
2024-09-01 20:21:04 +02:00
111fac2b2d Amélioration dialogue voyage
- le changement de terrain change l'affichage de compétences
- le total de fatigue est affiché (ajustement + base)
2024-09-01 20:13:09 +02:00
3e99265125 Version 12.0.7 - La propriété d'Astrobazzarh
- correction des opérations faites à la création d'un Item:
  - la durée des queues/rencontres/souffles
  - les effets draconiques d'un souffle/queue
  - mise à jour des points de tâche des blessures lors des soins
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
  d'une entité incarnée permet d'accorder le personnage
- Les messages pour résister aux possessions/conjuration sont envoyées
  au défenseur
- Les messages pour résister aux empoignades sont envoyées au défenseur
2024-08-31 00:59:26 +02:00
28878b74fc Fix: demandes au défenseur
Les demandes de résistance pour les possessions sont envoyées au
défenseur

Les demlandes de défense contre une empoignade dont envoyées au
 défenseur
2024-08-31 00:58:58 +02:00
ba8276ef37 Possibilité d'accorder un personnage
Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
d'une entité incarnée permet d'accorder le personnage
2024-08-31 00:21:24 +02:00
b9e8c24461 Pas d'expérience si le MJ n'est pas connecté
Pour éviter les jets de dés abusifs quand le MJ n'est pas là,
les réussites particulières ne rapportent plus d'expérience
lorsque le MJ n'est pas connecté
2024-08-30 23:56:20 +02:00
8754ea9f5f Fix hook sur creation
Correction des Hooks qui font des calculs à la création d'un item.

- document instanceof Document est false pour un Actor
- le tri des users ne marche pas sur foundry 12
- mise à jour des blessures lors des soins

Correction de la détermination du MJ connecté permettant de nouveau:
- jets de dés quand aucun MJ n'est connecté
- affichage de l'horloge
2024-08-30 23:54:06 +02:00
f56ddb4a1b Merge pull request 'Version 12.0.6 - Le bazar d'Astrobazzarh' (#708) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #708
2024-08-01 07:19:12 +02:00
e80dbc7332 Version 12.0.6 2024-08-01 01:19:54 +02:00
4c82d85e6a Fix: visibilité des tirages dans les compendium
Les macros /tirer affichaient le résultat pour tous les joueurs
2024-08-01 01:19:07 +02:00
538058ecc6 Fix: cas d'un objet est un conteneur fantôme
Lors d'une partie, la feuille d'un personnage a été bloquée.
Après debug, il semble que l'objet a eu le flag estContenu=true
sans être contenu.

En regardant le json, il semble que des Item "objet" se sont retrouvés
avec un champ "contenu", et que l'arbre des contenant a été cassé.

Du coup: l'ajout dans un conteneur est maintenant "sécurisé" pour
éviter l'accident. si on essaie d'ajouter dans un Item non conteneur,
on positionne estContenu à false, et on corrige si possible le "contenu"
de la cible, qui ne devrait pas être là.
2024-08-01 01:17:36 +02:00
70e42ea631 Merge pull request 'Restaurer la compatibilité v11' (#707) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #707
2024-07-15 17:17:29 +02:00
15525ef8cc Restaurer la compatibilité v11 2024-07-10 23:17:27 +02:00
5a4ef6da7e Merge pull request '12.0.5 - Les mauvais jours d'Astrobazzarh' (#706) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #706
2024-07-08 22:14:15 +02:00
ab698b2124 Version 12.0.5 - Les mauvais jours d'Astrobazzarh
- Fix: on peut de nouveau ouvrir l'édition de calendrier
- Fix: on ne peut plus ouvrir plusieurs fenêtres de lancer de sort
- Fix: Failed to execute 'getComputedStyle' on 'Window'
2024-07-04 21:30:19 +02:00
4cc6e86d79 Fix: Failed to execute 'getComputedStyle'
Dans certains cas (ouverture de fenêtre de lancer de sort),
le bringToTop était appelé alors que la fenêtre n'était pas prête
2024-07-04 21:23:29 +02:00
8f3d56a830 Une seule fenêtres de lancer de sort à la fois
On ne peut plus ouvrir de fenêtre de lancer de sort quand une
fenêtre est déjà ouverte
2024-07-04 21:23:29 +02:00
8561e3f8bc Securité: limiter les cleanupConteneurs
Dans certains cas mal identifiés, on pouvait avoir un problème de droits
sur l'acteur, quand plusieurs joueurs accédaient en même temps à
l'équipement porté par une mule, par exemple
2024-07-04 21:23:29 +02:00
f207cb7325 Fix: Fenêtre d'édition du calendrier
Ajout d'un helper Handlebars pour accéder à l'objet RDD_CONFIG
sans avoir besoin de l'ajouter dans les données pour rendu du template
2024-07-04 21:23:28 +02:00
b9e911a588 Merge pull request '## 12.0.4 - La plaie d'Astrobazzarh' (#705) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #705
2024-07-03 21:47:11 +02:00
92e9be8b02 Version 12.0.4 2024-07-03 02:35:23 +02:00
50a86e751d Fix: warnings deprecated v12 2024-07-02 23:37:50 +02:00
1725d4c17b Fix: impossible de faire l'encaissement
Echec lors des test de permission d'utilisateur
2024-07-02 23:36:52 +02:00
3e33053ed4 Merge pull request '12.0.3 - L'hémorragie d'Astrobazzarh' (#704) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #704
2024-07-01 22:21:26 +02:00
baa3729568 Version 12.0.3 2024-06-29 00:26:12 +02:00
99f29cb95b Fix confirmation de suppression
Lors de la suppression, la demande de confirmation était toujours
faite, même si on indiquait de ne plus demander
2024-06-29 00:12:31 +02:00
7d19860f5f Fix ouverture des Items avec rareté
La sélection des raretés ne fonctionnait plus, la liste des
raretés n'étant pas disponible configuration n'étant
pas disponible dans les données des Items.
2024-06-29 00:12:31 +02:00
40987149cc Fix Ouvertures impossibles
Le contexte des constructeurs est partagé entre Actor et Items,
il faut donc enlever l'indicateur qui sert au choix de la bonne
classe dérivée, sans quoi certains objets/acteurs peuvent être
créés en utilisant le type de base, ce qui empêche d'ouvrir
certains items d'acteurs après avoir redémarré le monde

Par exemple, après ajout d'une blessure et redémarrage, il était
impossible de réouvrir la feuille du personnage blessé.
2024-06-29 00:12:30 +02:00
49d7c4f71d Merge pull request '12.0.2 - Les pluies d'Astrobazzarh' (#703) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #703
2024-06-14 08:04:23 +02:00
23582984cf Version 12.0.2 - Les pluies d'Astrobazzarh 2024-06-14 00:25:10 +02:00
638459049d Fix: dé draconique et rencontre
Le dé draconique donnait toujours un total de 0
2024-06-14 00:03:06 +02:00
366ca981ca Fix message de log de journaux 2024-06-13 22:46:35 +02:00
c0e54c2369 Fix warning sur test de version 2024-06-13 22:06:23 +02:00
f95f5b2b81 Fix calendrier in v12 2024-06-13 22:00:09 +02:00
d30226cb33 Fix game.users for v12 2024-06-13 21:52:48 +02:00
5cf7dda76c Fix game.users for v12 2024-06-13 21:51:31 +02:00
9bc2593b8c Sync version to v12 2024-06-12 08:21:03 +02:00
efd02b40a9 Merge pull request 'Version 11.2.22 - Le futur d'Akarlikarlikar' (#702) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #702
2024-06-12 08:16:17 +02:00
feb3116c47 Version 11.2.22 2024-06-12 01:02:03 +02:00
91a870ad91 Merge pull request 'Fix User ... lacks permission to update' (#701) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #701
2024-06-11 07:52:59 +02:00
2bbf606f30 Fix User ... lacks permission to update
Correction de l'erreur qui était affichée chez les joueurs lors de
hooks utilisés pour effectuer des modifications sur des
documents:

- ChatMessage, ajout de flags pour l'heure
- Item au sein d'un Actor pour mettre à jour certains éléments
2024-06-11 02:49:18 +02:00
a385b98126 Various fixes for v12 2024-06-07 11:12:00 +02:00
8775df5285 Merge pull request 'Corrections v12' (#700) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #700
2024-06-01 09:11:18 +02:00
a103239288 Passe de vérification mergeObject
Quand mergeObject est utilisé pour retourner une valeur, faire très
attention à ne pas passer un Item/Actor, ou une de ses sous parties
en premier paramètre sans préciser l'option { inplace: false }

Sinon, le premier paramètre subit une mutation!
2024-06-01 01:53:14 +02:00
0b1c5d0a3d Fix again achatVente
- remplacement des données/JSON dans le html par des Flags sur
  le ChatMessage
- extraction de la gestion des infos de ventes pour rassembler la
  génération du ChatMessage
- on ne perd plus la quantité ou le vendeur
- attention au mergeObject: il modifie le premier parametre, ce
  qui modifiait parfois l'acteur (!!!) et toujours la quantité de
  l'objet du vendeur lors de la création de l'objet de l'acheteur!
2024-06-01 01:50:48 +02:00
e19577eab2 Fix for v12 2024-05-31 21:48:19 +02:00
c3b502ff6c Fix V12 Fenêtre de recherche 2024-05-31 21:42:09 +02:00
138 changed files with 12064 additions and 1610 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -1,3 +1,136 @@
# 12.0
## 12.0.19 - La témérité d'Astrobazzarh
- Fix
- les défenses des créatures sont correctement filtrées
- le lancer d'initiative pour tous les personnages/PNJs fonctionne correctement
- les lieux et commerces n'ont pas d'initiative
## 12.0.18 - A la barbe d'Astrobazzarh
- Améliorations sur la feuille de PNJ simplifiée
- Ajout du portrait
- Ajout du corps à corps
- Affichage du niveau d'esquive
- Un clic sur l'initiative permet de lancer l'initiative
- les boutons +/- pour la vie, l'endurance et la fatigue changent si on est à la valeur normale
- un clic sur l'endurance effectue un jet d'endurance
- Fix
- les achats des commerces sont de nouveau possibles
- la commande /astro fonctionne de nouveau
- le nombre d'utilisations d'items est réinitialisé à chaque round et fin de combat
- la difficulté de parade pour les armes à distances n'est plus indiquée
- les propositions d'armes de parade sont corrigées
- Ajout d'un indicateur pour les armes de parade nécessitant une significative
## 12.0.16 - Le secret d'Astrobazzarh
- Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués)
- Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs
- Ajout d'une option pour la localisation des blessures
## 12.0.15 - Le messager d'Astrobazzarh
- Correction des faces de dés personalisés dice-so-nice
- Les messages de maladies ne sont plus publics
- Les messages privés dans les TMR sont aussi envoyés au GM
- Les informations de compétences pouvant augmenter s'affichent comme tooltips
- Amélioration du rendu des tables de compendiums (commande /table)
## 12.0.14 - Les légions d'Astrobazzarh
- Feuille de PNJ:
- boutons standard (encaissement, ...)
- boutons pour ajuster les compteurs
- visualisation des blessures
- click sur blessure pour ajouter/enlever
- gestion des armes
## 12.0.13 - La Chance d'Astrobazzarh
- Fix: jets de caractéristiques
## 12.0.12 - L'étalage d'Astrobazzarh
- Fix: On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets
- Début de Feuille PNJ au format des encarts Scriptarium
- support des jets de caractéristiques
- support des jets de compétences
## 12.0.11 - Le scriptorium d'Astrobazzarh
- ajout d'un bouton pour générer les éléments de description d'un personnage
- ajout du logo en background dans la liste des systèmes Foundry
- ajout d'un champ pour le métier
- export scriptarium
- encodage de l'export en windows-1252
- export de l'esquive avec armure et sans armure
## 12.0.10 - Le scriptorium d'Astrobazzarh
- corrections de l'export scriptarium
## 12.0.9 - Le scriptorium d'Astrobazzarh
- ajout d'une fonction avancée pour exporter les personnages dans un format csv
## 12.0.8 - La quincaillerie d'Astrobazzarh
- le propriétaire est indiqué dans les feuilles d'équipements/compétences/...
- Ecaille d'efficacité
- l'écaille d'efficacité est prise en compte même si on n'utilise pas le ciblage en combat
- l'écaille d'efficacité est prise en compte pour l'initiative
- Corrections
- l'état général est pris en compte pour les initiatives
- le tooltip de l'initiative affiche correctement l'initiative
## 12.0.7 - La propriété d'Astrobazzarh
- correction des opérations faites à la création d'un Item:
- la durée des queues/rencontres/souffles
- les effets draconiques d'un souffle/queue
- mise à jour des points de tâche des blessures lors des soins
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
d'une entité incarnée permet d'accorder le personnage
- Les messages pour résister aux possessions/conjuration sont envoyées
au défenseur
- Les messages pour résister aux empoignades sont envoyées au défenseur
- la commande /voyage affiche maintenant le total de fatigue pour chaque voyageur
- la commande /voyage affiche maintenant les compétences liées au terrain
## 12.0.6 - Le bazar d'Astrobazzarh
- Corrections de l'inventaire en bazar:
- un problème pouvait survenir en déplaçant les objets
l'inventaire, qui fait qu'un conteneur se retrouve récursivement dans son
propre contenu, ce qui empêche d'ouvrir la feuille d'acteur.
- un objet non-conteneur pouvait dans certains cas avoir un pseudo contenu
- un objet pouvait être considéré comme contenu, sans être présent dans un
conteneur (et donc non affiché)
- vider les conteneurs supprime correctement toutes les informations liées
aux conteneurs/contenus
- Les messages pour les tirages dans le compendium utilisent le "roll mode"
courant pour leur visibilité
- Fix: restaurer la compatibilité Foundry 11
## 12.0.5 - Les mauvais jours d'Astrobazzarh
- Fix: on peut de nouveau ouvrir l'édition de calendrier
- Fix: on ne peut plus ouvrir plusieurs fenêtres de lancer de sort
- Fix: Failed to execute 'getComputedStyle' on 'Window'
## 12.0.4 - La plaie d'Astrobazzarh
- **Support V12**
- Fix: les boutons d'encaissement dans le tchat fonctionnent de nouveau
- Fix warnings sur "Die" et AudioHelper
## 12.0.3 - L'hémorragie d'Astrobazzarh
- **Support V12**
- On peut de nouveau ouvrir un acteur blessé après redémarrage du monde
- On peut de nouveau ouvrir les Items avec une rareté par environnement
- Le choix de ne plus afficher les demandes de suppression est bien pris en compte
## 12.0.2 - Les pluies d'Astrobazzarh
- **Support V12**
- correction des actions techniques déleguées au MJ qui bloquaient les fenêtre de lancer de dés des joueurs (et plein d'autres)
- la fenêtre de calendrier s'ouvre correctement
- les dés draconiques peuvent de nouveau faire plus que 0
- adaptation de la fenêtre de recherche
- correction des comparaisons de version pour les migrations automatiques
- correction des roll.eveluate: l'option async est maintenant standard
- correction des templates liés aux selections
- correction de l'ajustement de luminosité de la scène selon l'heure
- correction des images d'effets sur les tokens
- correction de la vente par le tchat: seul le premier acheteur pouvait acheter
- correction d'erreurs intempestives 'User ... lacks permission to update ...'
# 11.2 # 11.2
## 11.2.21 - Le questionnement d'Akarlikarlikar ## 11.2.21 - Le questionnement d'Akarlikarlikar
- Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente - Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente

4
icons/heures/.directory Normal file
View File

@ -0,0 +1,4 @@
[Dolphin]
Timestamp=2024,5,29,20,57,41.954
Version=4
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails

View File

@ -0,0 +1,65 @@
import { SYSTEM_RDD } from "../constants.js";
import { RdDUtility } from "../rdd-utility.js";
const DETAIL_VENTE = 'detailVente';
const NB_LOTS = 'nbLotss';
export class ChatVente {
static getDetailVente(chatMessageId) {
const chatMessage = game.messages.get(chatMessageId)
if (!chatMessage) {
return undefined;
}
const nbLots = chatMessage.getFlag(SYSTEM_RDD, NB_LOTS)
const detail = foundry.utils.duplicate(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE))
if (!detail.item) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return undefined;
}
const vendeur = detail.vendeurId ? game.actors.get(detail.vendeurId) : undefined;
return foundry.utils.mergeObject(detail,
{
alias: vendeur?.name ?? game.user.name,
vendeur,
nbLots: nbLots,
chatMessageIdVente: chatMessageId
})
}
static getDetailAchatVente(chatMessageId) {
const acheteur = RdDUtility.getSelectedActor()
const detail = ChatVente.getDetailVente(chatMessageId)
if (!acheteur && !detail.vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return undefined;
}
return foundry.utils.mergeObject(detail, { acheteur })
}
static async diminuerQuantiteAchatVente(chatMessageId, quantite) {
const chatMessage = game.messages.get(chatMessageId)
const vente = ChatVente.getDetailVente(chatMessageId)
vente.nbLots = Math.max(0, vente.nbLots - quantite)
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
chatMessage.update({ content: html });
chatMessage.render(true);
}
static async displayAchatVente(vente) {
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html))
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
await chatMessage.setFlag(SYSTEM_RDD, DETAIL_VENTE, {
item: vente.item,
properties: vente.item.getProprietes(),
vendeurId: vente.vendeurId,
tailleLot: vente.tailleLot,
quantiteIllimite: vente.quantiteIllimite,
prixLot: vente.prixLot
})
}
}

View File

@ -1,34 +1,12 @@
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";
export class DialogItemAchat extends Dialog { export class DialogItemAchat extends Dialog {
static preparerAchat(chatButton) { static preparerAchat(chatButton) {
const vendeurId = chatButton.attributes['data-vendeurId']?.value; return ChatVente.getDetailAchatVente(RdDUtility.findChatMessageId(chatButton))
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const acheteur = RdDUtility.getSelectedActor();
const json = chatButton.attributes['data-jsondata']?.value;
if (!acheteur && !vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return undefined;
} }
if (!json) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return undefined;
}
return {
item: JSON.parse(json),
vendeur,
acheteur,
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
};
}
static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) { static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
const venteData = { const venteData = {
@ -38,17 +16,21 @@ export class DialogItemAchat extends Dialog {
acheteur, acheteur,
tailleLot, tailleLot,
quantiteIllimite, quantiteIllimite,
quantiteNbLots: nbLots, nbLots,
choix: { seForcer: false, supprimerSiZero: true }, choix: { seForcer: false, supprimerSiZero: true },
prixLot, prixLot,
isVente: prixLot > 0, isVente: prixLot > 0,
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(), isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
chatMessageIdVente chatMessageIdVente
}; }
if (venteData.vendeur?.id == venteData.acheteur?.id) {
ui.notifications.info("Inutile de se vendre à soi-même")
return
}
DialogItemAchat.changeNombreLots(venteData, 1); DialogItemAchat.changeNombreLots(venteData, 1)
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData)
new DialogItemAchat(html, venteData).render(true); new DialogItemAchat(html, venteData).render(true)
} }
static changeNombreLots(venteData, nombreLots) { static changeNombreLots(venteData, nombreLots) {
@ -116,18 +98,18 @@ export class DialogItemAchat extends Dialog {
this.venteData.choix.seForcer = event.currentTarget.checked; this.venteData.choix.seForcer = event.currentTarget.checked;
} }
setNombreLots(nombreLots) { setNombreLots(nbLots) {
if (!this.venteData.quantiteIllimite) { if (!this.venteData.quantiteIllimite) {
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) { if (!this.venteData.quantiteIllimite && nbLots > this.venteData.nbLots) {
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`) ui.notifications.warn(`Seulement ${this.venteData.nbLots} lots disponibles, vous ne pouvez pas en prendre ${nbLots}`)
} }
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots); nbLots = Math.min(nbLots, this.venteData.nbLots);
} }
DialogItemAchat.changeNombreLots(this.venteData, nombreLots); DialogItemAchat.changeNombreLots(this.venteData, nbLots);
this.html.find(".nombreLots").val(nombreLots); this.html.find(".nombreLots").val(nbLots);
this.html.find(".prixTotal").text(this.venteData.prixTotal); this.html.find(".prixTotal").text(this.venteData.prixTotal);
this.html.find("span.total-sust").text(this.venteData.totalSust); this.html.find("span.total-sust").text(this.venteData.totalSust);
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere); this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);

View File

@ -1,10 +1,11 @@
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "../html-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { ChatVente } from "./chat-vente.js";
export class DialogItemVente extends Dialog { export class DialogItemVente extends Dialog {
static async display({ item, callback, quantiteMax = undefined }) { static async display({ item, quantiteMax = undefined }) {
const quantite = quantiteMax ?? item.getQuantite() ?? 1; const quantite = quantiteMax ?? item.getQuantite() ?? 1;
const isOwned = item.parent;
const venteData = { const venteData = {
item: item, item: item,
alias: item.actor?.name ?? game.user.name, alias: item.actor?.name ?? game.user.name,
@ -13,17 +14,17 @@ export class DialogItemVente extends Dialog {
prixUnitaire: item.calculerPrixCommercant(), prixUnitaire: item.calculerPrixCommercant(),
prixLot: item.calculerPrixCommercant(), prixLot: item.calculerPrixCommercant(),
tailleLot: 1, tailleLot: 1,
quantiteNbLots: quantite, nbLots: quantite,
quantiteMaxLots: quantite, maxLots: quantite,
quantiteMax: quantite, quantiteMax: quantite,
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned, quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !item.parent,
isOwned: isOwned, isOwned: item.parent,
}; }
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData); const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
return new DialogItemVente(venteData, html, callback).render(true); return new DialogItemVente(venteData, html).render(true);
} }
constructor(venteData, html, callback) { constructor(venteData, html) {
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 }; let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
let conf = { let conf = {
@ -34,7 +35,6 @@ export class DialogItemVente extends Dialog {
}; };
super(conf, options); super(conf, options);
this.callback = callback;
this.venteData = venteData; this.venteData = venteData;
} }
@ -43,7 +43,7 @@ export class DialogItemVente extends Dialog {
this.html = html; this.html = html;
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value))); this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value))); this.html.find(".nbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked)); this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value))); this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
@ -52,7 +52,15 @@ export class DialogItemVente extends Dialog {
async onProposer(it) { async onProposer(it) {
this.updateVente(this.getChoixVente()); this.updateVente(this.getChoixVente());
this.callback(this.venteData);
this.venteData["properties"] = this.venteData.item.getProprietes();
if (this.venteData.isOwned) {
if (this.venteData.nbLots * this.venteData.tailleLot > this.venteData.quantiteMax) {
ui.notifications.warn(`Vous avez ${this.venteData.quantiteMax} ${this.venteData.item.name}, ce n'est pas suffisant pour vendre ${this.venteData.nbLots} de ${this.venteData.tailleLot}`)
return;
}
}
await ChatVente.displayAchatVente(this.venteData)
} }
updateVente(update) { updateVente(update) {
@ -61,7 +69,7 @@ export class DialogItemVente extends Dialog {
getChoixVente() { getChoixVente() {
return { return {
quantiteNbLots: Number(this.html.find(".quantiteNbLots").val()), nbLots: Number(this.html.find(".nbLots").val()),
tailleLot: Number(this.html.find(".tailleLot").val()), tailleLot: Number(this.html.find(".tailleLot").val()),
quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'), quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'),
prixLot: Number(this.html.find(".prixLot").val()) prixLot: Number(this.html.find(".prixLot").val())
@ -77,26 +85,26 @@ export class DialogItemVente extends Dialog {
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot); const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.updateVente({ this.updateVente({
tailleLot, tailleLot,
quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots), nbLots: Math.min(maxLots, this.venteData.nbLots),
quantiteMaxLots: maxLots, maxLots: maxLots,
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2) prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
}); });
this.html.find(".prixLot").val(this.venteData.prixLot); this.html.find(".prixLot").val(this.venteData.prixLot);
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); this.html.find(".nbLots").val(this.venteData.nbLots);
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots) this.html.find(".nbLots").attr("max", this.venteData.maxLots)
} }
setNbLots(nbLots) { setNbLots(nbLots) {
this.updateVente({ this.updateVente({
quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots nbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.maxLots)) : nbLots
}) })
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots); this.html.find(".nbLots").val(this.venteData.nbLots);
} }
setQuantiteIllimite(checked) { setQuantiteIllimite(checked) {
this.updateVente({ quantiteIllimite: checked }) this.updateVente({ quantiteIllimite: checked })
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles"); this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite) HtmlUtility.showControlWhen(this.html.find(".nbLots"), !this.venteData.quantiteIllimite)
} }
} }

View File

@ -17,6 +17,7 @@ import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js"; import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
@ -32,14 +33,13 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
width: 550, width: 550,
showCompNiveauBase: false, showCompNiveauBase: false,
vueArchetype: false, vueArchetype: false,
}); }, { inplace: false });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
let formData = await super.getData(); let formData = await super.getData();
foundry.utils.mergeObject(formData, foundry.utils.mergeObject(formData, {
{
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
limited: this.actor.limited, limited: this.actor.limited,
@ -128,7 +128,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.render(true); this.render(true);
}); });
this.html.find('.visu-tmr').click(async event => this.actor.displayTMR("visu")) this.html.find('.button-tmr-visu').click(async event => this.actor.displayTMR("visu"))
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
@ -186,7 +186,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event))) this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event)))
this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle')) this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
this.html.find('.chance-appel').click(async event => this.actor.rollAppelChance()) this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance())
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux()) this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event))) this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
@ -199,6 +199,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event))) this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event))) this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
if (game.user.isGM) { if (game.user.isGM) {
// experience log // experience log
this.html.find('.experiencelog-delete').click(async event => { this.html.find('.experiencelog-delete').click(async event => {
@ -217,26 +218,26 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
} }
// Points de reve actuel // Points de reve actuel
this.html.find('.ptreve-actuel a').click(async event => this.actor.rollCarac('reve-actuel', true)) this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true))
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor))) this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.arme-label a').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event))))
this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
// Initiative pour l'arme // Initiative pour l'arme
this.html.find('.arme-initiative a').click(async event => { this.html.find('.roll-init-arme').click(async event => {
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id); let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
if (combatant) { if (combatant) {
let action = this._getEventArmeCombat(event); RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
RdDCombatManager.rollInitiativeAction(combatant._id, action);
} else { } else {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat."); ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
} }
}); })
// Display TMR // Display TMR
this.html.find('.monte-tmr').click(async event => this.actor.displayTMR("normal")) this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal"))
this.html.find('.monte-tmr-rapide').click(async event => this.actor.displayTMR("rapide")) this.html.find('.button-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
this.html.find('.repos').click(async event => await this.actor.repos()) this.html.find('.button-repos').click(async event => await this.actor.repos())
this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", ""))) this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event))) this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
@ -278,7 +279,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse')) this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse'))
this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre')) this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre'))
this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse')) this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse'))
this.html.find('.ethylisme-test').click(async event => this.actor.jetEthylisme()) this.html.find('.button-ethylisme').click(async event => this.actor.jetEthylisme())
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1)) this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1)) this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))

View File

@ -32,10 +32,12 @@ import { RdDItemBlessure } from "./item/blessure.js";
import { AppAstrologie } from "./sommeil/app-astrologie.js"; import { AppAstrologie } from "./sommeil/app-astrologie.js";
import { RdDEmpoignade } from "./rdd-empoignade.js"; import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js"; import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
import { RdDBaseActorSang } from "./actor/base-actor-sang.js"; import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js"; import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
import { RdDItemArme } from "./item-arme.js";
import { RdDCombatManager } from "./rdd-combat.js";
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre'] export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
@ -92,7 +94,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
canReceive(item) { canReceive(item) {
return ![TYPES.competencecreature, TYPES.tarot, TYPES.service].includes(item.type) return ![ITEM_TYPES.competencecreature, ITEM_TYPES.tarot, ITEM_TYPES.service].includes(item.type)
} }
isPersonnageJoueur() { isPersonnageJoueur() {
@ -125,11 +127,28 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
getMalusArmure() { getMalusArmure() {
return this.itemTypes[TYPES.armure].filter(it => it.system.equipe) return this.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
.map(it => it.system.malus) .map(it => it.system.malus)
.reduce(Misc.sum(), 0); .reduce(Misc.sum(), 0);
} }
listActionsCombat() {
// Recupération des armes
const actions = RdDCombatManager.listActionsArmes(
this.itemTypes[ITEM_TYPES.arme]
.filter(it => RdDItemArme.isAttaque(it))
.concat(RdDItemArme.empoignade(this))
.concat(RdDItemArme.mainsNues(this))
,
this.itemTypes[ITEM_TYPES.competence],
this.system.carac)
if (this.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
}
return actions
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getTache(id) { return this.findItemLike(id, 'tache') } getTache(id) { return this.findItemLike(id, 'tache') }
getMeditation(id) { return this.findItemLike(id, 'meditation') } getMeditation(id) { return this.findItemLike(id, 'meditation') }
@ -142,7 +161,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
getDemiReve() { return this.system.reve.tmrpos.coord } getDemiReve() { return this.system.reve.tmrpos.coord }
getDraconicList() { return this.itemTypes[TYPES.competence].filter(it => it.system.categorie == 'draconic') } getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
getBestDraconic() { return foundry.utils.duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) } getBestDraconic() { return foundry.utils.duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
getDraconicOuPossession() { getDraconicOuPossession() {
return [...this.getDraconicList().filter(it => it.system.niveau >= 0), return [...this.getDraconicList().filter(it => it.system.niveau >= 0),
@ -153,13 +172,13 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async $perteRevePotionsEnchantees() { async $perteRevePotionsEnchantees() {
let potions = this.itemTypes[TYPES.potion] let potions = this.itemTypes[ITEM_TYPES.potion]
.filter(it => Grammar.includesLowerCaseNoAccent(it.system.categorie, 'enchanté') && !it.system.prpermanent) .filter(it => Grammar.includesLowerCaseNoAccent(it.system.categorie, 'enchanté') && !it.system.prpermanent)
const potionUpdates = await Promise.all(potions.map(async it => { const potionUpdates = await Promise.all(potions.map(async it => {
const nouveauReve = Math.max(it.system.pr - 1, 0) const nouveauReve = Math.max(it.system.pr - 1, 0)
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, { content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, {
pr: nouveauReve, pr: nouveauReve,
alias: this.name, alias: this.name,
@ -210,7 +229,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async grisReve(nbJours) { async grisReve(nbJours) {
let message = { let message = {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: `${nbJours} jours de gris rêve sont passés. ` content: `${nbJours} jours de gris rêve sont passés. `
}; };
for (let i = 0; i < nbJours; i++) { for (let i = 0; i < nbJours; i++) {
@ -264,7 +283,7 @@ export class RdDActor extends RdDBaseActorSang {
async dormirChateauDormant() { async dormirChateauDormant() {
if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !this.system.sommeil || this.system.sommeil.nouveaujour) { if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !this.system.sommeil || this.system.sommeil.nouveaujour) {
const message = { const message = {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: "" content: ""
}; };
@ -345,7 +364,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _recupererBlessures(message, isMaladeEmpoisonne) { async _recupererBlessures(message, isMaladeEmpoisonne) {
const timestamp = game.system.rdd.calendrier.getTimestamp() const timestamp = game.system.rdd.calendrier.getTimestamp()
const blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure).sort(Misc.ascending(it => it.system.gravite)) const blessures = this.filterItems(it => it.system.gravite > 0, ITEM_TYPES.blessure).sort(Misc.ascending(it => it.system.gravite))
await Promise.all(blessures.map(async b => b.recuperationBlessure({ await Promise.all(blessures.map(async b => b.recuperationBlessure({
actor: this, actor: this,
@ -361,7 +380,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _recupererVie(message, isMaladeEmpoisonne) { async _recupererVie(message, isMaladeEmpoisonne) {
const tData = this.system const tData = this.system
let blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure); let blessures = this.filterItems(it => it.system.gravite > 0, ITEM_TYPES.blessure);
if (blessures.length > 0) { if (blessures.length > 0) {
return return
} }
@ -400,7 +419,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async remiseANeuf() { async remiseANeuf() {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: 'Remise à neuf de ' + this.name content: 'Remise à neuf de ' + this.name
}); });
await this.supprimerBlessures(it => true); await this.supprimerBlessures(it => true);
@ -417,7 +436,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async dormir(heures, options = { grisReve: false, chateauDormant: false }) { async dormir(heures, options = { grisReve: false, chateauDormant: false }) {
const message = { const message = {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: this.name + ': ' content: this.name + ': '
}; };
const insomnie = this.system.sommeil?.insomnie || heures == 0; const insomnie = this.system.sommeil?.insomnie || heures == 0;
@ -488,7 +507,7 @@ export class RdDActor extends RdDBaseActorSang {
else { else {
if (!ReglesOptionnelles.isUsing("recuperation-reve")) { if (!ReglesOptionnelles.isUsing("recuperation-reve")) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: `Pas de récupération de rêve (${reve} points ignorés)` content: `Pas de récupération de rêve (${reve} points ignorés)`
}); });
jetsReve.push(0); jetsReve.push(0);
@ -636,7 +655,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", [{
type: TYPES.sortreserve, type: ITEM_TYPES.sortreserve,
name: sort.name, name: sort.name,
img: sort.img, img: sort.img,
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' } system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
@ -902,7 +921,7 @@ export class RdDActor extends RdDBaseActorSang {
async ajouterRefoulement(value = 1, refouler) { async ajouterRefoulement(value = 1, refouler) {
let refoulement = this.system.reve.refoulement.value + value; let refoulement = this.system.reve.refoulement.value + value;
const roll = new Roll("1d20"); const roll = new Roll("1d20");
await roll.evaluate({ async: true }); await roll.evaluate();
await roll.toMessage({ flavor: `${this.name} refoule ${refouler} pour ${value} points de refoulement (total: ${refoulement})` }); await roll.toMessage({ flavor: `${this.name} refoule ${refouler} pour ${value} points de refoulement (total: ${refoulement})` });
if (roll.total <= refoulement) { if (roll.total <= refoulement) {
refoulement = 0; refoulement = 0;
@ -919,7 +938,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.createEmbeddedDocuments('Item', [souffle]); await this.createEmbeddedDocuments('Item', [souffle]);
if (options.chat) { if (options.chat) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: this.name + " subit un Souffle de Dragon : " + souffle.name content: this.name + " subit un Souffle de Dragon : " + souffle.name
}); });
} }
@ -939,7 +958,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.createEmbeddedDocuments('Item', [queue]); await this.createEmbeddedDocuments('Item', [queue]);
if (options.chat) { if (options.chat) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: this.name + " subit une Queue de Dragon : " + queue.name content: this.name + " subit une Queue de Dragon : " + queue.name
}); });
} }
@ -977,7 +996,7 @@ export class RdDActor extends RdDBaseActorSang {
let tmr = await TMRUtility.getTMRAleatoire(tmr => accessible(tmr) && !innaccessible.includes(tmr.coord)); let tmr = await TMRUtility.getTMRAleatoire(tmr => accessible(tmr) && !innaccessible.includes(tmr.coord));
ChatMessage.create({ ChatMessage.create({
content: `${raison} : ré-insertion aléatoire.`, content: `${raison} : ré-insertion aléatoire.`,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name) whisper: ChatUtility.getOwners(this)
}); });
await this.forcerPositionTMRInconnue(tmr); await this.forcerPositionTMRInconnue(tmr);
return tmr; return tmr;
@ -991,26 +1010,24 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
buildTMRInnaccessible() { buildTMRInnaccessible() {
return this.items[TYPES.casetmr] return this.items.filter(it => it.type == ITEM_TYPES.casetmr).filter(it => EffetsDraconiques.isInnaccessible(it)).map(it => it.system.coord)
.filter(it => EffetsDraconiques.isInnaccessible(it))
.map(it => it.system.coord)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getRencontresTMR() { getRencontresTMR() {
return this.itemTypes[TYPES.rencontre]; return this.itemTypes[ITEM_TYPES.rencontre];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async deleteRencontreTMRAtPosition() { async deleteRencontreTMRAtPosition() {
const rencontreIds = this.itemTypes[TYPES.rencontre].filter(this.filterRencontreTMRDemiReve()).map(it => it.id) const rencontreIds = this.itemTypes[ITEM_TYPES.rencontre].filter(this.filterRencontreTMRDemiReve()).map(it => it.id)
if (rencontreIds.length > 0) { if (rencontreIds.length > 0) {
await this.deleteEmbeddedDocuments('Item', rencontreIds) await this.deleteEmbeddedDocuments('Item', rencontreIds)
} }
} }
getRencontreTMREnAttente() { getRencontreTMREnAttente() {
return this.itemTypes[TYPES.rencontre].find(this.filterRencontreTMRDemiReve()) return this.itemTypes[ITEM_TYPES.rencontre].find(this.filterRencontreTMRDemiReve())
} }
filterRencontreTMRDemiReve() { filterRencontreTMRDemiReve() {
@ -1084,7 +1101,7 @@ export class RdDActor extends RdDBaseActorSang {
const jetMoral = await this._jetDeMoral(situation); const jetMoral = await this._jetDeMoral(situation);
const finMessage = (jetMoral.succes ? messageReussi : messageManque) ?? (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral"); const finMessage = (jetMoral.succes ? messageReussi : messageManque) ?? (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral");
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${situation} (${jetMoral.jet}/${jetMoral.difficulte}).` content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${situation} (${jetMoral.jet}/${jetMoral.difficulte}).`
}); });
return jetMoral.ajustement; return jetMoral.ajustement;
@ -1148,8 +1165,7 @@ export class RdDActor extends RdDBaseActorSang {
diffNbDoses: -Number(this.system.compteurs.ethylisme.nb_doses || 0), diffNbDoses: -Number(this.system.compteurs.ethylisme.nb_doses || 0),
finalLevel: 0, finalLevel: 0,
diffConditions: 0, diffConditions: 0,
ajustementsForce: CONFIG.RDD.difficultesLibres, ajustementsForce: CONFIG.RDD.difficultesLibres
config: game.system.rdd.config
} }
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ethylisme.html', rollData); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ethylisme.html', rollData);
new RdDRollDialogEthylisme(html, rollData, this, r => this.saouler(r.forceAlcool)).render(true); new RdDRollDialogEthylisme(html, rollData, this, r => this.saouler(r.forceAlcool)).render(true);
@ -1163,11 +1179,11 @@ export class RdDActor extends RdDBaseActorSang {
if (result) { return result } if (result) { return result }
switch (item.type) { switch (item.type) {
case TYPES.potion: return await this.consommerPotion(item, onActionItem); case ITEM_TYPES.potion: return await this.consommerPotion(item, onActionItem);
case TYPES.livre: return await this.actionLire(item); case ITEM_TYPES.livre: return await this.actionLire(item);
case TYPES.conteneur: return await item.sheet.render(true); case ITEM_TYPES.conteneur: return await item.sheet.render(true);
case TYPES.herbe: return await this.actionHerbe(item, onActionItem); case ITEM_TYPES.herbe: return await this.actionHerbe(item, onActionItem);
case TYPES.queue: case TYPES.ombre: return await this.actionRefoulement(item); case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return await this.actionRefoulement(item);
} }
return undefined return undefined
} }
@ -1422,7 +1438,7 @@ export class RdDActor extends RdDBaseActorSang {
}; };
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData)
}); });
@ -1508,7 +1524,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
if (display) { if (display) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html`, checkXp) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html`, checkXp)
}); });
} }
@ -1540,7 +1556,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
if (display) { if (display) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html`, checkXp) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html`, checkXp)
}); });
} }
@ -1551,6 +1567,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
if (!Misc.isFirstConnectedGM()) {
return
}
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance); let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance);
if (xpData.length) { if (xpData.length) {
@ -1559,11 +1578,11 @@ export class RdDActor extends RdDBaseActorSang {
xpData xpData
}) })
if (hideChatMessage) { if (hideChatMessage) {
ChatUtility.blindMessageToGM({ content: content }); ChatUtility.blindMessageToGM({ content: content })
} }
else { else {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: content content: content
}); });
} }
@ -1602,7 +1621,7 @@ export class RdDActor extends RdDBaseActorSang {
computeDraconicAndSortIndex(sortList) { computeDraconicAndSortIndex(sortList) {
let draconicList = this.getDraconicList(); let draconicList = this.getDraconicList();
for (let sort of sortList) { for (let sort of sortList) {
let draconicsSort = this.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++) {
if (draconicsSort.includes(draconicList[index].name)) { if (draconicsSort.includes(draconicList[index].name)) {
sort.system.listIndex = index; sort.system.listIndex = index;
@ -1612,19 +1631,6 @@ export class RdDActor extends RdDBaseActorSang {
return draconicList; return draconicList;
} }
/* -------------------------------------------- */
getDraconicsSort(draconicList, sort) {
//console.log(draconicList, bestDraconic, draconic, voie);
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
case "lecture d'aura":
case "detection d'aura":
return draconicList;
case "annulation de magie":
return draconicList.filter(it => !RdDItemCompetence.isThanatos(it));
}
return [RdDItemCompetence.getVoieDraconic(draconicList, sort.system.draconic)];
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollUnSort(coord) { async rollUnSort(coord) {
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
@ -1679,7 +1685,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
ChatMessage.create({ ChatMessage.create({
content: "Vous êtes sous le coup d'une Mauvaise Rencontre en Persective." + addMsg, content: "Vous êtes sous le coup d'une Mauvaise Rencontre en Persective." + addMsg,
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
} }
return rencSpecial; return rencSpecial;
@ -1691,7 +1697,7 @@ export class RdDActor extends RdDBaseActorSang {
if (countInertieDraconique > 0) { if (countInertieDraconique > 0) {
ChatMessage.create({ ChatMessage.create({
content: `Vous êtes sous le coup d'Inertie Draconique : vous perdrez ${countInertieDraconique + 1} cases de Fatigue par déplacement au lieu d'une.`, content: `Vous êtes sous le coup d'Inertie Draconique : vous perdrez ${countInertieDraconique + 1} cases de Fatigue par déplacement au lieu d'une.`,
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
} }
return countInertieDraconique + 1; return countInertieDraconique + 1;
@ -1703,7 +1709,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.reveActuelIncDec(-1); await this.reveActuelIncDec(-1);
ChatMessage.create({ ChatMessage.create({
content: "Vous êtes sous le coup d'un Péage : l'entrée sur cette case vous a coûté 1 Point de Rêve (déduit automatiquement).", content: "Vous êtes sous le coup d'un Péage : l'entrée sur cette case vous a coûté 1 Point de Rêve (déduit automatiquement).",
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
} }
} }
@ -1826,7 +1832,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
blessuresASoigner() { blessuresASoigner() {
return (this.itemTypes[TYPES.blessure]) return (this.itemTypes[ITEM_TYPES.blessure])
.filter(it => it.system.gravite > 0 && it.system.gravite <= 6) .filter(it => it.system.gravite > 0 && it.system.gravite <= 6)
.filter(it => !(it.system.premierssoins.done && it.system.soinscomplets.done)) .filter(it => !(it.system.premierssoins.done && it.system.soinscomplets.done))
.sort(Misc.descending(b => (b.system.premierssoins.done ? "A" : "B") + b.system.gravite)) .sort(Misc.descending(b => (b.system.premierssoins.done ? "A" : "B") + b.system.gravite))
@ -2283,7 +2289,7 @@ export class RdDActor extends RdDBaseActorSang {
// Cas de désir lancinant, pas d'expérience sur particulière // Cas de désir lancinant, pas d'expérience sur particulière
ChatMessage.create({ ChatMessage.create({
content: `Vous souffrez au moins d'un Désir Lancinant, vous ne pouvez pas gagner d'expérience sur une Particulière tant que le désir n'est pas assouvi`, content: `Vous souffrez au moins d'un Désir Lancinant, vous ne pouvez pas gagner d'expérience sur une Particulière tant que le désir n'est pas assouvi`,
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
return [] return []
} }
@ -2346,7 +2352,7 @@ export class RdDActor extends RdDBaseActorSang {
async _xpCaracDerivee(xpData) { async _xpCaracDerivee(xpData) {
const caracs = RdDActor._getComposantsCaracDerivee(xpData.caracName) const caracs = RdDActor._getComposantsCaracDerivee(xpData.caracName)
.map(c => foundry.utils.mergeObject(this.system.carac[c], { isMax: this.isCaracMax(c) })) .map(c => foundry.utils.mergeObject(this.system.carac[c], { isMax: this.isCaracMax(c) }, { inplace: false }))
switch (caracs.filter(it => !it.isMax).length) { switch (caracs.filter(it => !it.isMax).length) {
case 0: case 0:
xpData.caracRepartitionManuelle = true; xpData.caracRepartitionManuelle = true;
@ -2418,7 +2424,7 @@ export class RdDActor extends RdDBaseActorSang {
if (countMonteeLaborieuse > 0) { if (countMonteeLaborieuse > 0) {
ChatMessage.create({ ChatMessage.create({
content: `Vous êtes sous le coup d'une Montée Laborieuse : vos montées en TMR coûtent ${countMonteeLaborieuse} Point de Rêve de plus.`, content: `Vous êtes sous le coup d'une Montée Laborieuse : vos montées en TMR coûtent ${countMonteeLaborieuse} Point de Rêve de plus.`,
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
} }
return countMonteeLaborieuse; return countMonteeLaborieuse;
@ -2466,7 +2472,7 @@ export class RdDActor extends RdDBaseActorSang {
if (this.getReveActuel() < minReveValue) { if (this.getReveActuel() < minReveValue) {
ChatMessage.create({ ChatMessage.create({
content: `Vous n'avez les ${minReveValue} Points de Reve nécessaires pour monter dans les Terres Médianes`, content: `Vous n'avez les ${minReveValue} Points de Reve nécessaires pour monter dans les Terres Médianes`,
whisper: ChatMessage.getWhisperRecipients(this.name) whisper: ChatUtility.getOwners(this)
}); });
return; return;
} }
@ -2629,12 +2635,12 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async resetItemUse() { async resetItemUse() {
await this.unsetFlag(SYSTEM_RDD, 'itemUse'); await this.unsetFlag(SYSTEM_RDD, 'itemUse');
await this.setFlag(SYSTEM_RDD, 'itemUse', {});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async incDecItemUse(itemId, inc = 1) { async incDecItemUse(itemId, inc = 1) {
let itemUse = foundry.utils.duplicate(this.getFlag(SYSTEM_RDD, 'itemUse') ?? {}); const currentItemUse = this.getFlag(SYSTEM_RDD, 'itemUse');
let itemUse = currentItemUse ? foundry.utils.duplicate(currentItemUse) : {};
itemUse[itemId] = (itemUse[itemId] ?? 0) + inc; itemUse[itemId] = (itemUse[itemId] ?? 0) + inc;
await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse); await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse);
console.log("ITEM USE INC", inc, itemUse); console.log("ITEM USE INC", inc, itemUse);
@ -2863,7 +2869,7 @@ export class RdDActor extends RdDBaseActorSang {
await this.setBonusPotionSoin(potionData.system.herbebonus); await this.setBonusPotionSoin(potionData.system.herbebonus);
} }
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-soin.html`, potionData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-soin.html`, potionData)
}); });
} }
@ -2900,7 +2906,7 @@ export class RdDActor extends RdDBaseActorSang {
this.bonusRepos = potionData.system.herbebonus; this.bonusRepos = potionData.system.herbebonus;
} }
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-repos.html`, potionData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-repos.html`, potionData)
}); });
} }
@ -2932,7 +2938,7 @@ export class RdDActor extends RdDBaseActorSang {
this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins); this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html`, messageData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html`, messageData)
}); });
} }
@ -2957,7 +2963,7 @@ export class RdDActor extends RdDBaseActorSang {
} }
} }
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-generique.html`, potionData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-generique.html`, potionData)
}); });
} }
@ -3024,7 +3030,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onCreateOwnedDraconique(item, options, id) { async onCreateOwnedDraconique(item, options, id) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.match(item)); let draconique = Draconique.all().find(it => it.match(item));
if (draconique) { if (draconique) {
await draconique.onActorCreateOwned(this, item) await draconique.onActorCreateOwned(this, item)
@ -3036,7 +3042,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onDeleteOwnedDraconique(item, options, id) { async onDeleteOwnedDraconique(item, options, id) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.match(item)); let draconique = Draconique.all().find(it => it.match(item));
if (draconique) { if (draconique) {
await draconique.onActorDeleteOwned(this, item) await draconique.onActorDeleteOwned(this, item)
@ -3046,7 +3052,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onDeleteOwnedCaseTmr(item, options, id) { async onDeleteOwnedCaseTmr(item, options, id) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
let draconique = Draconique.all().find(it => it.isCase(item)); let draconique = Draconique.all().find(it => it.isCase(item));
if (draconique) { if (draconique) {
await draconique.onActorDeleteCaseTmr(this, item) await draconique.onActorDeleteCaseTmr(this, item)
@ -3057,7 +3063,7 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
notifyGestionTeteSouffleQueue(item, manualMessage = true) { notifyGestionTeteSouffleQueue(item, manualMessage = true) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: `${this.name} a reçu un/une ${item.type}: ${item.name}, qui ${manualMessage ? "n'est pas" : "est"} géré(e) automatiquement. ${manualMessage ? manualMessage : ''}` content: `${this.name} a reçu un/une ${item.type}: ${item.name}, qui ${manualMessage ? "n'est pas" : "est"} géré(e) automatiquement. ${manualMessage ? manualMessage : ''}`
}); });
} }
@ -3065,7 +3071,7 @@ export class RdDActor extends RdDBaseActorSang {
async nouvelleIncarnation() { async nouvelleIncarnation() {
let incarnation = this.toObject(); let incarnation = this.toObject();
incarnation.items = Array.from(this.items.filter(it => it.type == TYPES.competence), incarnation.items = Array.from(this.items.filter(it => it.type == ITEM_TYPES.competence),
it => { it => {
it = it.toObject(); it = it.toObject();
it.id = undefined; it.id = undefined;
@ -3080,7 +3086,7 @@ export class RdDActor extends RdDBaseActorSang {
incarnation.name = 'Réincarnation de ' + incarnation.name incarnation.name = 'Réincarnation de ' + incarnation.name
incarnation.system = { incarnation.system = {
carac: foundry.utils.duplicate(this.system.carac), carac: foundry.utils.duplicate(this.system.carac),
heure: RdDTimestamp.defHeure(await RdDDice.rollTotal("1dh", { rollMode: "selfroll", showDice: SHOW_DICE })).key, heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key,
age: 18, age: 18,
biographie: '', biographie: '',
notes: '', notes: '',

View File

@ -24,14 +24,15 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
this.html.find('.encaisser-direct').click(async event => this.actor.encaisser()) this.html.find('.button-encaissement').click(async event => this.actor.encaisser())
this.html.find('.carac-label a').click(async event => this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes.name.value))); this.html.find('.roll-carac').click(async event => {
this.html.find('a.competence-label').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event))); this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))});
this.html.find('.roll-competence').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1)); this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1));
this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1)); this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1));
if (game.user.isGM) { if (game.user.isGM) {
this.html.find('.remise-a-neuf').click(async event => this.actor.remiseANeuf()) this.html.find('.button-remise-a-neuf').click(async event => this.actor.remiseANeuf())
this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect'))); this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect')));
this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects()); this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects());
} }

View File

@ -12,10 +12,10 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { RdDBaseActor } from "./base-actor.js"; import { RdDBaseActor } from "./base-actor.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { StatusEffects } from "../settings/status-effects.js"; import { StatusEffects } from "../settings/status-effects.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { Targets } from "../targets.js"; import { Targets } from "../targets.js";
import { RdDPossession } from "../rdd-possession.js"; import { RdDPossession } from "../rdd-possession.js";
import { RdDCombat } from "../rdd-combat.js"; import { RdDCombat, RdDCombatManager } from "../rdd-combat.js";
import { RdDConfirm } from "../rdd-confirm.js"; import { RdDConfirm } from "../rdd-confirm.js";
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js"; import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItemArme } from "../item-arme.js"; import { RdDItemArme } from "../item-arme.js";
@ -78,8 +78,27 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } } async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } }
isDead() { return false } isDead() { return false }
isSonne() { return false }
blessuresASoigner() { return [] } blessuresASoigner() { return [] }
getEtatGeneral(options = { ethylisme: false }) { return 0 } getEtatGeneral(options = { ethylisme: false }) { return 0 }
isActorCombat() { return true }
getCaracInit(competence) {
if (!competence){
return 0
}
if (competence.type == ITEM_TYPES.competencecreature) {
return competence.system.carac_value
}
return this.system.carac[competence.system.defaut_carac].value;
}
listActionsCombat() {
return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
.map(it => RdDItemCompetenceCreature.armeCreature(it))
.filter(it => it != undefined);
}
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() } async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { } async remiseANeuf() { }
@ -108,14 +127,14 @@ export class RdDBaseActorReve extends RdDBaseActor {
async $finDeRoundSupprimerObsoletes() { async $finDeRoundSupprimerObsoletes() {
const obsoletes = [] const obsoletes = []
.concat(this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp <= 0)) .concat(this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
.concat(this.itemTypes[TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2)) .concat(this.itemTypes[ITEM_TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
.map(it => it.id); .map(it => it.id);
await this.deleteEmbeddedDocuments('Item', obsoletes); await this.deleteEmbeddedDocuments('Item', obsoletes);
} }
async $finDeRoundEmpoignade() { async $finDeRoundEmpoignade() {
const immobilisations = this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id); const immobilisations = this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this, immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
game.actors.get(emp.system.empoigneid), game.actors.get(emp.system.empoigneid),
emp emp
@ -151,13 +170,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
getPossession(possessionId) { getPossession(possessionId) {
return this.itemTypes[TYPES.possession].find(it => it.system.possessionid == possessionId); return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
}
getPossessions() {
return this.itemTypes[TYPES.possession];
} }
getEmpoignades() { getEmpoignades() {
return this.itemTypes[TYPES.empoignade]; return this.itemTypes[ITEM_TYPES.empoignade];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -286,18 +302,22 @@ export class RdDBaseActorReve extends RdDBaseActor {
getCarac() { getCarac() {
// TODO: le niveau d'une entité de cauchemar devrait être exclu... // TODO: le niveau d'une entité de cauchemar devrait être exclu...
const carac = foundry.utils.mergeObject(foundry.utils.duplicate(this.system.carac), return foundry.utils.mergeObject(this.system.carac,
{ {
'reve-actuel': this.getCaracReveActuel(), 'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle() 'chance-actuelle': this.getCaracChanceActuelle()
}); },
return carac; { inplace: false })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCarac(caracName, jetResistance = undefined) { async rollCarac(caracName, jetResistance = undefined) {
if (Grammar.equalsInsensitive(caracName, 'taille')) {
return
}
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName) let selectedCarac = this.getCaracByName(caracName)
console.log("selectedCarac", selectedCarac)
await this.openRollDialog({ await this.openRollDialog({
name: 'jet-' + caracName, name: 'jet-' + caracName,
label: 'Jet ' + Grammar.apostrophe('de', selectedCarac.label), label: 'Jet ' + Grammar.apostrophe('de', selectedCarac.label),
@ -318,19 +338,20 @@ export class RdDBaseActorReve extends RdDBaseActor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true }) { async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
RdDEmpoignade.checkEmpoignadeEnCours(this) RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName); const competence = this.getCompetence(idOrName);
let rollData = { carac: this.system.carac, competence: competence } let rollData = { carac: this.system.carac, competence: competence, arme: options.arme }
if (competence.type == TYPES.competencecreature) { if (competence.type == ITEM_TYPES.competencecreature) {
const token = RdDUtility.getSelectedToken(this)
const arme = RdDItemCompetenceCreature.armeCreature(competence) const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) { if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneToken(target => { Targets.selectOneTargetToken(target => {
if (arme.action == "possession") { if (arme.action == "possession") {
RdDPossession.onAttaquePossession(target, this, competence) RdDPossession.onAttaquePossession(target, this, competence)
} }
else { else {
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme) RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
} }
}); });
return; return;
@ -360,9 +381,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
* @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
* @returns * @returns
*/ */
rollArme(arme, categorieArme = "competence") { rollArme(arme, categorieArme, token) {
let compToUse = this.$getCompetenceArme(arme, categorieArme) token = token ?? RdDUtility.getSelectedToken(this)
if (!RdDItemArme.isArmeUtilisable(arme)) { const compToUse = this.$getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`) ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
return return
} }
@ -375,13 +397,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
title: 'Ne pas utiliser les automatisation de combat', title: 'Ne pas utiliser les automatisation de combat',
buttonLabel: "Pas d'automatisation", buttonLabel: "Pas d'automatisation",
onAction: async () => { onAction: async () => {
this.rollCompetence(compToUse, { tryTarget: false }) this.rollCompetence(compToUse, { tryTarget: false, arme: arme })
} }
}); });
return return
} }
Targets.selectOneToken(target => { Targets.selectOneTargetToken(target => {
if (Targets.isTargetEntite(target)) { if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`); ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
return return
@ -391,89 +413,74 @@ export class RdDBaseActorReve extends RdDBaseActor {
if (competence.isCompetencePossession()) { if (competence.isCompetencePossession()) {
return RdDPossession.onAttaquePossession(target, this, competence); return RdDPossession.onAttaquePossession(target, this, competence);
} }
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme); RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
}) })
} }
$getCompetenceArme(arme, competenceName) { $getCompetenceArme(arme, competenceName) {
switch (arme.type) { return RdDItemArme.getCompetenceArme(arme, competenceName)
case TYPES.competencecreature:
return arme.name
case TYPES.arme:
switch (competenceName) {
case 'competence': return arme.system.competence;
case 'unemain': return RdDItemArme.competence1Mains(arme);
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
case 'tir': return arme.system.tir;
case 'lancer': return arme.system.lancer;
}
}
return undefined
} }
verifierForceMin(item) { verifierForceMin(item) { }
}
/* -------------------------------------------- */
async resetItemUse() { }
async incDecItemUse(itemId, inc = 1) { }
getItemUse(itemId) { return 0; }
/* -------------------------------------------- */ /* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) } async encaisser() { await RdDEncaisser.encaisser(this) }
async encaisserDommages(rollData, attacker = undefined, show = undefined) { async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) { if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return; return;
} }
const armure = await this.computeArmure(rollData); const armure = await this.computeArmure(rollData);
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')){ if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
await this.encaisserDommagesValidationGR(rollData, armure, attacker?.id, show); await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
} }
else { else {
const jet = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE }); const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
await this.$onEncaissement(jet, show, attacker); await this.$onEncaissement(jet, show, attackerToken, defenderToken)
} }
} }
async encaisserDommagesValidationGR(rollData, armure, attackerId, show) { async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
if (!game.user.isGM) { if (!game.user.isGM) {
RdDBaseActor.remoteActorCall({ RdDBaseActor.remoteActorCall({
tokenId: this.token?.id, tokenId: this.token?.id,
actorId: this.id, actorId: this.id,
method: 'encaisserDommagesValidationGR', method: 'encaisserDommagesValidationGR',
args: [rollData, armure, attackerId, show] args: [rollData, armure, show, attackerToken, defenderToken]
}); })
} else { } else {
const attacker = game.actors.get(attackerId);
DialogValidationEncaissement.validerEncaissement(this, rollData, armure, DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
jet => this.$onEncaissement(jet, show, attacker)); jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
} }
} }
async $onEncaissement(jet, show, attacker) { async $onEncaissement(jet, show, attackerToken, defenderToken) {
await this.onAppliquerJetEncaissement(jet, attacker); await this.onAppliquerJetEncaissement(jet, attackerToken);
await this.$afficherEncaissement(jet, show); await this.$afficherEncaissement(jet, show, defenderToken);
} }
async onAppliquerJetEncaissement(encaissement, attacker) { } async onAppliquerJetEncaissement(encaissement, attackerToken) { }
async $afficherEncaissement(encaissement, show) { async $afficherEncaissement(encaissement, show, defenderToken) {
foundry.utils.mergeObject(encaissement, { foundry.utils.mergeObject(encaissement, {
alias: this.name, alias: defenderToken?.name ?? this.name,
hasPlayerOwner: this.hasPlayerOwner, hasPlayerOwner: this.hasPlayerOwner,
show: show ?? {} show: show ?? {}
}); }, { overwrite: false });
await ChatUtility.createChatWithRollMode(this.name, { await ChatUtility.createChatWithRollMode(
{
roll: encaissement.roll, roll: encaissement.roll,
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement) content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
}); },
this
)
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) { if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
encaissement = foundry.utils.duplicate(encaissement); encaissement = foundry.utils.duplicate(encaissement)
encaissement.isGM = true; encaissement.isGM = true
ChatMessage.create({ ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients("GM"), whisper: ChatUtility.getGMs(),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement) content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
}); });
} }
@ -508,8 +515,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
isEntiteAccordee(attacker) { return true } isEntiteAccordee(attacker) { return true }
async setEntiteReveAccordee(attacker) { async setEntiteReveAccordee(actor) {
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve"); ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entité incarnée");
} }
} }

View File

@ -39,8 +39,8 @@ export class RdDBaseActorSangSheet extends RdDBaseActorReveSheet {
ChatMessage.create({ ChatMessage.create({
content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance} content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance}
<br>${this.actor.name} a ${result.sonne ? 'échoué' : 'réussi'} son Jet d'Endurance ${result.sonne ? 'et devient Sonné' : ''}`, <br>${this.actor.name} a ${result.sonne ? 'échoué' : 'réussi'} son Jet d'Endurance ${result.sonne ? 'et devient Sonné' : ''}`,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.actor.name) whisper: ChatUtility.getOwners(this.actor)
}); })
} }
} }

View File

@ -1,10 +1,11 @@
import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js"; import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { STATUSES } from "../settings/status-effects.js"; import { STATUSES } from "../settings/status-effects.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { RdDBaseActorReve } from "./base-actor-reve.js"; import { RdDBaseActorReve } from "./base-actor-reve.js";
import { RdDDice } from "../rdd-dice.js"; import { RdDDice } from "../rdd-dice.js";
import { RdDItemBlessure } from "../item/blessure.js"; import { RdDItemBlessure } from "../item/blessure.js";
import { ChatUtility } from "../chat-utility.js";
/** /**
* Classe de base pour les acteurs qui peuvent subir des blessures * Classe de base pour les acteurs qui peuvent subir des blessures
@ -50,9 +51,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
isDead() { return this.system.sante.vie.value < -this.getSConst() } isDead() { return this.system.sante.vie.value < -this.getSConst() }
nbBlessuresLegeres() { return this.itemTypes[TYPES.blessure].filter(it => it.isLegere()).length } nbBlessuresLegeres() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isLegere()).length }
nbBlessuresGraves() { return this.itemTypes[TYPES.blessure].filter(it => it.isGrave()).length } nbBlessuresGraves() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isGrave()).length }
nbBlessuresCritiques() { return this.itemTypes[TYPES.blessure].filter(it => it.isCritique()).length } nbBlessuresCritiques() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isCritique()).length }
/* -------------------------------------------- */ /* -------------------------------------------- */
computeResumeBlessure() { computeResumeBlessure() {
@ -88,9 +89,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onAppliquerJetEncaissement(encaissement, attacker) { async onAppliquerJetEncaissement(encaissement, attackerToken) {
const santeOrig = foundry.utils.duplicate(this.system.sante); const santeOrig = foundry.utils.duplicate(this.system.sante);
const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table
const perteVie = await this.santeIncDec("vie", -encaissement.vie); const perteVie = await this.santeIncDec("vie", -encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique()); const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
@ -168,7 +169,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterBlessure(encaissement, attacker = undefined) { async ajouterBlessure(encaissement, attackerToken = undefined) {
if (encaissement.gravite < 0) return; if (encaissement.gravite < 0) return;
if (encaissement.gravite > 0) { if (encaissement.gravite > 0) {
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) { while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
@ -180,7 +181,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, attacker); 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;
} }
@ -196,20 +197,30 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
return blessure; return blessure;
} }
async supprimerBlessure({ gravite }) {
const toDelete = this.itemTypes[ITEM_TYPES.blessure].find(it => it.system.gravite == gravite)?.id
if (toDelete) {
await this.deleteEmbeddedDocuments('Item', [toDelete]);
}
}
async supprimerBlessures(filterToDelete) { async supprimerBlessures(filterToDelete) {
const toDelete = this.filterItems(filterToDelete, TYPES.blessure) const toDelete = this.filterItems(filterToDelete, ITEM_TYPES.blessure)
.map(it => it.id); .map(it => it.id);
await this.deleteEmbeddedDocuments('Item', toDelete); await this.deleteEmbeddedDocuments('Item', toDelete);
} }
countBlessures(filter = it => !it.isContusion()) { countBlessures(filter = it => !it.isContusion()) {
return this.filterItems(filter, 'blessure').length return this.filterItems(filter, ITEM_TYPES.blessure).length
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async jetDeVie() { async jetDeVie() {
if (this.isDead()) { if (this.isDead()) {
ChatMessage.create({ content: `Jet de Vie: ${this.name} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`, whisper: ChatMessage.getWhisperRecipients(this.name) }); ChatMessage.create({
content: `Jet de Vie: ${this.name} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`,
whisper: ChatUtility.getOwners(this)
})
return return
} }
const jetDeVie = await RdDDice.roll("1d20"); const jetDeVie = await RdDDice.roll("1d20");
@ -236,7 +247,10 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
else if (prochainJet > 0) { else if (prochainJet > 0) {
msgText += `<br>Prochain jet de vie dans ${prochainJet} ${isCritique ? 'round' : 'minute'}${prochainJet > 1 ? 's' : ''} ${isCritique ? '(état critique)' : '(état grave)'}` msgText += `<br>Prochain jet de vie dans ${prochainJet} ${isCritique ? 'round' : 'minute'}${prochainJet > 1 ? 's' : ''} ${isCritique ? '(état critique)' : '(état grave)'}`
} }
ChatMessage.create({ content: msgText, whisper: ChatMessage.getWhisperRecipients(this.name) }); ChatMessage.create({
content: msgText,
whisper: ChatUtility.getOwners(this)
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -262,11 +276,11 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`); ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`);
return; return;
} }
await this.setEffect(STATUSES.StatusStunned, sonne); await this.setEffect(STATUSES.StatusStunned, sonne)
} }
getSonne() { isSonne() {
return this.getEffect(STATUSES.StatusStunned); return this.getEffect(STATUSES.StatusStunned)
} }
isEffectAllowed(effectId) { return true } isEffectAllowed(effectId) { return true }

View File

@ -3,7 +3,7 @@ import { Misc } from "../misc.js";
import { DialogSplitItem } from "../dialog-split-item.js"; import { DialogSplitItem } from "../dialog-split-item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js"; import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js"; import { Monnaie } from "../item-monnaie.js";
import { RdDItem, TYPES } from "../item.js"; import { RdDItem, ITEM_TYPES } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js"; import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -20,7 +20,7 @@ export class RdDBaseActorSheet extends ActorSheet {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }], dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
vueDetaillee: false vueDetaillee: false
}); }, { inplace: false })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -38,8 +38,7 @@ export class RdDBaseActorSheet extends ActorSheet {
description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }), description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }),
notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }), notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable), options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable),
effects: this.actor.effects, effects: this.actor.effects
config: game.system.rdd.config
} }
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes); RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
@ -52,7 +51,7 @@ export class RdDBaseActorSheet extends ActorSheet {
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires); this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
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 == TYPES.competencecreature) formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it)) .forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
return formData; return formData;
} }

View File

@ -1,8 +1,9 @@
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 { 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 { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDAudio } from "../rdd-audio.js"; import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js"; import { RdDConfirm } from "../rdd-confirm.js";
@ -31,10 +32,10 @@ export class RdDBaseActor extends Actor {
} }
static init() { static init() {
Hooks.on("preUpdateItem", (item, change, options, id) => RdDBaseActor.getParentActor(item)?.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) => RdDBaseActor.getParentActor(item)?.onCreateItem(item, options, id)); Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
Hooks.on("deleteItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.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) => actor.onUpdateActor(change, options, actorId)); Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(actor)?.onUpdateActor(change, options, actorId))
} }
static onSocketMessage(sockmsg) { static onSocketMessage(sockmsg) {
@ -81,10 +82,6 @@ export class RdDBaseActor extends Actor {
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; }; static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
static getParentActor(document) {
return document?.parent instanceof Actor ? document.parent : undefined
}
/** /**
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut: * Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
* compétences et monnaies. * compétences et monnaies.
@ -124,6 +121,7 @@ export class RdDBaseActor extends Actor {
return new ActorConstructor(docData, context); return new ActorConstructor(docData, context);
} }
} }
context.rdd = undefined
super(docData, context); super(docData, context);
} }
@ -207,11 +205,8 @@ 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 onDeleteItem(item, options, id) { } async onDeleteItem(item, options, id) { }
async onUpdateActor(update, options, actorId) { } async onUpdateActor(update, options, actorId) { }
async onTimeChanging(oldTimestamp, newTimestamp) { async onTimeChanging(oldTimestamp, newTimestamp) {
@ -220,7 +215,7 @@ export class RdDBaseActor extends Actor {
} }
async creerObjetParMJ(object) { async creerObjetParMJ(object) {
if (!Misc.isUniqueConnectedGM()) { if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({ RdDBaseActor.remoteActorCall({
tokenId: this.token?.id, tokenId: this.token?.id,
actorId: this.id, actorId: this.id,
@ -234,6 +229,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
async cleanupConteneurs() { async cleanupConteneurs() {
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this)) {
let updates = this.itemTypes['conteneur'] let updates = this.itemTypes['conteneur']
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0) .filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } }); .map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
@ -241,6 +237,7 @@ export class RdDBaseActor extends Actor {
await this.updateEmbeddedDocuments("Item", updates) await this.updateEmbeddedDocuments("Item", updates)
} }
} }
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getFortune() { getFortune() {
@ -270,6 +267,7 @@ export class RdDBaseActor extends Actor {
} }
let fortune = this.getFortune(); let fortune = this.getFortune();
console.log("payer", game.user.character, depense, fortune); console.log("payer", game.user.character, depense, fortune);
// TODO: passer en handlebars
let msg = ""; let msg = "";
if (fortune >= depense) { if (fortune >= depense) {
await Monnaie.optimiserFortune(this, fortune - depense); await Monnaie.optimiserFortune(this, fortune - depense);
@ -279,11 +277,10 @@ export class RdDBaseActor extends Actor {
msg = "Vous n'avez pas assez d'argent pour payer cette somme !"; msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
} }
let message = { ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: msg content: msg
}; })
ChatMessage.create(message);
} }
async depenserSols(sols) { async depenserSols(sols) {
@ -317,7 +314,7 @@ export class RdDBaseActor extends Actor {
RdDAudio.PlayContextAudio("argent"); // Petit son RdDAudio.PlayContextAudio("argent"); // Petit son
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.` content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
}); });
} }
@ -335,7 +332,7 @@ export class RdDBaseActor extends Actor {
ui.notifications.info("Inutile de se vendre à soi-même"); ui.notifications.info("Inutile de se vendre à soi-même");
return; return;
} }
if (!Misc.isUniqueConnectedGM()) { if (!Misc.isFirstConnectedGM()) {
RdDBaseActor.remoteActorCall({ RdDBaseActor.remoteActorCall({
actorId: achat.vendeurId ?? achat.acheteurId, actorId: achat.vendeurId ?? achat.acheteurId,
method: 'achatVente', method: 'achatVente',
@ -360,12 +357,9 @@ export class RdDBaseActor extends Actor {
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`); ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
return; return;
} }
await this.decrementerVente(vendeur, itemVendu, quantite, cout); await vendeur?.vendre(itemVendu, quantite, cout);
if (acheteur) { await acheteur?.acheter(itemVendu, quantite, cout, achat)
await acheteur.depenserSols(cout);
const createdItemId = await acheteur.creerQuantiteItem(itemVendu, quantite);
await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId);
}
if (cout > 0) { if (cout > 0) {
RdDAudio.PlayContextAudio("argent"); RdDAudio.PlayContextAudio("argent");
} }
@ -374,29 +368,31 @@ export class RdDBaseActor extends Actor {
ChatMessage.create({ ChatMessage.create({
user: achat.userId, user: achat.userId,
speaker: { alias: (acheteur ?? vendeur).name }, speaker: { alias: (acheteur ?? vendeur).name },
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(this),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem) content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
}); });
if (!achat.vente.quantiteIllimite) { if (!achat.vente.quantiteIllimite) {
if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) { if (achat.vente.nbLots <= achat.choix.nombreLots) {
ChatUtility.removeChatMessageId(achat.chatMessageIdVente); ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
} }
else if (achat.chatMessageIdVente) { else if (achat.chatMessageIdVente) {
achat.vente.properties = itemVendu.getProprietes(); await ChatVente.diminuerQuantiteAchatVente(achat.chatMessageIdVente, achat.choix.nombreLots)
achat.vente.quantiteNbLots -= achat.choix.nombreLots;
achat.vente.jsondata = JSON.stringify(achat.vente.item);
const messageVente = game.messages.get(achat.chatMessageIdVente);
messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', achat.vente) });
messageVente.render(true);
} }
} }
} }
async decrementerVente(vendeur, itemVendu, quantite, cout) { async vendre(item, quantite, cout) {
if (vendeur) { await this.ajouterSols(cout);
await vendeur.ajouterSols(cout); await this.decrementerQuantiteItem(item, quantite);
await vendeur.decrementerQuantiteItem(itemVendu, quantite); }
async acheter(item, quantite, cout, achat) {
await this.depenserSols(cout)
const createdItemId = await this.creerQuantiteItem(item, quantite)
if (achat.choix.consommer && item.type == 'nourritureboisson' && createdItemId != undefined) {
achat.choix.doses = achat.choix.nombreLots;
await this.consommerNourritureboisson(createdItemId, achat.choix, achat.vente.actingUserId);
} }
} }
@ -409,31 +405,28 @@ export class RdDBaseActor extends Actor {
return disponible == undefined || disponible >= quantiteDemande; return disponible == undefined || disponible >= quantiteDemande;
} }
async consommerNourritureAchetee(achat, vente, createdItemId) { async consommerNourritureboisson(itemId, choix, userId) { }
if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) {
achat.choix.doses = achat.choix.nombreLots;
await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId);
}
}
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) { async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
if (item.isService()) { if (item.isService()) {
return; return;
} }
const itemId = item.id;
let resteQuantite = (item.system.quantite ?? 1) - quantite; let resteQuantite = (item.system.quantite ?? 1) - quantite;
if (resteQuantite <= 0) { if (resteQuantite <= 0) {
if (options.supprimerSiZero) { if (options.supprimerSiZero) {
await this.deleteEmbeddedDocuments("Item", [item.id]); await this.deleteEmbeddedDocuments("Item", [item.id]);
} }
else { else {
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]); await this.updateEmbeddedDocuments("Item", [{ _id: itemId, 'system.quantite': 0 }]);
} }
if (resteQuantite < 0) { if (resteQuantite < 0) {
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`) ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
} }
} }
else if (resteQuantite > 0) { else if (resteQuantite > 0) {
const realItem = this.getItem(item.id)
realItem.update({ 'system.quantite': resteQuantite });
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]); await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
} }
} }
@ -445,7 +438,7 @@ export class RdDBaseActor extends Actor {
type: item.type, type: item.type,
img: item.img, img: item.img,
name: item.name, name: item.name,
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }) system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
}; };
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem); const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
const items = await this.createEmbeddedDocuments("Item", newItems); const items = await this.createEmbeddedDocuments("Item", newItems);
@ -546,7 +539,7 @@ export class RdDBaseActor extends Actor {
// Calculer le total actuel des contenus // Calculer le total actuel des contenus
const encContenu = dest.getEncContenu(); const encContenu = dest.getEncContenu();
const newEnc = moved.getEncTotal(); // Calculer le total actuel du nouvel objet const newEnc = moved.getEncTotal(); // Calculer le total actuel du nouvel objet
const placeDisponible = Math.roundDecimals(dest.system.capacite - encContenu - newEnc, 4) const placeDisponible = Misc.keepDecimals(dest.system.capacite - encContenu - newEnc, 4)
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet // Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
if (placeDisponible < 0) { if (placeDisponible < 0) {
@ -561,15 +554,15 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** Ajoute un item dans un conteneur, sur la base de leurs ID */ /** Ajoute un item dans un conteneur, sur la base de leurs ID */
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) { async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
if (!conteneur) { if (conteneur?.isConteneur()) {
// TODO: afficher
item.estContenu = false;
}
else if (conteneur.isConteneur()) {
item.estContenu = true; item.estContenu = true;
const nouveauContenu = [...conteneur.system.contenu, item.id]; const nouveauContenu = [...conteneur.system.contenu, item.id];
await conteneur.update({ 'system.contenu': nouveauContenu }); await conteneur.update({ 'system.contenu': nouveauContenu });
onAjouterDansConteneur(item.id, conteneur.id); onAjouterDansConteneur(item.id, conteneur.id)
}
else {
item.estContenu = false;
await conteneur?.update({ 'system.-=contenu': undefined })
} }
} }
@ -587,9 +580,14 @@ export class RdDBaseActor extends Actor {
if (item.estContenu) { if (item.estContenu) {
item.estContenu = undefined; item.estContenu = undefined;
} }
if (item.type == 'conteneur' && item.system.contenu.length > 0) { if (item.system.contenu != undefined) {
if (item.type == 'conteneur') {
corrections.push({ _id: item.id, 'system.contenu': [] }); corrections.push({ _id: item.id, 'system.contenu': [] });
} }
else {
corrections.push({ _id: item.id, 'system.-=contenu': undefined });
}
}
} }
if (corrections.length > 0) { if (corrections.length > 0) {
await this.updateEmbeddedDocuments('Item', corrections); await this.updateEmbeddedDocuments('Item', corrections);
@ -623,15 +621,21 @@ export class RdDBaseActor extends Actor {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** Supprime un item d'un conteneur, sur la base /**
* de leurs ID */ * Supprime un item d'un conteneur, sur la base de leurs ID
*/
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) { async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
if (conteneur?.isConteneur()) { if (conteneur) {
item.estContenu = false; if (conteneur.isConteneur()) {
const contenu = conteneur.system.contenu.filter(id => id != item.id); const contenu = conteneur.system.contenu.filter(id => id != item.id);
await conteneur.update({ 'system.contenu': contenu }); await conteneur.update({ 'system.contenu': contenu });
onEnleverDeConteneur(); onEnleverDeConteneur();
} }
else {
await conteneur.update({ 'system.-=contenu': undefined })
}
}
item.estContenu = false;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -697,9 +701,28 @@ export class RdDBaseActor extends Actor {
async actionPrincipale(item, onActionItem = async () => { }) { async actionPrincipale(item, onActionItem = async () => { }) {
switch (item.type) { switch (item.type) {
case TYPES.conteneur: return await item.sheet.render(true); case ITEM_TYPES.conteneur: return await item.sheet.render(true);
} }
return undefined return undefined
} }
async resetItemUse() { }
async incDecItemUse(itemId, inc = 1) { }
getItemUse(itemId) { return 0; }
async finDeRound(options = { terminer: false }) { }
isActorCombat() { return false }
getCaracInit(competence) { return 0 }
listActionsCombat() { return [] }
listActionsPossessions() {
return this.itemTypes[ITEM_TYPES.possession]
.map(p => {
return {
name: p.name,
action: 'possession',
system: {
competence: p.name,
possessionid: p.system.possessionid,
}
}
})
}
} }

View File

@ -1,4 +1,4 @@
import { DialogItemAchat } from "../dialog-item-achat.js"; import { DialogItemAchat } from "../achat-vente/dialog-item-achat.js";
import { RdDItem } from "../item.js"; import { RdDItem } from "../item.js";
import { RdDUtility } from "../rdd-utility.js"; import { RdDUtility } from "../rdd-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js"; import { RdDBaseActorSheet } from "./base-actor-sheet.js";
@ -15,7 +15,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
width: 600, height: 720, width: 600, height: 720,
tabs: [] tabs: []
}); }, { inplace: false })
} }
get title() { get title() {
if (this.actor.token && this.actor.token != this.actor.prototypeToken) { if (this.actor.token && this.actor.token != this.actor.prototypeToken) {

View File

@ -25,8 +25,7 @@ export class RdDCommerce extends RdDBaseActor {
} }
await super.depenserSols(cout) await super.depenserSols(cout)
} }
async consommerNourritureboisson(itemId, choix, userId) {
async consommerNourritureAchetee(achat, vente, createdItemId) {
// ne pas consommer pour un commerce // ne pas consommer pour un commerce
} }

View File

@ -12,7 +12,7 @@ export class RdDCreatureSheet extends RdDBaseActorSangSheet {
return foundry.utils.mergeObject(RdDBaseActorSangSheet.defaultOptions, { return foundry.utils.mergeObject(RdDBaseActorSangSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html",
width: 640, height: 720 width: 640, height: 720
}); }, { inplace: false })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -1,5 +1,5 @@
import { ENTITE_INCARNE } from "../constants.js"; import { ENTITE_INCARNE } from "../constants.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { STATUSES } from "../settings/status-effects.js"; import { STATUSES } from "../settings/status-effects.js";
import { RdDBaseActorSang } from "./base-actor-sang.js"; import { RdDBaseActorSang } from "./base-actor-sang.js";
@ -12,7 +12,7 @@ export class RdDCreature extends RdDBaseActorSang {
isCreature() { return true } isCreature() { return true }
canReceive(item) { canReceive(item) {
return item.type == TYPES.competencecreature || item.isInventaire(); return item.type == ITEM_TYPES.competencecreature || item.isInventaire();
} }
async remiseANeuf() { async remiseANeuf() {
@ -33,27 +33,4 @@ export class RdDCreature extends RdDBaseActorSang {
} }
} }
isEntiteAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = this.system.sante.resonnance
return (resonnance.actors.find(it => it == attacker.id))
}
return true
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = foundry.utils.duplicate(this.system.sante.resonnance);
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé
return;
}
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
} }

View File

@ -9,7 +9,7 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, { return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
width: 640, height: 720, width: 640, height: 720,
}); }, { inplace: false })
} }
async getData() { async getData() {
@ -54,6 +54,12 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
}); });
} }
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid)
await this.actor.setEntiteReveAccordee(dropActor)
super._onDropActor(event, dragData)
}
async deleteSubActeur(actorId) { async deleteSubActeur(actorId) {
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId); let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false }); await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });

View File

@ -1,5 +1,5 @@
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js"; import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js"; import { RdDEncaisser } from "../rdd-roll-encaisser.js";
import { STATUSES } from "../settings/status-effects.js"; import { STATUSES } from "../settings/status-effects.js";
@ -12,7 +12,7 @@ export class RdDEntite extends RdDBaseActorReve {
} }
canReceive(item) { canReceive(item) {
return item.type == TYPES.competencecreature return item.type == ITEM_TYPES.competencecreature
} }
isEntite(typeentite = []) { isEntite(typeentite = []) {
@ -29,7 +29,7 @@ export class RdDEntite extends RdDBaseActorReve {
getChance() { return this.getReve() } getChance() { return this.getReve() }
getDraconicOuPossession() { getDraconicOuPossession() {
return this.itemTypes[TYPES.competencecreature] return this.itemTypes[ITEM_TYPES.competencecreature]
.filter(it => it.system.categorie == 'possession') .filter(it => it.system.categorie == 'possession')
.sort(Misc.descending(it => it.system.niveau)) .sort(Misc.descending(it => it.system.niveau))
.find(it => true); .find(it => true);
@ -74,7 +74,7 @@ export class RdDEntite extends RdDBaseActorReve {
return [STATUSES.StatusComma].includes(effectId); return [STATUSES.StatusComma].includes(effectId);
} }
async onAppliquerJetEncaissement(encaissement, attacker) { async onAppliquerJetEncaissement(encaissement, attackerToken) {
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance); const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
foundry.utils.mergeObject(encaissement, { foundry.utils.mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue, resteEndurance: perteEndurance.newValue,
@ -91,20 +91,16 @@ export class RdDEntite extends RdDBaseActorReve {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async setEntiteReveAccordee(attacker) { async setEntiteReveAccordee(actor) {
if (this.isEntite([ENTITE_INCARNE])) { if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = foundry.utils.duplicate(this.system.sante.resonnance); if (this.system.sante.resonnance.actors.find(it => it == actor.id)) {
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé // déjà accordé
return; return
} }
resonnance.actors.push(attacker.id); await this.update({ "system.sante.resonnance.actors": [...this.system.sante.resonnance.actors, actor.id] })
await this.update({ "system.sante.resonnance": resonnance });
} }
else { else {
super.setEntiteReveAccordee(attacker) super.setEntiteReveAccordee(actor)
} }
} }
} }

View File

@ -0,0 +1,115 @@
import { RdDActorSheet } from "../../actor-sheet.js"
import { SYSTEM_RDD } from "../../constants.js";
import { Misc } from "../../misc.js";
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
import { ExportScriptarium } from "./export-scriptarium.js";
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
export class RdDActorExportSheet extends RdDActorSheet {
static async init() {
await loadTemplates([
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-compteur.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/fatigue.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs",
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs",
])
Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille simplifiée" })
}
static get defaultOptions() {
return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs",
width: 550,
showCompNiveauBase: false,
vueArchetype: false,
}, { inplace: false })
}
constructor(actor, options) {
super(actor, options)
}
async getData() {
const formData = await super.getData()
// Add any structured, precomputed list of data
formData.context = Mapping.prepareContext(this.actor)
formData.export = this.getMappingValues(formData.context, this.actor)
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
const legeres = this.actor.nbBlessuresLegeres()
const graves = this.actor.nbBlessuresGraves()
const critiques = this.actor.nbBlessuresCritiques()
formData.etat = {
surenc: this.actor.computeMalusSurEncombrement(),
fatigue: {
value: this.actor.getFatigueActuelle(),
max: this.actor.getFatigueMax(),
malus: this.actor.malusFatigue()
},
blessures: legeres + graves + critiques,
blessure: [legeres > 0, legeres > 1, legeres > 2, legeres > 3, legeres > 4, graves > 0, graves > 1, critiques > 0],
}
formData.options.exportScriptarium = OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM)
return formData
}
getMappingValues(context, actor) {
return Object.fromEntries(Mapping.getMapping().map(it => [it.column, {
colName: it.colName ?? it.column,
column: it.column,
rollClass: it.rollClass,
value: String(it.getter(actor, context))
}]))
}
getCompetences(categories) {
const competences = Mapping.getCompetencesCategorie(this.actor, categories)
if (competences.length == 0) {
return ''
}
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
const listByCategories = Object.values(byCategories)
.map(it => it.competencesParNiveau)
.map(byNiveau => {
const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending())
if (niveaux.length == 0) {
return undefined
}
const listCategorieByNiveau = niveaux.map(niveau => {
const list = byNiveau[niveau].sort(Misc.ascending(it => it.name))
return { niveau, list }
})
return Misc.concat(listCategorieByNiveau)
}).filter(it => it != undefined)
return Misc.concat(listByCategories)
}
activateListeners(html) {
super.activateListeners(html);
this.html.find('.click-blessure-remove').click(async event =>
await this.actor.supprimerBlessure({
gravite: this.html.find(event.currentTarget).data('gravite')
})
)
this.html.find('.click-blessure-add').click(async event =>
await this.actor.ajouterBlessure({
gravite: this.html.find(event.currentTarget).data('gravite')
// event.currentTarget.attributes['data-gravite'].value
})
)
this.html.find('.button-export').click(async event => {
ExportScriptarium.INSTANCE.exportActors([this.actor],
`${this.actor.uuid}-${this.actor.name}`
)
})
}
}

View File

@ -0,0 +1,78 @@
import { ACTOR_TYPES } from "../../item.js"
import { Misc } from "../../misc.js"
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js"
import { Mapping } from "./mapping.js"
const IMG_SCRIPTARIUM = '<img class="context-menu-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/scriptarium.svg">'
export class ExportScriptarium {
static init() {
ExportScriptarium.INSTANCE = new ExportScriptarium()
}
constructor() {
Hooks.on("getActorDirectoryFolderContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
Hooks.on("getActorDirectoryEntryContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
}
onActorDirectoryMenu(actorDirectory, menus) {
menus.push({
name: 'Export Personnages <i class="fa-regular fa-file-csv"></i>',
icon: IMG_SCRIPTARIUM,
condition: (target) => game.user.isGM &&
OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM) &&
this.$getActors(actorDirectory, target).length > 0,
callback: target => this.exportActors(this.$getActors(actorDirectory, target), this.$getTargetName(actorDirectory, target))
})
}
$getTargetName(actorDirectory, target) {
const li = target.closest(".directory-item")
const folderId = li.data("folderId")
const actorId = li.data("documentId")
return actorId
? game.actors.get(actorId).name
: actorDirectory.folders.find(it => it.id == folderId).name
}
$getActors(actorDirectory, target) {
const li = target.closest(".directory-item")
const folderId = li.data("folderId")
const actorId = li.data("documentId")
const actors = actorId
? [game.actors.get(actorId)]
: folderId
? actorDirectory.folders.find(it => it.id == folderId).contents
: []
return actors.filter(it => it.type == ACTOR_TYPES.personnage)
}
exportActors(actors, targetName) {
const eol = '\n\r'
const header = Misc.join(this.getHeaderLine(), ';')
const actorLines = actors.map(actor => Misc.join(this.getActorLine(actor), ';'))
const data = Misc.join([header, ...actorLines], eol)
const filename = `scriptarium-${targetName?.slugify()}.csv`;
saveDataToFile(data, "text/csv;charset=windows-1252", `${filename}`);
}
getHeaderLine() {
return Mapping.getColumns()
}
getActorLine(actor) {
const values = Mapping.getValues(actor)
return values
.map(it => this.$escapeQuotes(it))
.map(it => it.replaceAll("\n", " ").replaceAll("\r", ""))
}
$escapeQuotes(it) {
it = '' + it
if (it.includes('"') || it.includes(';')) {
return `"${it.replaceAll('"', '\\"')}"`
}
return it
}
}

View File

@ -0,0 +1,384 @@
import { Grammar } from "../../grammar.js"
import { RdDItemArme } from "../../item-arme.js"
import { RdDItemCompetence } from "../../item-competence.js"
import { RdDItemSort } from "../../item-sort.js"
import { ITEM_TYPES } from "../../item.js"
import { Misc } from "../../misc.js"
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
import { RdDBonus } from "../../rdd-bonus.js"
import { TMRType } from "../../tmr-utility.js"
export const CATEGORIES_COMPETENCES = [
"generale",
"particuliere",
"specialisee",
"connaissance",
]
export const CATEGORIES_DRACONIC = [
"draconic",
]
const CATEGORIES_COMBAT = [
"melee",
"tir",
"lancer"
]
const NIVEAU_BASE = {
"generale": -4,
"particuliere": -8,
"specialisee": -11,
"connaissance": -11,
"draconic": -11,
"melee": -6,
"tir": -8,
"lancer": -8,
}
class ColumnMappingFactory {
static createMappingArme(part, i) {
return { column: `arme_${part}_${i}`, getter: (actor, context) => Mapping.getArme(actor, context, part, i) }
}
static createMappingSort(part, i) {
return { column: `sort_${part}_${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) }
}
}
const NB_ARMES = 10
const NB_SORTS = 20
const TABLEAU_ARMES = [...Array(NB_ARMES).keys()]
const TABLEAU_SORTS = [...Array(NB_SORTS).keys()]
const MAPPING_BASE = [
{ column: "ID", colName: 'ID', getter: (actor, context) => actor.id },
{ column: "name", getter: (actor, context) => actor.name },
{ column: "metier", colName: 'Métier', getter: (actor, context) => actor.system.metier },
{ column: "biographie", colName: 'Biographie', getter: (actor, context) => actor.system.biographie },
{ column: "taille", getter: (actor, context) => actor.system.carac.taille.value },
{ column: "apparence", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.apparence.value },
{ column: "constitution", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.constitution.value },
{ column: "force", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.force.value },
{ column: "agilite", rollClass: 'roll-carac', colName: 'Agilité', getter: (actor, context) => actor.system.carac.agilite.value },
{ column: "dexterite", rollClass: 'roll-carac', colName: 'Dextérité', getter: (actor, context) => actor.system.carac.dexterite.value },
{ column: "vue", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.vue.value },
{ column: "ouie", rollClass: 'roll-carac', colName: 'Ouïe', getter: (actor, context) => actor.system.carac.ouie.value },
{ column: "odoratgout", rollClass: 'roll-carac', colName: 'Odo-goût', getter: (actor, context) => actor.system.carac.odoratgout.value },
{ column: "volonte", rollClass: 'roll-carac', colName: 'Volonté', getter: (actor, context) => actor.system.carac.volonte.value },
{ column: "intellect", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.intellect.value },
{ column: "empathie", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.empathie.value },
{ column: "reve", rollClass: 'roll-carac', colName: 'Rêve', getter: (actor, context) => actor.system.carac.reve.value },
{ column: "chance", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.chance.value },
{ column: "melee", rollClass: 'roll-carac', colName: 'Mêlée', getter: (actor, context) => actor.system.carac.melee.value },
{ column: "tir", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.tir.value },
{ column: "lancer", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.lancer.value },
{ column: "derobee", rollClass: 'roll-carac', colName: 'Dérobée', getter: (actor, context) => actor.system.carac.derobee.value },
{ column: "vie", getter: (actor, context) => actor.system.sante.vie.max },
{ column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max },
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.system.attributs.plusdom.value },
{ column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? actor.system.attributs.protection.value : '' },
{ column: "description", getter: (actor, context) => Mapping.getDescription(actor) },
{ column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) },
{ column: "protectionarmure", colName: 'Protection', getter: (actor, context) => Mapping.getProtectionArmure(actor, context) },
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
]
const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i))
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('niveau', i)))
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('init', i)))
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('dommages', i)))
const MAPPING_SORTS = TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('voie', i))
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('description', i)))
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('bonus', i)))
const MAPPING = MAPPING_BASE
.concat(MAPPING_ARMES)
.concat(MAPPING_SORTS)
export class Mapping {
static getMapping() {
return MAPPING
}
static getColumns() {
return MAPPING.map(it => it.column)
}
static getValues(actor) {
const context = Mapping.prepareContext(actor)
return MAPPING.map(it => it.getter(actor, context))
}
static getAsObject(actor) {
const context = Mapping.prepareContext(actor)
return Object.fromEntries(MAPPING.map(it => [it.column, {
colName: it.colName ?? it.column,
value: it.getter(actor, context)
}]))
}
static getValues(actor) {
const context = Mapping.prepareContext(actor)
return MAPPING.map(it => it.getter(actor, context))
}
static prepareContext(actor) {
return {
armes: Mapping.prepareArmes(actor),
armure: Mapping.prepareArmure(actor),
esquive: Mapping.prepareEsquive(actor),
sorts: Mapping.prepareSorts(actor)
}
}
static prepareArmes(actor) {
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
RdDItemArme.ajoutCorpsACorps(armes, actor)
return armes.map(arme => [
arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
!(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined]
.filter(it => it != undefined))
.reduce((a, b) => a.concat(b), [])
}
static prepareArme(actor, arme, maniement) {
const nameCompetenceArme = RdDItemArme.getCompetenceArme(arme, maniement)
const competence = actor.getCompetence(nameCompetenceArme)
if (RdDItemCompetence.isNiveauBase(competence)) {
return undefined
}
const categorie = Mapping.complementCategorie(arme, maniement)
const dommages = Mapping.dommagesArme(actor, arme, maniement)
return {
name: arme.name + categorie,
niveau: Misc.toSignedString(competence.system.niveau),
init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau,
dommages: dommages,
competence: competence,
arme: arme
}
}
static dommagesArme(actor, arme, maniement){
const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
switch(arme.system.mortalite) {
case 'non-mortel': return `(${dommages})`
case 'empoignade': return '-'
}
return dommages
}
static complementCategorie(arme, maniement) {
switch (maniement) {
case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : ''
case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : ''
}
return ''
}
static calculBaseInit(actor, categorie) {
const mapping = MAPPING_BASE.find(it => it.column == categorie)
if (mapping) {
switch (categorie) {
case 'melee':
case 'tir':
case 'lancer':
const caracteristique = Number(actor.system.carac[categorie].value)
return Math.floor(caracteristique / 2)
}
}
return 0
}
static prepareArmure(actor) {
const armures = actor.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
if (armures.length > 1) {
console.warn(`${actor.name} a équipé ${armures.length} armures, seule la première sera considérée`)
}
if (armures.length > 0) {
const armure = armures[0]
return {
name: armure.name,
protection: armure.system.protection,
malus: armure.system.malus ?? 0
}
}
return {
name: '',
protection: actor.system.attributs.protection.value,
malus: 0
}
}
static prepareEsquive(actor) {
const esquives = actor.getCompetences("Esquive")
if (esquives.length > 0) {
const esquive = esquives[0]
return {
name: esquive.name,
niveau: esquive.system.niveau,
competence: esquive
}
}
return undefined
}
static prepareSorts(actor) {
const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC)
.map(it => RdDItemSort.getVoieCode(it))
return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies))
.sort(Misc.ascending(it => `${it.voie} : ${it.description}`))
}
static prepareSort(sort, voies) {
return {
voie: RdDItemSort.getCodeDraconic(sort, voies),
description: Mapping.descriptionSort(sort),
bonus: Mapping.bonusCase(sort)
}
}
static descriptionSort(sort) {
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
const ptreve = Mapping.addSpaceToNonNumeric(sort.system.ptreve)
const diff = Mapping.addSpaceToNonNumeric(sort.system.difficulte)
return `${sort.name}${ptSeuil} (${caseTMR}) R${diff} r${ptreve}`
}
static addSpaceToNonNumeric(value) {
return Number.isNumeric(value) ? value : ' ' + Mapping.toVar(value)
}
static toVar(value) {
return value.replace('variable', 'var')
}
static bonusCase(sort) {
const list = RdDItemSort.bonuscaseStringToList(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
if (list.length > 0) {
const bonus = list[0]
return `+${bonus.bonus}% en ${bonus.case}`
}
return ''
}
static getDescription(actor) {
const sexe = actor.system.sexe
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 heure = actor.system.heure
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
const age = actor.system.age ? `${actor.system.age} ans` : undefined
const taille = actor.system.taille
const poids = actor.system.poids
const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined
const yeux = actor.system.yeux ? `yeux ${actor.system.yeux}` : undefined
const beaute = actor.system.beaute ? `beauté ${actor.system.beaute}` : undefined
const list = [race, hn, age, taille, poids, cheveux, yeux, beaute]
return Misc.join(list.filter(it => it), ', ')
}
static getArmure(actor, context) {
return context.armure?.name ?? ''
}
static getProtectionArmure(actor, context) {
const naturelle = Number(actor.system.attributs.protection.value)
if (context?.armure?.protection == undefined) {
return naturelle
}
if (Number.isNumeric(context?.armure?.protection)) {
return Number(context?.armure?.protection ?? 0) + naturelle
}
return context?.armure.protection + (naturelle > 0 ? `+${naturelle}` : '')
}
static getMalusArmure(actor, context) {
return context?.armure?.malus ?? 0
}
static getEsquive(context) {
if (context.esquive) {
return Misc.toSignedString(context.esquive.niveau)
}
return ''
}
static getEsquiveArmure(context) {
if (context.esquive) {
const niveau = context.esquive.niveau + context.armure.malus
return Misc.toSignedString(niveau)
}
return ''
}
static getCompetences(actor, categories) {
const competences = Mapping.getCompetencesCategorie(actor, categories)
if (competences.length == 0) {
return ''
}
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
const txtByCategories = Object.values(byCategories)
.map(it => it.competencesParNiveau)
.map(byNiveau => {
const niveaux = Object.keys(byNiveau)
.map(it => Number(it)).sort(Misc.ascending())
if (niveaux.length == 0) {
return ''
}
const txtCategorieByNiveau = niveaux.map(niveau => {
const names = Misc.join(byNiveau[niveau].map(it => it.name).sort(Misc.ascending()), ', ')
return names + ' ' + Misc.toSignedString(niveau)
})
const txtCategorie = Misc.join(txtCategorieByNiveau, ' / ')
return txtCategorie
}).filter(it => it != '')
return Misc.join(txtByCategories, ' / ')
}
static competencesByCategoriesByNiveau(competences, categories) {
return categories.map(c => {
return {
categorie: c,
competencesParNiveau: Misc.classify(
competences.filter(comp => comp.system.categorie == c),
comp => comp.system.niveau)
}
})
}
static getArme(actor, context, part, numero) {
if (numero < context.armes.length) {
return context.armes[numero][part] ?? ''
}
return ''
}
static getCompetencesCategorie(actor, categories) {
return actor.itemTypes[ITEM_TYPES.competence]
.filter(it => categories.includes(it.system.categorie))
.filter(it => !RdDItemCompetence.isNiveauBase(it))
}
static getSort(actor, context, part, numero) {
if (numero < context.sorts.length) {
return context.sorts[numero][part]
}
return ''
}
}

View File

@ -0,0 +1,188 @@
import { SHOW_DICE } from "../../constants.js";
import { Misc } from "../../misc.js";
import { RdDCarac } from "../../rdd-carac.js";
import { RdDDice } from "../../rdd-dice.js";
import { RdDNameGen } from "../../rdd-namegen.js";
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
const PATHS = [
'name',
'system.sexe',
'system.age',
'system.taille',
'system.poids',
'system.main',
'system.heure',
'system.cheveux',
'system.yeux'
]
const RANDOM_VALUES = {
'system.sexe': { 'masculin': 1, 'féminin': 1 },
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidectre': 6 },
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 },
'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
}
export class AppPersonnageAleatoire extends FormApplication {
static preloadHandlebars() {
loadTemplates([
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
])
}
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs",
title: "Génération aléatoire",
width: 'fit-content',
height: 'fit-content',
classes: ['app-personnage-aleatoire'],
popOut: true,
resizable: true
}, { inplace: false })
}
constructor(actor) {
super({})
this.actor = actor
this.current = foundry.utils.duplicate(actor)
this.checked = {
'name': false,
'system.sexe': true,
'system.age': true,
'system.taille': true,
'system.poids': true,
'system.main': true,
'system.heure': true,
'system.cheveux': true,
'system.yeux': true
}
}
async getData(options) {
return foundry.utils.mergeObject(await super.getData(options), {
actor: this.actor,
current: this.current,
checked: this.checked,
options: { isGM: game.user.isGM }
})
}
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("button.button-cancel").click(async event => await this.close())
this.html.find("button.button-apply").click(async event => await this.onApply())
this.html.find("input.current-value").change(async event => await this.onChange(event))
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
this.html.find("a.random").click(async event => await this.onRandom(event))
this.html.find("a.reset").click(async event => await this.onReset(event))
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
this.html.find("input.check-for-random").click(async event => await this.onCheckForRandom(event))
}
async _updateObject(event, formData) { }
async onApply() {
const updates = Object.fromEntries(
PATHS.filter(path => game.user.isGM || path != 'name')
.map(path => [path, this.current[path]])
)
await this.actor.update(updates)
await this.close()
}
getPath(selector) {
const fields = this.html.find(selector).parents("div.random-field:first")
return fields[0].attributes['data-path'].value
}
async onChange(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = event.currentTarget.value
}
async onRandom(event) {
const path = this.getPath(event.currentTarget)
await this.setRandom(path);
this.render()
}
async onReset(event) {
const path = this.getPath(event.currentTarget)
this.current[path] = this.actor[path]
await this.render()
}
async onCheckForRandom(event) {
const path = this.getPath(event.currentTarget)
this.checked[path] = event.currentTarget.checked
this.render()
}
async onRandomizeSelected() {
const paths = this.html.find("input.check-for-random:checked")
.parents("div.random-field")
.toArray()
.map(it => it.attributes['data-path'].value)
await Promise.all(paths.map(path => this.setRandom(path)))
this.render()
}
async setRandom(path) {
this.current[path] = await this.random(path);
}
async random(path) {
switch (path) {
case 'name':
return await RdDNameGen.generate()
case 'system.sexe':
case 'system.main':
case 'system.cheveux':
case 'system.yeux':
return await this.randomFromMap(RANDOM_VALUES[path])
case 'system.poids':
return await this.randomPoids()
case 'system.taille':
return await this.randomTaille()
case 'system.age':
return await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl')
case 'system.heure':
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
}
return 'unknown'
}
async randomFromMap(valuesMap) {
const max = Object.values(valuesMap).reduce(Misc.sum(), 0)
const total = await RdDDice.rollTotal(`1d${max}`)
let sum = 0
for (let entry of Object.entries(valuesMap)) {
sum = sum + entry[1]
if (sum >= total) {
return entry[0]
}
}
return Object.keys(valuesMap)[0]
}
async randomPoids() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const range = caracTaille.poidsMax - caracTaille.poidsMin + 1
const total = await RdDDice.rollTotal(`1d${range} + ${caracTaille.poidsMin}`)
return total + ' kg'
}
async randomTaille() {
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
const base = this.current.system.carac.taille.value * 2 + 60 + caracTaille.poidsMin
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
const cm = total % 100
const m = (total - cm) / 100
return `${m}m${cm}`
}
}

View File

@ -9,7 +9,7 @@ export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, { return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
width: 640, height: 720, width: 640, height: 720,
}); }, { inplace: false })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -0,0 +1,433 @@
/************************************************************************************/
import "./xregexp-all.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { RdDBaseActorReve } from "../actor/base-actor-reve.js";
/************************************************************************************/
// Some internal test strings
let statBlock01 = `+$16(/, baron de Sylvedire, né à lheure du
Roseau, 40 ans, 1m78, 65 kg, Beauté 13.
TAILLE
10
Mêlée
14
APPARENCE
13
Tir
11
CONSTITUTION
12
Lancer
11
FORCE
12
Dérobée
13
AGILITÉ
16
Vie
11
DEXTÉRITÉ
13
Endurance
25
VUE
10
+dom
0
OUÏE
11
Protection
2 ou 4
ODO-GOÛT
9
cuir souple
VOLONTÉ
14
ou cuir / métal
INTELLECT
9
EMPATHIE
11
RÊVE
13
CHANCE
10
niv
init
+dom
Épée dragonne
+5
12
+3
Hache de bataille
+6
13
+3
Bouclier moyen
+5
Dague mêlée
+4
11
+1
Corps à corps
+4
11
(0)
Esquive
+8
Escalade +4 / Saut +5 / Commerce +3 / Équitation
+6 / Chirurgie 0 / Survie en extérieur +4 / Survie fo-
rêt +6 / Acrobatie -2 / Métallurgie +2 / Natation +3 /
Légendes -1 / Écriture -4
`;
let statBlock02 = `/HVJDUGHV
TAILLE
11
Mêlée
12
CONSTITUTION
11
Tir
11
FORCE
12
Lancer
11
AGILITÉ
12
Dérobée
11
DEXTERITÉ
11
Vie
11
VUE
11
Endurance
22
OUÏE
11
Vitesse
12
VOLONTÉ
10
+dom
0
Protection
4
cuir / métal
niv
init
+dom
Hache de bataille
+4
10
+3
Bouclier moyen
+4
Dague mêlée
+3
9
+1
Arc
+5
10
+2
Corps à corps
+3
9
(0)
Esquive avec armure
+2
Course +1/ Vigilance +4
`;
let statBlock03 = `rencontres sont laissées à /HVFKLHQVORXSVGXEDURQ
chaque gardien des rêves.
TAILLE
8
Vie
10
CONSTITUTION FORCE
12
11
Endurance
Vitesse
12/38
21
/HVFKLHQV]RPELV
PERCEPTION 13
+dom
0
VOLONTÉ
10
Protection
0
Les « monstres » apparaîtront un soir, durant
RÊVE
10
lheure du Serpent, et attaqueront les voya-
niv
init
+dom
geurs à leur campement. Si ces derniers ne
Morsure
13
+4
10
+1
campent pas, ils apparaîtront tout de même à
Esquive
11
+3
lheure du Serpent. Le feu ne les effraie pas. Ils
Course, Saut
12
+3
ne sont pas très rapides, mais en revanche, très
Discrétion
12
+3
silencieux : ils naboient pas. Les voyageurs
Vigilance
13
+3
`
// Skill parser depending on the type of actor
const compParser = { personnage: "\\s+(?<value>[\\+\\-]?\\d+)", creature: "\\s+(?<carac>\\d+)\\s+(?<value>[\\+\\-]?\\d+)\\s?(?<init>\\d+)?\\s+?(?<dommages>\\+\\d+)?" };
// Main class for parsing a stat block
export class RdDStatBlockParser {
static openInputDialog() {
let dialog = new Dialog({
title: "Import de stats de PNJ/Créatures",
content: `
<div>
<p>Coller le texte de la stat ici</p>
<textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
</div>
`,
buttons: {
ok: {
label: "OK",
callback: async (html) => {
let statBlock = html.find("#statBlock")[0].value;
await RdDStatBlockParser.parseStatBlock(statBlock);
dialog.close();
}
},
cancel: {
label: "Cancel"
}
}
});
dialog.render(true);
}
static fixWeirdPDF(statString) {
// Split the statString into lines
let lines = statString.split("\n");
let newLines = [];
let index = 0;
let nextType = "string";
// Loop through each line
for (let i = 0; i < lines.length; i++) {
// remove trailing spaces
lines[i] = lines[i].trim();
// Is it text ?
if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
if ( nextType == "string" ) {
newLines[index] = lines[i];
nextType = "number";
} else {
console.log("Wrong sequence string detected...", lines[i], nextType);
}
}
// Is it a number ?
if (lines[i].match(/^[\d\s]+/)) {
if ( nextType == "number" ) {
newLines[index] = newLines[index] + lines[i];
nextType = "string";
index++;
} else {
console.log("Wrong sequence number detected...", lines[i], nextType);
}
}
}
}
static async parseStatBlock(statString, type = "npc") {
//statString = statBlock03;
if (!statString) {
return;
}
// Special function to fix strange/weird copy/paste from PDF readers
// Unused up to now : this.fixWeirdPDF(statString);
// Replace all endline by space in the statString
statString = statString.replace(/\n/g, " ");
// Remove all multiple spaces
statString = statString.replace(/\s{2,}/g, " ");
// Remove all leading and trailing spaces
statString = statString.trim();
let actorType = "personnage";
let perception = XRegExp.exec(statString.toLowerCase(), XRegExp("perception\\s+(?<value>\\d+)", 'gi'));
if (perception?.value ) {
actorType = "creature";
}
// Now start carac
let actorData = foundry.utils.deepClone(game.model.Actor[actorType]);
for (let key in game.model.Actor.personnage.carac) {
let caracDef = game.model.Actor.personnage.carac[key];
// Parse the stat string for each caracteristic
let carac = XRegExp.exec(statString.toLowerCase(), XRegExp(caracDef.label.toLowerCase()+"\\s+(?<value>\\d+)", 'gi'));
if (carac?.value) {
actorData.carac[key].value = Number(carac.value);
}
}
// If creature we need to setup additionnal fields
if (actorType == "creature") {
let plusDom = XRegExp.exec(statString.toLowerCase(), XRegExp("\\+dom\\s+(?<value>\\+\\d+)", 'gi'));
if (plusDom?.values) {
actorData.attributs.plusdom.value = Number(plusDom.value);
}
let protection = XRegExp.exec(statString.toLowerCase(), XRegExp("protection\\s+(?<value>\\d+)", 'gi'));
if (protection?.value) {
actorData.attributs.protection.value = Number(protection.value);
}
let endurance = XRegExp.exec(statString.toLowerCase(), XRegExp("endurance\\s+(?<value>\\d+)", 'gi'));
if (endurance?.value) {
actorData.sante.endurance.value = Number(endurance.value);
actorData.sante.endurance.max = Number(endurance.value);
}
let vie = XRegExp.exec(statString.toLowerCase(), XRegExp("vie\\s+(?<value>\\d+)", 'gi'));
if (vie.value) {
actorData.sante.vie.value = Number(vie.value);
actorData.sante.vie.max = Number(vie.value);
}
let vitesse = XRegExp.exec(statString.toLowerCase(), XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'gi'));
if (vitesse?.value) {
actorData.attributs.vitesse.value = vitesse.value;
}
}
let items = [];
// Get skills from compendium
const competences = await SystemCompendiums.getCompetences(actorType);
//console.log("Competences : ", competences);
let allComp = competences.map(i => i.toObject())
for (let comp of allComp) {
let skill = XRegExp.exec(statString.toLowerCase(), XRegExp(comp.name.toLowerCase()+compParser[actorType], 'gi'));
if (skill) {
comp.system.niveau = Number(skill.value);
if (actorType == "creature") {
comp.system.carac_value = Number(skill.carac);
if (skill.init) {
comp.system.dommages = Number(skill.dommages);
comp.system.iscombat = true;
}
items.push(comp); // Only selective push
}
}
if (actorType == "personnage") {
items.push(comp); // Always push
}
}
// Now process weapons
const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement")
//console.log("Equipement : ", equipment);
for (let w of weapons) {
let weapon = XRegExp.exec(statString.toLowerCase(), XRegExp(w.name.toLowerCase()+"\\s+(?<value>\\+\\d+)", 'gi'));
if (weapon) {
w.system.equipe = true
items.push(w.toObject());
// now process the skill
if ( w.system?.competence != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.competence.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
if ( w.system?.tir != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.tir.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
if ( w.system?.lancer != "") {
let wComp = items.find(i => i.name.toLowerCase() == w.system.lancer.toLowerCase());
if (wComp) {
wComp.system.niveau = Number(weapon.value);
}
}
}
}
// Now process armors
const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement")
for (let a of armors) {
let armor = XRegExp.exec(statString.toLowerCase(), XRegExp(a.name.toLowerCase(), 'gi'));
if (armor) {
a.system.equipe = true
items.push(a.toObject());
}
}
// Get hour name : heure du XXXXX
let heure = XRegExp.exec(statString.toLowerCase(), XRegExp("heure du\\s+(?<value>\\w+)", 'gi'));
if (heure?.value) {
actorData.heure = heure.value;
}
// Get age
let age = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) ans", 'gi'));
if (age?.value) {
actorData.age = Number(age.value);
}
// Get height
let taille = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+)m\\d+", 'gi'));
if (taille?.value) {
actorData.taille = taille.value;
}
// Get weight
let poids = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) kg", 'gi'));
if (poids?.value) {
actorData.poids = poids.value;
}
// Get beauty
let beaute = XRegExp.exec(statString.toLowerCase(), XRegExp("beauté\\s+(?<value>\\d+)", 'gi'));
if (beaute?.value) {
actorData.beaute = Number(beaute.value);
}
// Name is all string before ', né'
let name
if (actorType == "personnage") {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>[\\w\\s\\d]+),", 'gi'));
if (!name?.value) {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
}
name = name?.value || "Importé";
}
if (actorType == "creature") {
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
name = name?.value || "Importé";
}
let newActor = RdDBaseActorReve.create({name: name || "Importé", type:actorType, system: actorData, items: items});
// DUmp....
console.log(actorData);
}
}

8225
module/apps/xregexp-all.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,15 +8,20 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
*/ */
export class ChatUtility { export class ChatUtility {
static async init() {
Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg))
Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id))
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static onSocketMessage(sockmsg) { static onSocketMessage(sockmsg) {
switch (sockmsg.msg) { switch (sockmsg.msg) {
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data); case "msg_gm_chat_message": return ChatUtility.handleGMChatMessage(sockmsg.data)
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data); case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data)
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data)
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static notifyUser(userId, level = 'info', message) { static notifyUser(userId, level = 'info', message) {
const socketData = { const socketData = {
@ -44,7 +49,7 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static onRemoveMessages(socketData) { static onRemoveMessages(socketData) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
if (socketData.part) { if (socketData.part) {
const toDelete = game.messages.filter(it => it.content.includes(socketData.part)); const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
toDelete.forEach(it => it.delete()); toDelete.forEach(it => it.delete());
@ -58,7 +63,7 @@ export class ChatUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static removeMessages(socketData) { static removeMessages(socketData) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
ChatUtility.onRemoveMessages(socketData); ChatUtility.onRemoveMessages(socketData);
} }
else { else {
@ -78,85 +83,101 @@ export class ChatUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async createChatWithRollMode(name, chatOptions) { static async createChatWithRollMode(messageData, actor = undefined) {
let rollMode = game.settings.get("core", "rollMode") switch (game.settings.get("core", "rollMode")) {
switch (rollMode) {
case "blindroll": // GM only case "blindroll": // GM only
if (!game.user.isGM) { if (!game.user.isGM) {
ChatUtility.blindMessageToGM(chatOptions); ChatUtility.blindMessageToGM(messageData)
messageData.whisper = [game.user];
chatOptions.whisper = [game.user.id]; messageData.content = "Message envoyé en aveugle au Gardien"
chatOptions.content = "Message envoyé en aveugle au Gardien";
} }
else { else {
chatOptions.whisper = ChatUtility.getUsers(user => user.isGM); messageData.whisper = ChatUtility.getGMs()
} }
break; break
default: case "gmroll":
chatOptions.whisper = ChatUtility.getWhisperRecipients(rollMode, name); messageData.whisper = ChatUtility.getOwners(actor)
break; break
case "selfroll":
messageData.whisper = [game.user]
break
} }
chatOptions.alias = chatOptions.alias || name; messageData.alias = messageData.alias ?? actor?.name ?? game.user.name
return await ChatMessage.create(chatOptions); return await ChatMessage.create(messageData)
}
static getOwners(document) {
return game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
}
static getUserAndGMs() {
return [game.user, ...ChatUtility.getGMs()]
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static prepareChatMessage(rollMode, name) { static getMultipleActorsOwners(...actors) {
return { return Misc.concat(actors.map(it => it == undefined ? [] : ChatUtility.getOwners(it)))
user: game.user.id,
whisper: ChatUtility.getWhisperRecipients(rollMode, name)
}
}
/* -------------------------------------------- */
static getWhisperRecipients(rollMode, name) {
switch (rollMode) {
case "blindroll": return ChatUtility.getUsers(user => user.isGM);
case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name);
case "selfroll": return [game.user.id];
}
return undefined;
}
/* -------------------------------------------- */
static getWhisperRecipientsAndGMs(...names) {
let recipients = [...ChatMessage.getWhisperRecipients('GM')]
names.forEach(name => recipients.push(...ChatMessage.getWhisperRecipients(name)))
return recipients
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getUsers(filter) { static getUsers(filter) {
return game.users.filter(filter).map(user => user.id); return game.users.filter(filter)
}
static getGMs() {
return game.users.filter(user => user.isGM)
}
static applyRollMode(chatMessageData = {}, rollMode = game.settings.get("core", "rollMode")) {
switch (rollMode) {
case "blindroll":
chatMessageData.blind = true
chatMessageData.whisper = ChatUtility.getGMs()
break
case "gmroll":
chatMessageData.whisper = ChatUtility.getGMs()
chatMessageData.blind = false
break
case "roll":
chatMessageData.whisper = ChatUtility.getUsers(user => user.active)
chatMessageData.blind = false
break
case "selfroll":
chatMessageData.whisper = [game.user]
chatMessageData.blind = false
break
}
return chatMessageData
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static blindMessageToGM(chatOptions) { static blindMessageToGM(chatOptions) {
let chatGM = foundry.utils.duplicate(chatOptions); const chatGM = foundry.utils.duplicate(chatOptions)
chatGM.whisper = ChatUtility.getUsers(user => user.isGM); chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content; console.log("blindMessageToGM", chatGM)
console.log("blindMessageToGM", chatGM); game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM })
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static handleGMChatMessage(socketData) { static handleGMChatMessage(socketData) {
console.log("blindMessageToGM", socketData); console.log("blindMessageToGM", socketData);
if (game.user.isGM) { // message privé pour GM only if (Misc.isFirstConnectedGM()) {
socketData.user = game.user.id; ChatMessage.create({
ChatMessage.create(socketData); user: game.user.id,
whisper: ChatUtility.getGMs(),
content: socketData.content
})
} }
} }
static async setMessageData(chatMessage, key, flag) { static async setMessageData(chatMessage, key, flag) {
if (flag) { if (flag && chatMessage.isAuthor) {
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag)); await chatMessage.setFlag(SYSTEM_RDD, key, flag)
} }
} }
static getMessageData(chatMessage, key) { static getMessageData(chatMessage, key) {
const json = chatMessage.getFlag(SYSTEM_RDD, key); return chatMessage.getFlag(SYSTEM_RDD, key);
return json ? JSON.parse(json) : undefined;
} }
static getChatMessage(event) { static getChatMessage(event) {
@ -175,6 +196,8 @@ export class ChatUtility {
} }
static async onCreateChatMessage(chatMessage, options, id) { static async onCreateChatMessage(chatMessage, options, id) {
if (chatMessage.isAuthor) {
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp()); await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
} }
}
} }

View File

@ -30,7 +30,8 @@ export class RdDCoeur {
} }
static extractInfoCoeur(event) { static extractInfoCoeur(event) {
return ChatUtility.getMessageData(ChatUtility.getChatMessage(event), INFO_COEUR) const chatMesage = ChatUtility.getChatMessage(event);
return ChatUtility.getMessageData(chatMesage, INFO_COEUR)
} }
static getInfoCoeur(sourceActorId, targetActorId) { static getInfoCoeur(sourceActorId, targetActorId) {
@ -98,12 +99,11 @@ export class RdDCoeur {
static async startSubActeurTendreMoment(actorId, subActeurId) { static async startSubActeurTendreMoment(actorId, subActeurId) {
const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId) const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId)
if (infoCoeur.target?.actor.id) { if (infoCoeur.target?.actor?.id) {
// TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...) // TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...)
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
const chatMessage = await ChatMessage.create({ const chatMessage = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.target?.actor.name), whisper: ChatUtility.getOwners(infoCoeur.target.actor),
content: chatHtml content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
}) })
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage) RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
} }
@ -117,8 +117,8 @@ export class RdDCoeur {
} }
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId) ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate())).total
infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate())).total
const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre) const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre)
for (let amoureux of [infoCoeur.source, infoCoeur.target]) { for (let amoureux of [infoCoeur.source, infoCoeur.target]) {
const actorAmoureux = game.actors.get(amoureux.actor.id); const actorAmoureux = game.actors.get(amoureux.actor.id);
@ -127,7 +127,7 @@ export class RdDCoeur {
} }
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur) const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur)
const chatMessage = await ChatMessage.create({ const chatMessage = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name), whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
content: chatHtml content: chatHtml
}) })
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage) RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
@ -142,7 +142,7 @@ export class RdDCoeur {
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId) ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur) const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur)
await ChatMessage.create({ await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name), whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
content: chatHtml content: chatHtml
}); });
} }

View File

@ -29,5 +29,25 @@ export const RDD_CONFIG = {
"incarne": "Incarnée", "incarne": "Incarnée",
"nonincarne": "Non Incarnée", "nonincarne": "Non Incarnée",
"blurette": "Blurette" "blurette": "Blurette"
} },
heuresRdD : [
{value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"},
{value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"},
{value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"},
{value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"},
{value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"},
{value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"},
{value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"},
{value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"},
{value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"},
{value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"},
{value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"},
{value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"}
],
raretes: [
{value: "Commune", label: "Commune"},
{value: "Frequente", label: "Fréquente"},
{value: "Rare", label: "Rare"},
{value: "Rarissime", label: "Rarissime"}
]
} }

View File

@ -8,7 +8,7 @@ const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
export class DialogChronologie extends Dialog { export class DialogChronologie extends Dialog {
static init() { static initSettings() {
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, { game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
name: "Dernier article de journal utilisé pour enregistrer la chronologie", name: "Dernier article de journal utilisé pour enregistrer la chronologie",
scope: "client", scope: "client",

View File

@ -24,7 +24,7 @@ export class DialogCreateSigneDraconique extends Dialog {
} }
constructor(dialogData, html) { constructor(dialogData, html) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 }; let options = { classes: ["DialogCreateSigneDraconiqueActors"], width: 500, height: 650, 'z-index': 99999 };
let conf = { let conf = {
title: "Créer un signe", title: "Créer un signe",
content: html, content: html,
@ -48,7 +48,7 @@ export class DialogCreateSigneDraconique extends Dialog {
async _createSigneForActor(actor, signe) { async _createSigneForActor(actor, signe) {
actor.createEmbeddedDocuments("Item", [signe]); actor.createEmbeddedDocuments("Item", [signe]);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name), whisper: ChatUtility.getOwners(actor),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", { content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
signe: signe, signe: signe,
alias: actor.name alias: actor.name

View File

@ -8,14 +8,13 @@ import { RdDUtility } from "./rdd-utility.js";
export class DialogValidationEncaissement extends Dialog { export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, rollData, armure, onEncaisser) { static async validerEncaissement(actor, rollData, armure, onEncaisser) {
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE }); const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', { const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
actor: actor, actor: actor,
rollData: rollData, rollData: rollData,
encaissement: encaissement encaissement: encaissement
}); });
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser); new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
dialog.render(true);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -56,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog {
this.html = html; this.html = html;
this.html.find('input.encaissement-roll-result').keyup(async event => { this.html.find('input.encaissement-roll-result').keyup(async event => {
this.forceDiceResult.total = event.currentTarget.value; this.forceDiceResult.total = event.currentTarget.value;
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult}); this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
this.html.find('label.encaissement-total').text(this.encaissement.total); this.html.find('label.encaissement-total').text(this.encaissement.total);
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures) this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
}); });
} }
async onValider() { async onValider() {
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult}); this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement) this.onEncaisser(this.encaissement)
} }
} }

View File

@ -7,7 +7,7 @@ import { CompendiumTableHelpers, CompendiumTable, SystemCompendiums } from "./se
const COMPENDIUMS_RECHERCHE = 'compendiums-recherche'; const COMPENDIUMS_RECHERCHE = 'compendiums-recherche';
export class Environnement { export class Environnement {
static init() { static initSettings() {
game.settings.register(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, { game.settings.register(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, {
name: COMPENDIUMS_RECHERCHE, name: COMPENDIUMS_RECHERCHE,
default: [ default: [

View File

@ -1,5 +1,5 @@
import { RdDItemCompetenceCreature } from "./item-competencecreature.js" import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
const nomCategorieParade = { const nomCategorieParade = {
@ -20,19 +20,35 @@ const nomCategorieParade = {
export class RdDItemArme extends Item { export class RdDItemArme extends Item {
static isArme(item) { static isArme(item) {
return item.type == TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item); return item.type == ITEM_TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getArme(arme) { static getArme(arme) {
switch (arme ? arme.type : '') { switch (arme ? arme.type : '') {
case TYPES.arme: return arme; case ITEM_TYPES.arme: return arme;
case TYPES.competencecreature: case ITEM_TYPES.competencecreature:
return RdDItemCompetenceCreature.armeCreature(arme); return RdDItemCompetenceCreature.armeCreature(arme);
} }
return RdDItemArme.mainsNues(); return RdDItemArme.mainsNues();
} }
static getCompetenceArme(arme, maniement) {
switch (arme.type) {
case ITEM_TYPES.competencecreature:
return arme.name
case ITEM_TYPES.arme:
switch (maniement) {
case 'competence': return arme.system.competence;
case 'unemain': return RdDItemArme.competence1Mains(arme);
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
case 'tir': return arme.system.tir;
case 'lancer': return arme.system.lancer;
}
}
return undefined
}
static computeNiveauArmes(armes, competences) { static computeNiveauArmes(armes, competences) {
for (const arme of armes) { for (const arme of armes) {
arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences); arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
@ -65,37 +81,59 @@ export class RdDItemArme extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorieParade(armeData) { static getCategorieParade(armeData) {
if (armeData.system.categorie_parade) { if (armeData.system.categorie_parade) {
return armeData.system.categorie_parade; return armeData.system.categorie_parade
} }
// pour compatibilité avec des personnages existants // pour compatibilité avec des personnages existants
if (armeData.type == TYPES.competencecreature || armeData.system.categorie == 'creature') { if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : ''); return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
} }
if (!armeData.type.match(/arme|competencecreature/)) { if (!armeData.type.match(/arme|competencecreature/)) {
return ''; return ''
} }
if (armeData.system.competence == undefined) { if (armeData.system.competence == undefined) {
return TYPES.competencecreature; return ITEM_TYPES.competencecreature;
} }
let compname = armeData.system.competence.toLowerCase(); let compname = armeData.system.competence.toLowerCase();
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return ''; if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) {
return ''
}
if (compname.match('hache')) return 'haches'; if (compname.match('hache')) return 'haches'
if (compname.match('hast')) return 'hast'; if (compname.match('hast')) return 'hast'
if (compname.match('lance')) return 'lances'; if (compname.match('lance')) return 'lances'
if (compname.match('bouclier')) return 'boucliers'; if (compname.match('bouclier')) return 'boucliers'
if (compname.match('masse')) return 'masses'; if (compname.match('masse')) return 'masses'
if (compname.match('epée') || compname.match('épée')) { if (compname.match('epée') || compname.match('épée')) {
if (armeData.name.toLowerCase().match(/(gnome)/)) if (armeData.name.toLowerCase().match(/(gnome)/))
return 'epees-courtes'; return 'epees-courtes'
if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/)) if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/))
return 'epees-longues'; return 'epees-longues'
return 'epees-lourdes'; return 'epees-lourdes'
} }
if (compname.match('dague')) { if (compname.match('dague')) {
return 'dagues'; return 'dagues'
}
return 'sans-armes'
}
static defenseArmeParade(armeAttaque, armeParade) {
const defCategory = RdDItemArme.getCategorieParade(armeParade)
if (defCategory == 'bouclier') {
return 'norm'
}
if (armeAttaque.system.competence.toLowerCase().match(/(fléau)/)) {
return ''
}
if (armeParade.system.tir) {
return ''
}
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
switch (attCategory) {
case 'armes-naturelles': case 'sans-armes':
return defCategory == 'sans-armes' ? 'norm' : ''
default:
return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
} }
return 'sans-armes';
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -104,8 +142,8 @@ export class RdDItemArme extends Item {
return false; return false;
} }
// categories d'armes à la parade (cf. page 115 ) // categories d'armes à la parade (cf. page 115 )
let attCategory = RdDItemArme.getCategorieParade(armeAttaque); const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
let defCategory = RdDItemArme.getCategorieParade(armeParade); const defCategory = RdDItemArme.getCategorieParade(armeParade)
// bouclier et mêmes catégorie: peuvent se parer sans difficulté // bouclier et mêmes catégorie: peuvent se parer sans difficulté
if (defCategory == 'boucliers') { if (defCategory == 'boucliers') {
return false; return false;
@ -132,43 +170,66 @@ export class RdDItemArme extends Item {
return true; return true;
} }
static dommagesReels(arme, maniement) {
switch (maniement) {
case 'tir':
case 'lancer':
case 'competence':
return Number(arme.system.dommages)
}
if (arme.system.unemain && arme.system.deuxmains) {
const containsSlash = !Number.isInteger(arme.system.dommages) && arme.system.dommages.includes("/")
if (!containsSlash) {
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
return Number(arme.system.dommages)
}
const tableauDegats = arme.system.dommages.split("/");
return Number(tableauDegats[maniement == 'unemain' ? 0 : 1])
}
return Number(arme.system.dommages);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static armeUneOuDeuxMains(armeData, aUneMain) { static armeUneOuDeuxMains(arme, aUneMain) {
if (armeData && !armeData.system.cac) { if (arme && !arme.system.cac) {
armeData.system.unemain = armeData.system.unemain || !armeData.system.deuxmains; arme = foundry.utils.duplicate(arme);
const uneOuDeuxMains = armeData.system.unemain && armeData.system.deuxmains; arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? 'unemain' : 'deuxmains')
const containsSlash = !Number.isInteger(armeData.system.dommages) && armeData.system.dommages.includes("/");
if (containsSlash) { // Sanity check
armeData = foundry.utils.duplicate(armeData);
const tableauDegats = armeData.system.dommages.split("/");
if (aUneMain)
armeData.system.dommagesReels = Number(tableauDegats[0]);
else // 2 mains
armeData.system.dommagesReels = Number(tableauDegats[1]);
} }
else { return arme;
armeData.system.dommagesReels = Number(armeData.system.dommages);
}
if (uneOuDeuxMains != containsSlash) {
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)");
}
}
return armeData;
}
static competence2Mains(arme) {
return arme.system.competence.replace(" 1 main", " 2 mains");
} }
static competence1Mains(arme) { static competence1Mains(arme) {
return arme.system.competence.replace(" 2 mains", " 1 main"); return arme.system.competence.replace(" 2 mains", " 1 main");
} }
static isArmeUtilisable(arme) { static competence2Mains(arme) {
return arme.system.competence.replace(" 1 main", " 2 mains");
}
static isUtilisable(arme) {
switch (arme.type) { switch (arme.type) {
case TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0) case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case TYPES.competencecreature: return true case ITEM_TYPES.competencecreature: return true
}
return false
}
static isAttaque(arme) {
switch (arme.type) {
case ITEM_TYPES.arme:
return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case ITEM_TYPES.competencecreature:
return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
}
return false
}
static isParade(arme) {
switch (arme.type) {
case ITEM_TYPES.arme:
return arme.system.equipe && arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
case ITEM_TYPES.competencecreature:
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
} }
return false return false
} }
@ -180,11 +241,11 @@ export class RdDItemArme extends Item {
static corpsACorps(actor) { static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } }; let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } };
let melee = actor? actor.system.carac['melee'].value : 0 let melee = actor ? actor.system.carac['melee'].value : 0
return { return {
_id: competence?.id, _id: competence?.id,
name: 'Corps à corps', name: 'Corps à corps',
type: TYPES.arme, type: ITEM_TYPES.arme,
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp', img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
system: { system: {
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee), initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),

View File

@ -1,4 +1,5 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDItem } from "./item.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"], const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
@ -23,12 +24,12 @@ const limitesArchetypes = [
]; ];
/* -------------------------------------------- */ /* -------------------------------------------- */
const categoriesCompetences = { export const CATEGORIES_COMPETENCES = {
"generale": { base: -4, label: "Générales" }, "generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" }, "particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" }, "specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" }, "connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconics" }, "draconic": { base: -11, label: "Draconic" },
"melee": { base: -6, label: "Mêlée" }, "melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" }, "tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" } "lancer": { base: -8, label: "Lancer" }
@ -48,16 +49,14 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP(); const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item { export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static getCategories() {
return categoriesCompetences;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static getLabelCategorie(category) { static getLabelCategorie(category) {
return categoriesCompetences[category].label; return CATEGORIES_COMPETENCES[category].label;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getNiveauBase(category, categories = categoriesCompetences) { /* -------------------------------------------- */
static getNiveauBase(category, itemType) {
let categories = RdDItem.getCategories(itemType)
return categories[category]?.base ?? 0; return categories[category]?.base ?? 0;
} }
@ -191,7 +190,7 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isNiveauBase(item) { static isNiveauBase(item) {
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.getCategories()); return item.system.niveau == undefined || Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -199,7 +198,7 @@ export class RdDItemCompetence extends Item {
if (idOrName == undefined || idOrName == "") { if (idOrName == undefined || idOrName == "") {
return RdDItemCompetence.sansCompetence(); return RdDItemCompetence.sansCompetence();
} }
options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false }); options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false, inplace: false });
return RdDItemCompetence.findFirstItem(list, idOrName, options); return RdDItemCompetence.findFirstItem(list, idOrName, options);
} }

View File

@ -1,8 +1,8 @@
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
const categories = { export const CATEGORIES_COMPETENCES_CREATURES = {
"generale": { base: 0, label: "Générale" }, "generale": { base: 0, label: "Générale" },
"naturelle": { base: 0, label: "Arme naturelle" }, "naturelle": { base: 0, label: "Arme naturelle" },
"melee": { base: 0, label: "Mêlée" }, "melee": { base: 0, label: "Mêlée" },
@ -15,10 +15,6 @@ const categories = {
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemCompetenceCreature extends Item { export class RdDItemCompetenceCreature extends Item {
static getCategories() {
return categories;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static setRollDataCreature(rollData) { static setRollDataCreature(rollData) {
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } } rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
@ -31,32 +27,29 @@ export class RdDItemCompetenceCreature extends Item {
static armeCreature(item) { static armeCreature(item) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item) const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
if (categorieAttaque != undefined) { if (categorieAttaque != undefined) {
// si c'est un Item compétence: cloner pour ne pas modifier la compétence // cloner pour ne pas modifier la compétence
let arme = item.clone(); return foundry.utils.mergeObject(item, {
foundry.utils.mergeObject(arme,
{
action: item.isCompetencePossession() ? 'possession' : 'attaque', action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: { system: {
competence: arme.name, competence: item.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "", cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau, niveau: item.system.niveau,
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value), initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
equipe: true, equipe: true,
resistance: 100, resistance: 100,
dommagesReels: arme.system.dommages, dommagesReels: item.system.dommages,
penetration: 0, penetration: 0,
force: 0, force: 0,
rapide: true, rapide: true,
} }
}); }, { inplace: false, });
return arme;
} }
return undefined; return undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static isCompetenceAttaque(item) { static isAttaque(item) {
if (item.type == TYPES.competencecreature) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) { switch (item.system.categorie) {
case "melee": case "melee":
case "tir": case "tir":
@ -66,11 +59,11 @@ export class RdDItemCompetenceCreature extends Item {
return true return true
} }
} }
return undefined return false
} }
static getCategorieAttaque(item) { static getCategorieAttaque(item) {
if (item.type == TYPES.competencecreature) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) { switch (item.system.categorie) {
case "melee": case "melee":
case "tir": case "tir":
@ -83,8 +76,9 @@ export class RdDItemCompetenceCreature extends Item {
} }
return undefined return undefined
} }
static isDommages(item) { static isDommages(item) {
if (item.type == TYPES.competencecreature) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) { switch (item.system.categorie) {
case "melee": case "melee":
case "tir": case "tir":
@ -95,8 +89,9 @@ export class RdDItemCompetenceCreature extends Item {
} }
return false return false
} }
static isParade(item) { static isParade(item) {
if (item.type == TYPES.competencecreature) { if (item.type == ITEM_TYPES.competencecreature) {
switch (item.system.categorie) { switch (item.system.categorie) {
case "melee": case "melee":
case "naturelle": case "naturelle":
@ -107,8 +102,4 @@ export class RdDItemCompetenceCreature extends Item {
return false return false
} }
/* -------------------------------------------- */
static isCompetenceParade(item) {
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
}
} }

View File

@ -12,7 +12,7 @@ import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES, RdDItem } from "./item.js";
/** /**
* Extend the basic ItemSheet for RdD specific items * Extend the basic ItemSheet for RdD specific items
@ -44,7 +44,7 @@ export class RdDItemSheet extends ItemSheet {
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE), template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
width: 550, width: 550,
height: 550 height: 550
}); }, { inplace: false });
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -53,7 +53,8 @@ export class RdDItemSheet extends ItemSheet {
} }
get title() { get title() {
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`; const owner = (this.item.parent instanceof Actor) ? `(${this.item.parent.name})` : '';
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name} ${owner}`;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -98,18 +99,18 @@ export class RdDItemSheet extends ItemSheet {
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }), description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }), descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
isComestible: this.item.getUtilisationCuisine(), isComestible: this.item.getUtilisationCuisine(),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable) options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable),
} }
if (this.item.type == TYPES.competencecreature) { if (this.item.type == ITEM_TYPES.competencecreature) {
formData.isparade = RdDItemCompetenceCreature.isParade(this.item) formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item) formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
} }
const competences = await SystemCompendiums.getCompetences('personnage'); const competences = await SystemCompendiums.getCompetences('personnage');
formData.categories = this.item.getCategories() formData.categories = RdDItem.getCategories(this.item.type)
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') { if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
formData.caracList = foundry.utils.duplicate(game.system.model.Actor.personnage.carac) formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.system.model.Actor.personnage.reve.reve) formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
formData.competences = competences; formData.competences = competences;
} }
if (this.item.type == 'arme') { if (this.item.type == 'arme') {
@ -257,7 +258,7 @@ export class RdDItemSheet extends ItemSheet {
if (this.item.isCompetence()) { if (this.item.isCompetence()) {
const categorie = event.currentTarget.value; const categorie = event.currentTarget.value;
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.getCategories()); const level = RdDItemCompetence.getNiveauBase(categorie, this.item.type);
this.item.system.base = level; this.item.system.base = level;
this.html.find('[name="system.base"]').val(level); this.html.find('[name="system.base"]').val(level);
} }
@ -266,10 +267,17 @@ export class RdDItemSheet extends ItemSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) {
if (this.item.type == 'sort') { switch (this.item.type) {
case ITEM_TYPES.sort:
// Données de bonus de cases ? // Données de bonus de cases ?
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue); formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue)
break
case ITEM_TYPES.competence:
if (formData['system.niveau'] == undefined) {
formData['system.niveau'] = formData['system.base']
} }
}
return this.item.update(formData); return this.item.update(formData);
} }

View File

@ -1,9 +1,59 @@
import { Grammar } from "./grammar.js";
import { RdDItemCompetence } from "./item-competence.js";
import { ITEM_TYPES } from "./item.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
const VOIES_DRACONIC = [
{ code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' },
{ code: 'H', label: "Voie d'Hypnos", short: 'Hypnos', ordre: 'b' },
{ code: 'N', label: "Voie de Narcos", short: 'Narcos', ordre: 'c' },
{ code: 'T', label: "Voie de Thanatos", short: 'Thanatos', ordre: 'd' },
{ code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'Oniros/Hypnos/Narcos/Thanatos', ordre: 'e' },
{ code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "Oniros/Hypnos/Narcos", ordre: 'f' }
]
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItemSort extends Item { export class RdDItemSort extends Item {
static getDraconicsSort(draconicList, sort) {
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
case "lecture d'aura":
case "detection d'aura":
return draconicList;
case "annulation de magie":
return draconicList.filter(it => !RdDItemCompetence.isThanatos(it));
}
return [RdDItemCompetence.getVoieDraconic(draconicList, sort.system.draconic)];
}
static getOrdreCode(code) {
return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?')
}
static getVoieCode(voie) {
return VOIES_DRACONIC.find(it => voie.name.includes(it.short))?.code ?? '?'
}
static getCodeDraconic(sort, voies = ['O', 'H', 'N', 'T']) {
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
case "lecture d'aura":
case "detection d'aura":
return RdDItemSort.$voiesConnues('O/H/N/T', voies)
case "annulation de magie":
return RdDItemSort.$voiesConnues('O/H/N', voies)
}
const voie = VOIES_DRACONIC.find(it => it.label.includes(sort.system.draconic))
return voie?.code ?? sort.system.draconic
}
static $voiesConnues(voiesSort, voies) {
const codes = voies.filter(it => voiesSort.includes(it))
.sort(Misc.ascending(it => RdDItemSort.getOrdreCode(it)))
return Misc.join(codes ?? [''], '/');
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static isDifficulteVariable(sort) { static isDifficulteVariable(sort) {
return sort && (sort.system.difficulte.toLowerCase() == "variable"); return sort && (sort.system.difficulte.toLowerCase() == "variable");
@ -31,9 +81,9 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static buildBonusCaseList(bonuscase, newCase) { static buildBonusCaseList(bonuscase, newCase) {
const list = RdDItemSort._bonuscaseStringToList(bonuscase) const list = RdDItemSort.bonuscaseStringToList(bonuscase)
if (newCase) { if (newCase) {
return list.concat({ case: "Nouvelle", bonus: 0 }); list.push({ case: "Nouvelle", bonus: 0 })
} }
return list; return list;
} }
@ -44,7 +94,7 @@ export class RdDItemSort extends Item {
*/ */
static getBonusCaseList(item, newCase = false) { static getBonusCaseList(item, newCase = false) {
// Gestion spéciale case bonus // Gestion spéciale case bonus
if (item.type == 'sort') { if (item.type == ITEM_TYPES.sort) {
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase); return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
} }
return undefined; return undefined;
@ -104,8 +154,11 @@ export class RdDItemSort extends Item {
.sort(Misc.ascending()) .sort(Misc.ascending())
.join(','); .join(',');
} }
static _bonuscaseStringToList(bonuscase) { static bonuscaseStringToList(bonuscase) {
return (bonuscase ?? '').split(',').map(it => { if (bonuscase == undefined || bonuscase == '') {
return []
}
return bonuscase.split(',').map(it => {
const b = it.split(':'); const b = it.split(':');
return { case: b[0], bonus: b[1] }; return { case: b[0], bonus: b[1] };
}); });

View File

@ -1,4 +1,4 @@
import { DialogItemVente } from "./dialog-item-vente.js"; import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
@ -6,10 +6,18 @@ import { RdDTimestamp } from "./time/rdd-timestamp.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 { RdDRaretes } from "./item/raretes.js"; import { RdDRaretes } from "./item/raretes.js";
import { RdDItemCompetence } from "./item-competence.js"; import { CATEGORIES_COMPETENCES } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
export const TYPES = { export const ACTOR_TYPES = {
personnage: 'personnage',
creature: 'creature',
entite: 'entite',
commerce: 'commerce',
vehicule: 'vehicule'
}
export const ITEM_TYPES = {
competence: 'competence', competence: 'competence',
competencecreature: 'competencecreature', competencecreature: 'competencecreature',
empoignade: 'empoignade', empoignade: 'empoignade',
@ -56,33 +64,33 @@ export const TYPES = {
} }
const typesInventaireMateriel = [ const typesInventaireMateriel = [
TYPES.arme, ITEM_TYPES.arme,
TYPES.armure, ITEM_TYPES.armure,
TYPES.conteneur, ITEM_TYPES.conteneur,
TYPES.faune, ITEM_TYPES.faune,
TYPES.gemme, ITEM_TYPES.gemme,
TYPES.herbe, ITEM_TYPES.herbe,
TYPES.plante, ITEM_TYPES.plante,
TYPES.ingredient, ITEM_TYPES.ingredient,
TYPES.livre, ITEM_TYPES.livre,
TYPES.monnaie, ITEM_TYPES.monnaie,
TYPES.munition, ITEM_TYPES.munition,
TYPES.nourritureboisson, ITEM_TYPES.nourritureboisson,
TYPES.objet, ITEM_TYPES.objet,
TYPES.potion, ITEM_TYPES.potion,
] ]
const typesInventaire = { const typesInventaire = {
materiel: typesInventaireMateriel, materiel: typesInventaireMateriel,
all: ['service'].concat(typesInventaireMateriel), all: ['service'].concat(typesInventaireMateriel),
} }
const typesObjetsOeuvres = [TYPES.oeuvre, TYPES.recettecuisine, TYPES.musique, TYPES.chant, TYPES.danse, TYPES.jeu] const typesObjetsOeuvres = [ITEM_TYPES.oeuvre, ITEM_TYPES.recettecuisine, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.jeu]
const typesObjetsDraconiques = [TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.tete, TYPES.signedraconique, TYPES.sortreserve, TYPES.rencontre] const typesObjetsDraconiques = [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.tete, ITEM_TYPES.signedraconique, ITEM_TYPES.sortreserve, ITEM_TYPES.rencontre]
const typesObjetsConnaissance = [TYPES.meditation, TYPES.recettealchimique, TYPES.sort] const typesObjetsConnaissance = [ITEM_TYPES.meditation, ITEM_TYPES.recettealchimique, ITEM_TYPES.sort]
const typesObjetsEffet = [TYPES.possession, TYPES.poison, TYPES.maladie, TYPES.blessure] const typesObjetsEffet = [ITEM_TYPES.possession, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.blessure]
const typesObjetsCompetence = [TYPES.competence, TYPES.competencecreature] const typesObjetsCompetence = [ITEM_TYPES.competence, ITEM_TYPES.competencecreature]
const typesObjetsTemporels = [TYPES.blessure, TYPES.poison, TYPES.maladie, TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.signedraconique, TYPES.rencontre] const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.signedraconique, ITEM_TYPES.rencontre]
const typesObjetsEquipable = [TYPES.arme, TYPES.armure, TYPES.objet]; const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet];
const typesEnvironnement = typesInventaireMateriel; const typesEnvironnement = typesInventaireMateriel;
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
@ -141,12 +149,12 @@ export class RdDItem extends Item {
static isFieldInventaireModifiable(type, field) { static isFieldInventaireModifiable(type, field) {
switch (field) { switch (field) {
case 'quantite': case 'quantite':
if ([TYPES.conteneur].includes(type)) { if ([ITEM_TYPES.conteneur].includes(type)) {
return false; return false;
} }
break; break;
case 'cout': case 'cout':
if ([TYPES.monnaie].includes(type)) { if ([ITEM_TYPES.monnaie].includes(type)) {
return game.user.isGM; return game.user.isGM;
} }
break; break;
@ -164,9 +172,11 @@ export class RdDItem extends Item {
static getItemTypesInventaire(mode = 'materiel') { static getItemTypesInventaire(mode = 'materiel') {
return typesInventaire[mode ?? 'materiel'] return typesInventaire[mode ?? 'materiel']
} }
static getItemTypesDraconiques() { static getItemTypesDraconiques() {
return typesObjetsDraconiques; return typesObjetsDraconiques;
} }
static getItemTypesEnvironnement() { static getItemTypesEnvironnement() {
return typesEnvironnement; return typesEnvironnement;
} }
@ -175,6 +185,16 @@ export class RdDItem extends Item {
return typesObjetsOeuvres return typesObjetsOeuvres
} }
static getCategories(itemType) {
switch (itemType) {
case ITEM_TYPES.competence:
return CATEGORIES_COMPETENCES
case ITEM_TYPES.competencecreature:
return CATEGORIES_COMPETENCES_CREATURES
}
return {}
}
constructor(docData, context = {}) { constructor(docData, context = {}) {
if (!context.rdd?.ready) { if (!context.rdd?.ready) {
foundry.utils.mergeObject(context, { rdd: { ready: true } }); foundry.utils.mergeObject(context, { rdd: { ready: true } });
@ -189,20 +209,21 @@ export class RdDItem extends Item {
if (!docData.img) { if (!docData.img) {
docData.img = RdDItem.getDefaultImg(docData.type); docData.img = RdDItem.getDefaultImg(docData.type);
} }
context.rdd = undefined
super(docData, context); super(docData, context);
} }
getUniteQuantite() { getUniteQuantite() {
switch (this.type) { switch (this.type) {
case TYPES.monnaie: return "(Pièces)" case ITEM_TYPES.monnaie: return "(Pièces)"
case TYPES.herbe: case ITEM_TYPES.herbe:
switch (this.system.categorie) { switch (this.system.categorie) {
case 'Alchimie': case 'Repos': case 'Soin': case 'Alchimie': case 'Repos': case 'Soin':
return "(Brins)" return "(Brins)"
case 'Cuisine': return ''; case 'Cuisine': return '';
} }
return ''; return '';
case TYPES.ingredient: return "(Pépins ou Brins)" case ITEM_TYPES.ingredient: return "(Pépins ou Brins)"
} }
return ''; return '';
} }
@ -211,13 +232,13 @@ export class RdDItem extends Item {
return typesObjetsEquipable.includes(this.type) return typesObjetsEquipable.includes(this.type)
} }
isCompetencePersonnage() { return this.type == TYPES.competence } isCompetencePersonnage() { return this.type == ITEM_TYPES.competence }
isCompetenceCreature() { return this.type == TYPES.competencecreature } isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature }
isConteneur() { return this.type == TYPES.conteneur; } isConteneur() { return this.type == ITEM_TYPES.conteneur; }
isMonnaie() { return this.type == TYPES.monnaie; } isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
isPotion() { return this.type == TYPES.potion; } isPotion() { return this.type == ITEM_TYPES.potion; }
isNourritureBoisson() { return this.type == TYPES.nourritureboisson; } isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
isService() { return this.type == TYPES.service; } isService() { return this.type == ITEM_TYPES.service; }
isCompetence() { return typesObjetsCompetence.includes(this.type) } isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() { isEsquive() {
@ -233,33 +254,26 @@ export class RdDItem extends Item {
} }
isCompetenceArme() { isCompetenceArme() {
return this.isCompetence() && [ 'melee','tir', 'lancer'].includes(this.system.categorie) return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie)
} }
isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" } isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == "possession" }
isTemporel() { return typesObjetsTemporels.includes(this.type) } isTemporel() { return typesObjetsTemporels.includes(this.type) }
isOeuvre() { return typesObjetsOeuvres.includes(this.type) } isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) } isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
isQueueDragon() { return [TYPES.queue, TYPES.ombre].includes(this.type) } isQueueDragon() { return [ITEM_TYPES.queue, ITEM_TYPES.ombre].includes(this.type) }
isEffet() { return typesObjetsEffet.includes(this.type) } isEffet() { return typesObjetsEffet.includes(this.type) }
isConnaissance() { return typesObjetsConnaissance.includes(this.type) } isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); } isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; } isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; } isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
isHerbeAPotion() { return this.type == TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); } isHerbeAPotion() { return this.type == ITEM_TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
isBlessure() { return this.type == TYPES.blessure } isBlessure() { return this.type == ITEM_TYPES.blessure }
isPresentDansMilieux(milieux) { isPresentDansMilieux(milieux) {
return this.getEnvironnements(milieux).length > 0 return this.getEnvironnements(milieux).length > 0
} }
getCategories() {
switch (this.type) {
case TYPES.competence: return RdDItemCompetence.getCategories()
case TYPES.competencecreature: return RdDItemCompetenceCreature.getCategories()
}
return {}
}
getEnvironnements(milieux = undefined) { getEnvironnements(milieux = undefined) {
const environnements = this.isInventaire() ? this.system.environnement : undefined; const environnements = this.isInventaire() ? this.system.environnement : undefined;
@ -340,15 +354,15 @@ export class RdDItem extends Item {
getUtilisation() { getUtilisation() {
switch (this.type) { switch (this.type) {
case TYPES.potion: case ITEM_TYPES.potion:
switch (this.system.categorie) { switch (this.system.categorie) {
case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie' case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie'
case 'Cuisine': return 'cuisine' case 'Cuisine': return 'cuisine'
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins' case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins'
} }
return ''; return '';
case TYPES.nourritureboisson: return 'cuisine'; case ITEM_TYPES.nourritureboisson: return 'cuisine';
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante: case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
switch (this.system.categorie) { switch (this.system.categorie) {
case 'Cuisine': return 'cuisine'; case 'Cuisine': return 'cuisine';
case 'Toxique': case 'Poison': return 'poison'; case 'Toxique': case 'Poison': return 'poison';
@ -363,9 +377,9 @@ export class RdDItem extends Item {
getUtilisationCuisine() { getUtilisationCuisine() {
if (this.getUtilisation() == 'cuisine') { if (this.getUtilisation() == 'cuisine') {
switch (this.type) { switch (this.type) {
case TYPES.nourritureboisson: case ITEM_TYPES.nourritureboisson:
return 'pret'; return 'pret';
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante: case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
return 'brut'; return 'brut';
} }
} }
@ -373,7 +387,7 @@ export class RdDItem extends Item {
} }
isCristalAlchimique() { isCristalAlchimique() {
return this.type == TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0; return this.type == ITEM_TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
} }
isMagique() { isMagique() {
@ -401,11 +415,11 @@ export class RdDItem extends Item {
getEnc() { getEnc() {
switch (this.type) { switch (this.type) {
case TYPES.service: case ITEM_TYPES.service:
return 0; return 0;
case TYPES.herbe: case ITEM_TYPES.herbe:
return this.getEncHerbe(); return this.getEncHerbe();
case TYPES.gemme: case ITEM_TYPES.gemme:
return encPepin * this.system.taille; return encPepin * this.system.taille;
} }
return Math.max(this.system.encombrement ?? 0, 0); return Math.max(this.system.encombrement ?? 0, 0);
@ -483,7 +497,7 @@ export class RdDItem extends Item {
getActionPrincipale(options = { warnIfNot: true }) { getActionPrincipale(options = { warnIfNot: true }) {
switch (this.type) { switch (this.type) {
case TYPES.conteneur: return 'Ouvrir'; case ITEM_TYPES.conteneur: return 'Ouvrir';
} }
if (this.actor?.isPersonnage()) { if (this.actor?.isPersonnage()) {
const warn = options.warnIfNot; const warn = options.warnIfNot;
@ -491,11 +505,11 @@ export class RdDItem extends Item {
return 'Cuisiner'; return 'Cuisiner';
} }
switch (this.type) { switch (this.type) {
case TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn); case ITEM_TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
case TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn); case ITEM_TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn);
case TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn); case ITEM_TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
case TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined; case ITEM_TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
case TYPES.queue: case TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined; case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
} }
} }
return undefined; return undefined;
@ -538,7 +552,7 @@ export class RdDItem extends Item {
_id: this.id, _id: this.id,
'system.quantite': this.system.quantite * sust, 'system.quantite': this.system.quantite * sust,
'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2), 'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2),
'system.cout': Misc.keepDecimals(this.system.cout / sust, 2), 'system.cout': Math.max(0, Misc.keepDecimals(this.system.cout / sust, 2)),
'system.sust': 1 'system.sust': 1
}]) }])
} }
@ -621,23 +635,7 @@ export class RdDItem extends Item {
ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`); ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`);
return; return;
} }
await DialogItemVente.display({ await DialogItemVente.display({ item: this, quantiteMax })
item: this,
quantiteMax,
callback: async (vente) => {
vente["properties"] = this.getProprietes();
if (vente.isOwned) {
if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) {
ui.notifications.warn(`Vous avez ${vente.quantiteMax} ${vente.item.name}, ce n'est pas suffisant pour vendre ${vente.quantiteNbLots} de ${vente.tailleLot}`)
return;
}
}
vente.jsondata = JSON.stringify(vente.item);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
ChatMessage.create(RdDUtility.chatDataSetup(html));
}
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -39,7 +39,7 @@ export class RdDItemBlessure extends RdDItem {
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`) ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
return undefined; return undefined;
} }
return foundry.utils.mergeObject(foundry.utils.duplicate(BASE_TACHE_SOIN_BLESSURE), tache) return foundry.utils.mergeObject(BASE_TACHE_SOIN_BLESSURE, tache, { inplace: false })
} }
static async applyFullBlessure(actor, gravite) { static async applyFullBlessure(actor, gravite) {
@ -48,7 +48,7 @@ export class RdDItemBlessure extends RdDItem {
let lostEndurance = 0 let lostEndurance = 0
let lostVie = 0 let lostVie = 0
if (definition.endurance) { if (definition.endurance) {
lostEndurance = new Roll(definition.endurance).roll({async: false}).total; lostEndurance = await new Roll(definition.endurance).roll().total;
actor.santeIncDec("endurance", -Number(lostEndurance)); actor.santeIncDec("endurance", -Number(lostEndurance));
} }
if (definition.vie) { if (definition.vie) {
@ -62,12 +62,12 @@ export class RdDItemBlessure extends RdDItem {
content: `Blessure ${definition.label} appliquée à ${actor.name}`+ content: `Blessure ${definition.label} appliquée à ${actor.name}`+
`<br>Perte d'endurance : ${lostEndurance}`+ `<br>Perte d'endurance : ${lostEndurance}`+
`<br>Perte de Vie : ${lostVie}`, `<br>Perte de Vie : ${lostVie}`,
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name) whisper: ChatUtility.getOwners(actor)
}); });
} }
static async createBlessure(actor, gravite, localisation = '', attacker) { static async createBlessure(actor, gravite, localisation = '', attackerToken) {
const definition = RdDItemBlessure.getDefinition(gravite) const definition = RdDItemBlessure.getDefinition(gravite)
const blessure = { const blessure = {
name: definition.label, name: definition.label,
@ -77,7 +77,7 @@ export class RdDItemBlessure extends RdDItem {
gravite: gravite, gravite: gravite,
difficulte: - gravite, difficulte: - gravite,
localisation: localisation, localisation: localisation,
origine: attacker?.name ?? "" origine: attackerToken?.name ?? ""
} }
} }
const blessures = await actor.createEmbeddedDocuments('Item', [blessure]) const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
@ -106,12 +106,12 @@ export class RdDItemBlessure extends RdDItem {
} }
async setSoinsBlessure(systemUpdate = {}) { async setSoinsBlessure(systemUpdate = {}) {
systemUpdate = foundry.utils.mergeObject(systemUpdate, this.system, { overwrite: false }), systemUpdate = foundry.utils.mergeObject(systemUpdate, this.system, { overwrite: false })
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
await this.update({ await this.update({
img: this.getImgSoins(systemUpdate.gravite, systemUpdate.soinscomplets.done), img: this.getImgSoins(systemUpdate.gravite, systemUpdate.soinscomplets.done),
system: systemUpdate system: systemUpdate
}); })
} }
async recuperationBlessure({ actor, timestamp, message, isMaladeEmpoisonne, blessures }) { async recuperationBlessure({ actor, timestamp, message, isMaladeEmpoisonne, blessures }) {

View File

@ -1,3 +1,4 @@
import { ChatUtility } from "../chat-utility.js";
import { RdDItem } from "../item.js"; import { RdDItem } from "../item.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js"; import { RdDTimestamp } from "../time/rdd-timestamp.js";
@ -21,9 +22,12 @@ export class RdDItemMaladie extends RdDItem {
const souffrance = mal.system.identifie const souffrance = mal.system.identifie
? `de ${mal.name}` ? `de ${mal.name}`
: `d'un mal inconnu` : `d'un mal inconnu`
ChatMessage.create({ content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !` }); ChatMessage.create({
mal.postItemToChat('gmroll'); whisper: ChatUtility.getOwners(mal.actor),
await RdDItemMaladie.prolongerPeriode(mal,oldTimestamp, newTimestamp); content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !`
})
mal.postItemToChat('gmroll')
await RdDItemMaladie.prolongerPeriode(mal, oldTimestamp, newTimestamp)
} }
} }

View File

@ -10,7 +10,7 @@ export class RdDItemInventaireSheet extends RdDItemSheet {
static get defaultOptions() { static get defaultOptions() {
return foundry.utils.mergeObject(RdDItemSheet.defaultOptions, { return foundry.utils.mergeObject(RdDItemSheet.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }] tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
}); }, { inplace: false })
} }
setPosition(options = {}) { setPosition(options = {}) {
@ -23,9 +23,10 @@ export class RdDItemInventaireSheet extends RdDItemSheet {
async getData() { async getData() {
const formData = await super.getData(); const formData = await super.getData();
return foundry.utils.mergeObject(formData, { foundry.utils.mergeObject(formData, {
milieux: await game.system.rdd.environnement.autresMilieux(this.item) milieux: await game.system.rdd.environnement.autresMilieux(this.item)
}); })
return formData
} }
activateListeners(html) { activateListeners(html) {

View File

@ -8,7 +8,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
static get defaultOptions() { static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, { return foundry.utils.mergeObject(super.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }] tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
}); }, { inplace: false })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -35,7 +35,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
select: RdDRencontre.mapEffets(this.item.system.echec.effets) select: RdDRencontre.mapEffets(this.item.system.echec.effets)
} }
} }
}); })
return formData; return formData;
} }

View File

@ -2,7 +2,7 @@ import { RdDBaseActor } from "./actor/base-actor.js";
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; import { LOG_HEAD, SYSTEM_RDD } 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 { RdDItem, TYPES } from "./item.js"; import { RdDItem, ITEM_TYPES } from "./item.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js"; import { RdDRaretes } from "./item/raretes.js";
import { RdDCalendrier } from "./time/rdd-calendrier.js"; import { RdDCalendrier } from "./time/rdd-calendrier.js";
@ -465,7 +465,7 @@ class _10_7_19_CategorieCompetenceCreature extends Migration {
async migrate() { async migrate() {
await this.applyItemsUpdates(items => items await this.applyItemsUpdates(items => items
.filter(it => TYPES.competencecreature == it.type) .filter(it => ITEM_TYPES.competencecreature == it.type)
.map(it => this.migrateCompetenceCreature(it)) .map(it => this.migrateCompetenceCreature(it))
); );
} }
@ -502,7 +502,7 @@ class _10_7_19_PossessionsEntiteVictime extends Migration {
async migrate() { async migrate() {
await this.applyItemsUpdates(items => items await this.applyItemsUpdates(items => items
.filter(it => TYPES.possession == it.type) .filter(it => ITEM_TYPES.possession == it.type)
.map(it => this.migratePossession(it)) .map(it => this.migratePossession(it))
); );
} }
@ -567,9 +567,9 @@ export class Migrations {
if (currentVersion.startsWith("v")) { if (currentVersion.startsWith("v")) {
currentVersion = currentVersion.substring(1) currentVersion = currentVersion.substring(1)
} }
if (isNewerVersion(game.system.version, currentVersion)) { if (foundry.utils.isNewerVersion(game.system.version, currentVersion)) {
// if (true) { /* comment previous and uncomment here to test before upgrade */ // if (true) { /* comment previous and uncomment here to test before upgrade */
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion)); const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion));
if (migrations.length > 0) { if (migrations.length > 0) {
migrations.sort((a, b) => this.compareVersions(a, b)); migrations.sort((a, b) => this.compareVersions(a, b));
migrations.forEach(async (m) => { migrations.forEach(async (m) => {

View File

@ -139,7 +139,7 @@ export class Misc {
} }
static join(params, separator = '') { static join(params, separator = '') {
return params?.reduce(Misc.joining(separator)) ?? ''; return (!params || params.length == 0) ? '' : params.reduce(Misc.joining(separator))
} }
static joining(separator = '') { static joining(separator = '') {
@ -166,22 +166,54 @@ export class Misc {
} }
static firstConnectedGM() { static firstConnectedGM() {
return game.users.filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active); if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
return game.users.activeGM
}
return game.users.find(u => u.isGM && u.active);
} }
static isOwnerPlayer(actor, user = undefined) { static connectedGMs() {
return actor.testUserPermission(user ?? game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER) return game.users.filter(u => u.isGM && u.active);
} }
static isOwnerPlayerOrUniqueConnectedGM(actor, user = undefined) { /**
return Misc.isOwnerPlayer(actor, user) ?? Misc.isUniqueConnectedGM(); * This helper method allows to get the docuument, for a single user (either first connected GM, or the owner
* if there is no connected GMs), or else return undefined.
*
* This allows for example update hooks that should apply modifications to actors to be called only for one
* user (preventing the "User ... lacks permission to update Item" that was occuring on hooks when Item updates
* were triggering other changes)
*
* @param {*} document the Document with is potentially an Actor
* @returns the actor if either the game.user is the first connected GM, or if the game.user is the owner
* and there is no connected GM
*/
static documentIfResponsible(document) {
if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
if (game.users.activeGM || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document)))
{
return document
}
}
else if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) {
return document
}
return undefined
}
static isOwnerPlayer(document) {
return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
}
static isOwnerPlayerOrUniqueConnectedGM(actor) {
return Misc.isOwnerPlayer(actor) ?? Misc.isFirstConnectedGM();
} }
/** /**
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id * @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
*/ */
static isUniqueConnectedGM() { static isFirstConnectedGM() {
return game.user.id == Misc.firstConnectedGMId(); return game.user == Misc.firstConnectedGM();
} }
static firstConnectedGMId() { static firstConnectedGMId() {

View File

@ -15,7 +15,7 @@ export class RdDAudio {
if ( audioData ) { if ( audioData ) {
let audioPath = "systems/foundryvtt-reve-de-dragon/sounds/" + audioData.file; let audioPath = "systems/foundryvtt-reve-de-dragon/sounds/" + audioData.file;
console.log(`foundryvtt-reve-de-dragon | Playing Sound: ${audioPath}`) console.log(`foundryvtt-reve-de-dragon | Playing Sound: ${audioPath}`)
AudioHelper.play({ src: audioPath }, audioData.isGlobal); foundry.audio.AudioHelper.play({ src: audioPath }, audioData.isGlobal);
} }
} }
} }

View File

@ -31,8 +31,8 @@ export class RdDBonus {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static dmg(rollData, dmgActor, isEntiteIncarnee = false) { static dmg(rollData, actor, isEntiteIncarnee = false) {
const dmgArme = RdDBonus._dmgArme(rollData) const dmgArme = RdDBonus.dmgArme(rollData.arme)
let dmg = { let dmg = {
total: 0, total: 0,
dmgArme: dmgArme, dmgArme: dmgArme,
@ -41,7 +41,7 @@ export class RdDBonus {
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._dmgPerso(dmgActor, rollData.selectedCarac?.label, dmgArme) dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
} }
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere; dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
return dmg; return dmg;
@ -71,11 +71,11 @@ export class RdDBonus {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _dmgArme(rollData) { static dmgArme(arme) {
if (rollData.arme) { if (arme) {
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0); let dmgBase = arme.system.dommagesReels ?? Number(arme.system.dommages ?? 0);
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278) //Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0); return dmgBase + Math.min(dmgBase, arme.system.magique ? arme.system.ecaille_efficacite : 0);
} }
return 0; return 0;
} }
@ -86,13 +86,14 @@ export class RdDBonus {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _dmgPerso(dmgActor, categorie, dmgArme) { static bonusDmg(actor, categorie, dmgArme) {
const dmgActor = actor.getBonusDegat()
if (categorie == undefined) { if (categorie == undefined) {
return 0 return 0
} }
switch (categorie) { switch (categorie) {
case "Tir": return 0; case "tir": return 0;
case "Lancer": return Math.max(0, Math.min(dmgArme, dmgActor)); case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
} }
return dmgActor; return dmgActor;
} }

View File

@ -3,38 +3,38 @@ import { Misc } from "./misc.js";
const TABLE_CARACTERISTIQUES_DERIVEES = { const TABLE_CARACTERISTIQUES_DERIVEES = {
// xp: coût pour passer du niveau inférieur à ce niveau // xp: coût pour passer du niveau inférieur à ce niveau
1: { xp: 3, poids: "moins de 1kg", plusdom: -5, sconst: 0.5, sust: 0.1 }, 1: { xp: 3, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
2: { xp: 3, poids: "1-5", plusdom: -4, sconst: 0.5, sust: 0.3 }, 2: { xp: 3, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
3: { xp: 4, poids: "6-10", plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' }, 3: { xp: 4, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
4: { xp: 4, poids: "11-20", plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' }, 4: { xp: 4, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
5: { xp: 5, poids: "21-30", plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' }, 5: { xp: 5, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
6: { xp: 5, poids: "31-40", plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' }, 6: { xp: 5, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
7: { xp: 6, poids: "41-50", plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' }, 7: { xp: 6, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
8: { xp: 6, poids: "51-60", plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' }, 8: { xp: 6, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
9: { xp: 7, poids: "61-65", plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' }, 9: { xp: 7, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
10: { xp: 7, poids: "66-70", plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' }, 10: { xp: 7, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
11: { xp: 8, poids: "71-75", plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' }, 11: { xp: 8, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
12: { xp: 8, poids: "76-80", plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' }, 12: { xp: 8, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
13: { xp: 9, poids: "81-90", plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' }, 13: { xp: 9, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
14: { xp: 9, poids: "91-100", plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' }, 14: { xp: 9, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
15: { xp: 10, poids: "101-110", plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' }, 15: { xp: 10, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
16: { xp: 20, poids: "111-120", plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' }, 16: { xp: 20, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
17: { xp: 30, poids: "121-131", plusdom: +3, sconst: 5, sust: 5 }, 17: { xp: 30, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
18: { xp: 40, poids: "131-141", plusdom: +4, sconst: 6, sust: 5 }, 18: { xp: 40, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
19: { xp: 50, poids: "141-150", plusdom: +4, sconst: 6, sust: 5 }, 19: { xp: 50, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
20: { xp: 60, poids: "151-160", plusdom: +4, sconst: 6, sust: 6 }, 20: { xp: 60, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
21: { xp: 70, poids: "161-180", plusdom: +5, sconst: 7, sust: 6 }, 21: { xp: 70, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
22: { xp: 80, poids: "181-200", plusdom: +5, sconst: 7, sust: 7 }, 22: { xp: 80, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
23: { xp: 90, poids: "201-300", plusdom: +6, sconst: 7, sust: 8 }, 23: { xp: 90, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
24: { xp: 100, poids: "301-400", plusdom: +6, sconst: 8, sust: 9 }, 24: { xp: 100, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
25: { xp: 110, poids: "401-500", plusdom: +7, sconst: 8, sust: 10 }, 25: { xp: 110, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
26: { xp: 120, poids: "501-600", plusdom: +7, sconst: 8, sust: 11 }, 26: { xp: 120, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
27: { xp: 130, poids: "601-700", plusdom: +8, sconst: 9, sust: 12 }, 27: { xp: 130, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
28: { xp: 140, poids: "701-800", plusdom: +8, sconst: 9, sust: 13 }, 28: { xp: 140, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
29: { xp: 150, poids: "801-900", plusdom: +9, sconst: 9, sust: 14 }, 29: { xp: 150, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
30: { xp: 160, poids: "901-1000", plusdom: +9, sconst: 10, sust: 15 }, 30: { xp: 160, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
31: { xp: 170, poids: "1001-1500", plusdom: +10, sconst: 10, sust: 16 }, 31: { xp: 170, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
32: { xp: 180, poids: "1501-2000", plusdom: +11, sconst: 10, sust: 17 } 32: { xp: 180, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
}; };
export class RdDCarac { export class RdDCarac {

View File

@ -42,7 +42,8 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */ /* -------------------------------------------- */
Hooks.on("getCombatTrackerEntryContext", (html, options) => { RdDCombatManager.pushInitiativeOptions(html, options); }); Hooks.on("getCombatTrackerEntryContext", (html, options) => { RdDCombatManager.pushInitiativeOptions(html, options); });
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) }); Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() }); Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() })
Hooks.on("deleteCombat", (combat, html, id) => { combat.onDeleteCombat() })
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -53,83 +54,81 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async onPreDeleteCombat() { async onPreDeleteCombat() {
if (Misc.isUniqueConnectedGM()) { 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, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
.forEach(it => it.delete()); .forEach(it => it.delete())
RdDEmpoignade.deleteAllEmpoignades() RdDEmpoignade.deleteAllEmpoignades()
} }
} }
async onDeleteCombat() {
if (Misc.isFirstConnectedGM()) {
if (game.combats.size <= 1) {
game.actors.forEach(actor => actor.resetItemUse())
}
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async finDeRound(options = { terminer: false }) { async finDeRound(options = { terminer: false }) {
this.turns.forEach(turn => turn.actor.resetItemUse()); this.combatants.map(it => RdDCombatManager.getActorCombatant(it, { warning: false }))
.filter(it => it != undefined)
for (let combatant of this.combatants) { .forEach(async actor => {
if (combatant.actor) { await actor.finDeRound(options)
await combatant.actor.finDeRound(options); await actor.resetItemUse()
})
} }
else {
static getActorCombatant(combatant, options = { warning: true }) {
if (!combatant.actor) {
if (options.warning) {
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`) ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`)
} }
return undefined
} }
else if (!combatant.actor.isActorCombat()) {
if (options.warning) {
ui.notifications.warn(`${combatant.name} ne peut pas combattre!`)
}
return undefined
}
return combatant.actor
}
static calculAjustementInit(actor, arme) {
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
const etatGeneral = actor.getEtatGeneral() ?? 0
return efficacite + etatGeneral
} }
/************************************************************************************/ /************************************************************************************/
async rollInitiative(ids, formula = undefined, messageOptions = {}) { async rollInitiative(ids, messageOptions = {}) {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions); console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
ids = typeof ids === "string" ? [ids] : ids
ids.forEach(async id =>
await this.rollInitRdD(id, undefined, messageOptions)
)
return this
}
ids = typeof ids === "string" ? [ids] : ids; async rollInitRdD(id, formula, messageOptions = {}) {
// calculate initiative const combatant = this.combatants.get(id);
for (let cId = 0; cId < ids.length; cId++) { const actor = RdDCombatManager.getActorCombatant(combatant)
const combatant = this.combatants.get(ids[cId]); if (actor) {
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0); const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor)
if (!formula) {
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
const competence = combatant.actor.items.find(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
if (competence) {
rollFormula = RdDCombatManager.formuleInitiative(2, competence.system.carac_value, competence.system.niveau, 0);
}
} else {
const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe)
let compName = "Corps à corps"
if (armeCombat) {
if (armeCombat.system.competence != "") {
compName = armeCombat.system.competence
}
if (armeCombat.system.lancer != "") {
compName = armeCombat.system.lancer
}
if (armeCombat.system.tir != "") {
compName = armeCombat.system.tir
}
}
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
if (competence && competence.system.defaut_carac) {
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
const niveau = competence.system.niveau;
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
} else {
ui.notifications.warn(`Votre arme ${armeCombat.name} n'a pas de compétence renseignée`);
}
}
}
//console.log("Combatat", c);
const roll = combatant.getInitiativeRoll(rollFormula); const roll = combatant.getInitiativeRoll(rollFormula);
if (!roll.total) { if (!roll.total) {
roll.evaluate({ async: false }); await roll.evaluate();
} }
const total = Math.max(roll.total, 0.00); const total = Math.max(roll.total, 0.00);
console.log("Compute init for", rollFormula, roll, total, combatant); console.log("Compute init for", rollFormula, roll, total, combatant);
let id = combatant._id || combatant.id; await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]);
await this.updateEmbeddedDocuments("Combatant", [{ _id: 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");
let messageData = foundry.utils.mergeObject( let messageData = foundry.utils.mergeObject({
{
speaker: { speaker: {
scene: canvas.scene._id, scene: canvas.scene._id,
actor: combatant.actor?._id, actor: combatant.actor?._id,
@ -137,18 +136,28 @@ 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.initInfo}) flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.info})<br>`
<br>
`,
}, },
messageOptions messageOptions);
);
roll.toMessage(messageData, { rollMode, create: true }); roll.toMessage(messageData, { rollMode, create: true });
RdDCombatManager.processPremierRoundInit(); RdDCombatManager.processPremierRoundInit();
} }
return this; return this;
}; }
static getFirstInitRollFormula(actor) {
const actions = actor.listActionsCombat()
if (actions.length > 0) {
const action = actions[0]
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
}
let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined);
return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement);
}
static formuleInitiative(rang, carac, niveau, bonusMalus) { static formuleInitiative(rang, carac, niveau, bonusMalus) {
return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`; return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
@ -218,72 +227,23 @@ export class RdDCombatManager extends Combat {
static $prepareAttaqueArme(infoAttaque) { static $prepareAttaqueArme(infoAttaque) {
const comp = infoAttaque.competences.find(c => c.name == infoAttaque.competence); const comp = infoAttaque.competences.find(c => c.name == infoAttaque.competence);
const attaque = foundry.utils.duplicate(infoAttaque.arme); const arme = infoAttaque.arme;
const attaque = foundry.utils.duplicate(arme);
attaque.action = 'attaque'; attaque.action = 'attaque';
attaque.system.competence = infoAttaque.competence; attaque.system.competence = infoAttaque.competence;
attaque.system.dommagesReels = infoAttaque.dommagesReel; attaque.system.dommagesReels = infoAttaque.dommagesReel;
attaque.system.infoMain = infoAttaque.infoMain; attaque.system.infoMain = infoAttaque.infoMain;
attaque.system.niveau = comp.system.niveau; attaque.system.niveau = comp.system.niveau;
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value);
const ajustement = (arme?.parent?.getEtatGeneral() ?? 0) + (arme?.system.magique) ? arme.system.ecaille_efficacite : 0;
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value, ajustement);
return attaque; return attaque;
} }
static listActionsCreature(competences) {
return competences
.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
.map(it => RdDItemCompetenceCreature.armeCreature(it))
.filter(it => it != undefined);
}
static listActionsPossessions(actor) {
return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
return {
name: p.name,
action: 'possession',
system: {
competence: p.name,
possessionid: p.system.possessionid,
}
}
}));
}
/* -------------------------------------------- */
static listActionsCombat(combatant) {
const actor = combatant.actor;
let actions = RdDCombatManager.listActionsPossessions(actor);
if (actions.length > 0) {
return actions;
}
if (actor.isCreatureEntite()) {
actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']);
} else if (actor.isPersonnage()) {
// Recupération des items 'arme'
const competences = actor.itemTypes['competence'];
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
.concat(RdDItemArme.empoignade(actor))
.concat(RdDItemArme.mainsNues(actor));
actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac);
if (actor.system.attributs.hautrevant.value) {
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
}
}
return RdDCombatManager._indexActions(actions);
}
static _indexActions(actions) {
for (let index = 0; index < actions.length; index++) {
actions[index].index = index;
}
return actions;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static processPremierRoundInit() { static processPremierRoundInit() {
// Check if we have the whole init ! // Check if we have the whole init !
if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) { if (Misc.isFirstConnectedGM() && game.combat.current.round == 1) {
let initMissing = game.combat.combatants.find(it => !it.initiative); let initMissing = game.combat.combatants.find(it => !it.initiative);
if (!initMissing) { // Premier round ! if (!initMissing) { // Premier round !
for (let combatant of game.combat.combatants) { for (let combatant of game.combat.combatants) {
@ -317,13 +277,13 @@ export class RdDCombatManager extends Combat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static pushInitiativeOptions(html, options) { static pushInitiativeOptions(html, options) {
for (let i = 0; i < options.length; i++) { for (let i = 0; i < options.length; i++) {
let option = options[i]; let option = options[i]
if (option.name == 'COMBAT.CombatantReroll') { // Replace ! if (option.name == 'COMBAT.CombatantReroll') { // Replace !
option.name = "Sélectionner l'initiative..."; option.name = "Sélectionner l'initiative..."
option.condition = true; option.condition = true
option.icon = '<i class="far fa-question-circle"></i>'; option.icon = '<i class="far fa-question-circle"></i>'
option.callback = target => { option.callback = target => {
RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id')); RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id'))
} }
} }
} }
@ -334,96 +294,82 @@ export class RdDCombatManager extends Combat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static rollInitiativeAction(combatantId, action) { static rollInitiativeAction(combatantId, action) {
const combatant = game.combat.combatants.get(combatantId); const combatant = game.combat.combatants.get(combatantId)
if (combatant.actor == undefined) { const actor = RdDCombatManager.getActorCombatant(combatant)
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) if (actor == undefined) { return [] }
return [];
}
let initInfo = "";
let initOffset = 0;
let caracForInit = 0;
let compNiveau = 0;
let compData = { name: "Aucune" };
if (combatant.actor.getSurprise() == "totale") {
initOffset = -1; // To force 0
initInfo = "Surprise Totale"
} else if (combatant.actor.getSurprise() == "demi") {
initOffset = 0;
initInfo = "Demi Surprise"
} else if (action.action == 'possession') {
initOffset = 10;
caracForInit = combatant.actor.getReveActuel();
initInfo = "Possession"
} else if (action.action == 'autre') {
initOffset = 2;
initInfo = "Autre Action"
} else if (action.action == 'haut-reve') {
initOffset = 9;
initInfo = "Draconic"
} else {
compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence);
compNiveau = compData.system.niveau;
initInfo = action.name + " / " + action.system.competence;
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
caracForInit = compData.system.carac_value;
} else {
caracForInit = combatant.actor.system.carac[compData.system.defaut_carac].value;
}
initOffset = RdDCombatManager._baseInitOffset(compData.system.categorie, action);
}
let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général
// Cas des créatures et entités vs personnages
let rollFormula = RdDCombatManager.formuleInitiative(initOffset, caracForInit, compNiveau, malus);
// Garder la trace de l'arme/compétence utilisée pour l'iniative
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0 combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
const init = RdDCombatManager.getInitData(actor, action)
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
game.combat.rollInitRdD(combatantId, rollFormula, init);
} }
/* -------------------------------------------- */ static getInitData(actor, action) {
static _baseInitOffset(categorie, arme) { if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } }
if (categorie == "tir") { // Offset de principe pour les armes de jet if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } }
return 8; if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } }
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
const comp = RdDItemCompetence.findCompetence(actor.items, action.system.competence);
return {
offset: RdDCombatManager.initOffset(comp?.system.categorie, action),
info: action.name + " / " + action.system.competence,
carac: actor.getCaracInit(comp),
niveau: comp?.system.niveau ?? -8
} }
if (categorie == "lancer") { // Offset de principe pour les armes de jet
return 7;
} }
static initOffset(categorie, arme) {
switch (categorie) {
case "tir": return 8
case "lancer": return 7
default:
switch (arme.system.cac) { switch (arme.system.cac) {
case "empoignade": case "empoignade": return 3
return 3; case "pugilat": return 4
case "pugilat": case "naturelle": return 4
case "naturelle": default: return 5
return 4; }
} }
return 5;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static displayInitiativeMenu(html, combatantId) { static displayInitiativeMenu(html, combatantId) {
console.log("Combatant ; ", combatantId); const combatant = game.combat.combatants.get(combatantId)
const combatant = game.combat.combatants.get(combatantId); const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
if (!(combatant?.actor)) { if (actor) {
ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) const actions = RdDCombatManager.listActionsActorCombatant(actor)
return;
}
let actions = RdDCombatManager.listActionsCombat(combatant);
// Build the relevant submenu // Build the relevant submenu
if (actions) { const menuItems = actions.map(action => {
let menuItems = []; return {
for (let action of actions) {
menuItems.push({
name: action.system.competence, name: action.system.competence,
icon: "<i class='fas fa-dice-d6'></i>", icon: "<i class='fas fa-dice-d6'></i>",
callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) } callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) }
});
} }
})
if (menuItems.length > 0) {
new ContextMenu(html, ".directory-list", menuItems).render(); new ContextMenu(html, ".directory-list", menuItems).render();
} }
} }
}
/* -------------------------------------------- */
static listActionsActorCombatant( actor) {
const possessions = actor.listActionsPossessions()
const actions = possessions.length > 0
? possessions
: actor.listActionsCombat()
for (let index = 0; index < actions.length; index++) {
actions[index].index = index
}
return actions
}
} }
@ -447,11 +393,11 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
static combatNouveauTour(combat) { static combatNouveauTour(combat) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId); let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId);
if (turn?.actor) { if (turn?.actor) {
RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token.id);
// TODO Playaudio for player?? // TODO Playaudio for player??
RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token);
} }
} }
} }
@ -462,52 +408,51 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static rddCombatTarget(target, attacker) { static rddCombatTarget(target, attacker, attackerToken) {
const defender = target?.actor; return new RdDCombat(attacker, attackerToken?.id, target?.actor, target?.id, target)
const defenderTokenId = target?.id;
return new RdDCombat(attacker, defender, defenderTokenId, target)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) { static rddCombatForAttackerAndDefender(attackerId, attackerTokenId, defenderTokenId) {
const attacker = game.actors.get(attackerId); const attacker = game.actors.get(attackerId)
let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined; const defenderToken = defenderTokenId ? canvas.tokens.get(defenderTokenId) : undefined
let defender = defenderToken?.actor;
let target = undefined let target = undefined
if (!defenderTokenId || !defender) { if (!defenderTokenId || !defender) {
console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`); console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`);
target = Targets.getTarget() target = Targets.getTarget()
if (!target) { if (!target) {
return; return
} }
defenderTokenId = target.id; defenderTokenId = target.id;
defender = target.actor; defender = target.actor;
if (!defenderTokenId || !defender) { if (!defenderTokenId || !defender) {
return; return
} }
} }
return new RdDCombat(attacker, defender, defenderTokenId, target) return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onMsgEncaisser(msg) { static onMsgEncaisser(msg) {
let defender = canvas.tokens.get(msg.defenderTokenId).actor;
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) { if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
let attackerRoll = msg.attackerRoll; let attackerRoll = msg.attackerRoll;
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined; let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
let defender = canvas.tokens.get(msg.defenderToken.id).actor;
defender.encaisserDommages(attackerRoll, attacker); defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme); rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onMsgDefense(msg) { static onMsgDefense(msg) {
let defenderToken = canvas.tokens.get(msg.defenderTokenId); let defenderToken = canvas.tokens.get(msg.defenderToken.id)
if (defenderToken && Misc.isUniqueConnectedGM()) { if (defenderToken && Misc.isFirstConnectedGM()) {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme); rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme)
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll); rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
} }
} }
@ -538,6 +483,7 @@ export class RdDCombat {
html.on("click", button, event => { html.on("click", button, event => {
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender( const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
event.currentTarget.attributes['data-attackerId']?.value, event.currentTarget.attributes['data-attackerId']?.value,
event.currentTarget.attributes['data-attackerTokenId']?.value,
event.currentTarget.attributes['data-defenderTokenId']?.value); event.currentTarget.attributes['data-defenderTokenId']?.value);
if (rddCombat) { if (rddCombat) {
rddCombat.onEvent(button, event); rddCombat.onEvent(button, event);
@ -553,22 +499,38 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(attacker, defender, defenderTokenId, target) { constructor(attacker, attackerTokenId, defender, defenderTokenId, target) {
this.attacker = attacker this.attacker = attacker
this.defender = defender this.defender = defender
this.target = target this.target = target
this.attackerId = this.attacker.id this.attackerId = this.attacker.id
this.defenderId = this.defender.id this.defenderId = this.defender.id
this.attackerTokenId = attackerTokenId
this.defenderTokenId = defenderTokenId this.defenderTokenId = defenderTokenId
this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId)
this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, target)
} }
static $extractAttackerTokenData(attacker, attackerTokenId) {
const token = canvas.tokens.get(attackerTokenId);
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(attackerTokenId, attacker)
}
static $extractDefenderTokenData(defender, defenderTokenId, target) {
if (target) {
return Targets.extractTokenData(target)
}
const token = canvas.tokens.get(defenderTokenId);
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender)
}
/* -------------------------------------------- */ /* -------------------------------------------- */
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, 'defender-roll');
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll'); const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll');
console.log('RdDCombat', attackerRoll, defenderRoll); console.log('RdDCombat', attackerRoll, defenderRoll);
const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value;
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value; const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
const competence = event.currentTarget.attributes['data-competence']?.value; const competence = event.currentTarget.attributes['data-competence']?.value;
@ -578,7 +540,7 @@ export class RdDCombat {
case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value); case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
case '#parer-button': return this.parade(attackerRoll, armeParadeId); case '#parer-button': return this.parade(attackerRoll, armeParadeId);
case '#esquiver-button': return this.esquive(attackerRoll, compId, competence); case '#esquiver-button': return this.esquive(attackerRoll, compId, competence);
case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll, defenderTokenId); case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
case '#echec-total-attaque': return this._onEchecTotal(attackerRoll); case '#echec-total-attaque': return this._onEchecTotal(attackerRoll);
case '#appel-chance-attaque': return this.attacker.rollAppelChance( case '#appel-chance-attaque': return this.attacker.rollAppelChance(
@ -691,11 +653,11 @@ export class RdDCombat {
if (this.defender.isEntite([ENTITE_BLURETTE])) { if (this.defender.isEntite([ENTITE_BLURETTE])) {
ChatMessage.create({ ChatMessage.create({
content: `<strong>La cible est une blurette, l'arme à distance sera perdue dans le blurêve`, content: `<strong>La cible est une blurette, l'arme à distance sera perdue dans le blurêve`,
whisper: ChatMessage.getWhisperRecipients("GM") whisper: ChatUtility.getGMs()
}) })
} }
else { else {
const defenderToken = canvas.tokens.get(this.defenderTokenId); const defenderToken = canvas.tokens.get(this.defenderTokenId)
const dist = this.distance(_token, defenderToken) const dist = this.distance(_token, defenderToken)
const isVisible = this.isVisible(_token, defenderToken) const isVisible = this.isVisible(_token, defenderToken)
const portee = this._ajustementPortee(dist, rollData.arme) const portee = this._ajustementPortee(dist, rollData.arme)
@ -714,7 +676,7 @@ export class RdDCombat {
activite: activite, activite: activite,
total: total total: total
}), }),
whisper: ChatMessage.getWhisperRecipients("GM") whisper: ChatUtility.getGMs()
}) })
} }
} }
@ -762,7 +724,7 @@ export class RdDCombat {
} }
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker) RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
let rollData = this._prepareAttaque(competence, arme); let rollData = this._prepareAttaque(competence, arme)
console.log("RdDCombat.attaque >>>", rollData); console.log("RdDCombat.attaque >>>", rollData);
if (arme) { if (arme) {
this.attacker.verifierForceMin(arme); this.attacker.verifierForceMin(arme);
@ -788,15 +750,18 @@ export class RdDCombat {
dialog.render(true); dialog.render(true);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_prepareAttaque(competence, arme) { _prepareAttaque(competence, arme) {
let rollData = { let rollData = {
passeArme: randomID(16), alias: this.attackerToken.name,
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite, mortalite: arme?.system.mortalite,
competence: competence, competence: competence,
surprise: this.attacker.getSurprise(true), surprise: this.attacker.getSurprise(true),
surpriseDefenseur: this.defender.getSurprise(true), surpriseDefenseur: this.defender.getSurprise(true),
targetToken: Targets.extractTokenData(this.target), sourceToken: this.attackerToken,
targetToken: this.defenderToken,
essais: {} essais: {}
}; };
@ -839,11 +804,12 @@ export class RdDCombat {
const choixParticuliere = await ChatMessage.create({ const choixParticuliere = await ChatMessage.create({
alias: this.attacker.name, alias: this.attacker.name,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', {
alias: this.attacker.name, alias: this.attackerToken.name,
attackerId: this.attackerId, attackerId: this.attackerId,
defenderTokenId: this.defenderTokenId, attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
isForce: isForce, isForce: isForce,
isFinesse: isFinesse, isFinesse: isFinesse,
isRapide: isRapide, isRapide: isRapide,
@ -857,10 +823,10 @@ export class RdDCombat {
async _onAttaqueNormale(attackerRoll) { async _onAttaqueNormale(attackerRoll) {
console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll); console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll);
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntite()); attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite());
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} } let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
attackerRoll.show = { attackerRoll.show = {
cible: this.target ? this.defender.name : 'la cible', cible: this.defenderToken?.name ?? 'la cible',
isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge') isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge')
} }
await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html'); await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html');
@ -891,7 +857,7 @@ export class RdDCombat {
// # utilisation esquive // # utilisation esquive
const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) }); const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) });
const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive()) const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive())
esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0); esquives.forEach(e => e.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
const paramChatDefense = { const paramChatDefense = {
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
@ -901,7 +867,8 @@ export class RdDCombat {
attacker: this.attacker, attacker: this.attacker,
attackerId: this.attackerId, attackerId: this.attackerId,
esquives: esquives, esquives: esquives,
defenderTokenId: this.defenderTokenId, attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps, mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps,
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme), armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0, diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
@ -912,7 +879,7 @@ export class RdDCombat {
dmg: attackerRoll.dmg, dmg: attackerRoll.dmg,
}; };
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
await this._chatMessageDefense(paramChatDefense, defenderRoll); await this._chatMessageDefense(paramChatDefense, defenderRoll);
} }
else { else {
@ -925,8 +892,8 @@ export class RdDCombat {
const choixDefense = await ChatMessage.create({ const choixDefense = await ChatMessage.create({
// message privé: du défenseur à lui même (et aux GMs) // message privé: du défenseur à lui même (et aux GMs)
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)), speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
alias: this.attacker.name, alias: this.attackerToken.name,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.defender.name), whisper: ChatUtility.getOwners(this.defender),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense),
}); });
// flag pour garder les jets d'attaque/defense // flag pour garder les jets d'attaque/defense
@ -939,8 +906,9 @@ export class RdDCombat {
game.socket.emit(SYSTEM_SOCKET_ID, { game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_defense", data: { msg: "msg_defense", data: {
attackerId: this.attacker?.id, attackerId: this.attacker?.id,
attackerToken: this.attackerToken,
defenderId: this.defender?.id, defenderId: this.defender?.id,
defenderTokenId: this.defenderTokenId, defenderToken: this.defenderToken,
defenderRoll: defenderRoll, defenderRoll: defenderRoll,
paramChatDefense: paramChatDefense, paramChatDefense: paramChatDefense,
rollMode: true rollMode: true
@ -949,31 +917,33 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_filterArmesParade(defender, competence) { _filterArmesParade(defender, competence, armeAttaque) {
let items = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it)) let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
items.forEach(item => item.system.nbUsage = defender.getItemUse(item.id)); // Ajout du # d'utilisation ce round defenses = foundry.utils.duplicate(defenses)
defenses.forEach(armeDefense => {
// Ajout du # d'utilisation ce round
armeDefense.nbUsage = defender.getItemUse(armeDefense.id)
armeDefense.typeParade = RdDItemArme.defenseArmeParade(armeAttaque, armeDefense)
})
switch (competence.system.categorie) { switch (competence.system.categorie) {
case 'tir': case 'tir':
case 'lancer': case 'lancer':
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers') return defenses.filter(armeDefense => RdDItemArme.getCategorieParade(armeDefense) == 'boucliers')
default: default:
// Le fléau ne peut être paré quau bouclier p115 return defenses.filter(armeDefense => armeDefense.typeParade != '')
if (competence.name == "Fléau") {
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
}
return items.filter(item => RdDItemArme.getCategorieParade(item));
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onAttaqueEchecTotal(attackerRoll) { async _onAttaqueEchecTotal(attackerRoll) {
const choixEchecTotal = await ChatMessage.create({ const choixEchecTotal = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name), whisper: ChatUtility.getOwners(this.attacker),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
attackerId: this.attackerId, attackerId: this.attackerId,
attacker: this.attacker, attacker: this.attacker,
defenderTokenId: this.defenderTokenId, attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
essais: attackerRoll.essais essais: attackerRoll.essais
}) })
}); });
@ -987,9 +957,9 @@ export class RdDCombat {
const arme = rollData.arme; const arme = rollData.arme;
const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.system.categorie_parade ?? ''); const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.system.categorie_parade ?? '');
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque"); const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
ChatUtility.createChatWithRollMode(this.defender.name, { ChatUtility.createChatWithRollMode(
content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme }) { content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme }) },
}); this.defender)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1045,8 +1015,11 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_prepareParade(attackerRoll, armeParade, competenceParade) { _prepareParade(attackerRoll, armeParade, competenceParade) {
let defenderRoll = { let defenderRoll = {
alias: this.defenderToken?.name,
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre, diffLibre: attackerRoll.diffLibre,
attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
attackerRoll: attackerRoll, attackerRoll: attackerRoll,
competence: this.defender.getCompetence(competenceParade), competence: this.defender.getCompetence(competenceParade),
arme: armeParade, arme: armeParade,
@ -1069,9 +1042,9 @@ export class RdDCombat {
console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll); console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll);
if (!defenderRoll.attackerRoll.isPart) { if (!defenderRoll.attackerRoll.isPart) {
// 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(this.defender.name, { 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)` },
}); this.defender)
} }
} }
@ -1126,8 +1099,11 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_prepareEsquive(attackerRoll, competence) { _prepareEsquive(attackerRoll, competence) {
let rollData = { let rollData = {
alias: this.defenderToken?.name,
passeArme: attackerRoll.passeArme, passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre, diffLibre: attackerRoll.diffLibre,
attackerToken: this.attackerToken,
defenderToken: this.defenderToken,
attackerRoll: attackerRoll, attackerRoll: attackerRoll,
competence: competence, competence: competence,
surprise: this.defender.getSurprise(true), surprise: this.defender.getSurprise(true),
@ -1145,9 +1121,9 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
_onEsquiveParticuliere(rollData) { _onEsquiveParticuliere(rollData) {
console.log("RdDCombat._onEsquiveParticuliere >>>", rollData); console.log("RdDCombat._onEsquiveParticuliere >>>", rollData);
ChatUtility.createChatWithRollMode(this.defender.name, { ChatUtility.createChatWithRollMode(
content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" { content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
}); this.defender);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -1269,9 +1245,8 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async encaisser(attackerRoll, defenderRoll, defenderTokenId) { async encaisser(attackerRoll, defenderRoll) {
defenderTokenId = defenderTokenId || this.defenderTokenId; console.log("RdDCombat.encaisser >>>", attackerRoll, defenderRoll);
console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId);
if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) { if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) {
this._onEchecTotal(defenderRoll); this._onEchecTotal(defenderRoll);
@ -1279,18 +1254,19 @@ export class RdDCombat {
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) { if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) {
attackerRoll.attackerId = this.attackerId; attackerRoll.attackerId = this.attackerId;
attackerRoll.defenderTokenId = defenderTokenId; attackerRoll.defenderTokenId = this.defenderToken.id;
await this.computeRecul(defenderRoll); await this.computeRecul(defenderRoll);
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show); await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
} }
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
game.socket.emit(SYSTEM_SOCKET_ID, { game.socket.emit(SYSTEM_SOCKET_ID, {
msg: "msg_encaisser", msg: "msg_encaisser",
data: { data: {
attackerId: this.attackerId, attackerId: this.attackerId,
defenderTokenId: defenderTokenId, attackerRoll: attackerRoll,
attackerRoll: attackerRoll attackerToken: this.attackerToken,
defenderToken: this.defenderToken
} }
}); });
} }
@ -1298,28 +1274,31 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async displayActorCombatStatus(combat, actor, tokenId) { static async displayActorCombatStatus(combat, actor, token) {
let formData = { if (!actor?.isActorCombat()) {
return
}
const formData = {
combatId: combat._id, combatId: combat._id,
alias: actor.name, alias: token.name ?? actor.name,
etatGeneral: actor.getEtatGeneral(), etatGeneral: actor.getEtatGeneral(),
isSonne: actor.getSonne(), isSonne: actor.isSonne(),
blessuresStatus: actor.computeResumeBlessure(), blessuresStatus: actor.computeResumeBlessure(),
SConst: actor.getSConst(), SConst: actor.getSConst(),
actorId: actor.id, actorId: actor.id,
actor: actor, actor: actor,
tokenId: tokenId, tokenId: token.id,
isGrave: actor.countBlessures(it => it.isGrave()) > 0, isGrave: actor.countBlessures(it => it.isGrave()) > 0,
isCritique: actor.countBlessures(it => it.isCritique()) > 0 isCritique: actor.countBlessures(it => it.isCritique()) > 0
} }
await ChatMessage.create({ await ChatMessage.create({
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs`, formData), content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs`, formData),
alias: actor.name alias: token.name ?? actor.name
}); })
await ChatMessage.create({ await ChatMessage.create({
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData), content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData),
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name), whisper: ChatUtility.getOwners(actor),
alias: actor.name alias: token.name ?? actor.name
}); })
} }
} }

View File

@ -17,6 +17,7 @@ import { RdDUtility } from "./rdd-utility.js";
import { FenetreRechercheTirage } from "./tirage/fenetre-recherche-tirage.js"; import { FenetreRechercheTirage } from "./tirage/fenetre-recherche-tirage.js";
import { TMRUtility } from "./tmr-utility.js"; 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";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
@ -81,7 +82,7 @@ export class RdDCommands {
this.registerCommand({ path: ["/sommeil"], func: (content, msg, params) => this.sommeil(msg, params), descr: "Prépare le passage de journée pour chateau dormant" }); this.registerCommand({ path: ["/sommeil"], func: (content, msg, params) => this.sommeil(msg, params), descr: "Prépare le passage de journée pour chateau dormant" });
this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" }); this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" });
this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" }); this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.proposeName(msg, params), descr: "Génère un nom aléatoire" });
this.registerCommand({ this.registerCommand({
path: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params), path: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params),
@ -206,26 +207,20 @@ export class RdDCommands {
/* Manage chat commands */ /* Manage chat commands */
processChatCommand(commandLine, content = '', msg = {}) { processChatCommand(commandLine, content = '', msg = {}) {
// Setup new message's visibility // Setup new message's visibility
let rollMode = game.settings.get("core", "rollMode"); ChatUtility.applyRollMode(msg)
if (["gmroll", "blindroll"].includes(rollMode)) { msg.type = 0;
msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
}
if (rollMode === "blindroll") {
msg["blind"] = true;
}
msg["type"] = 0;
if (!this.commandsTable) { if (!this.commandsTable) {
this._registerCommands(); this._registerCommands()
} }
let command = commandLine[0].toLowerCase(); let command = commandLine[0].toLowerCase();
if (this._isCommandHandled(command)) { if (this._isCommandHandled(command)) {
let params = commandLine.slice(1); let params = commandLine.slice(1);
this._processCommand(this.commandsTable, command, params, content, msg); this._processCommand(this.commandsTable, command, params, content, msg)
return true; return true
} }
return false; return false
} }
_isCommandHandled(command) { _isCommandHandled(command) {

View File

@ -1,9 +1,11 @@
import { Grammar } from "./grammar.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
export class RdDConfirm { export class RdDConfirm {
/* -------------------------------------------- */ /* -------------------------------------------- */
static confirmer(options, autresActions) { static confirmer(options, autresActions) {
if (options.settingConfirmer && !ReglesOptionnelles.isSet(options.settingConfirmer)) {
return options.onAction()
}
let buttons = { let buttons = {
"action": RdDConfirm._createButtonAction(options), "action": RdDConfirm._createButtonAction(options),
"cancel": RdDConfirm._createButtonCancel() "cancel": RdDConfirm._createButtonCancel()
@ -12,7 +14,7 @@ export class RdDConfirm {
buttons = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons); buttons = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons);
} }
if (autresActions) { if (autresActions) {
buttons = foundry.utils.mergeObject(autresActions, buttons); buttons = foundry.utils.mergeObject(autresActions, buttons, { inplace: false });
} }
const dialogDetails = { const dialogDetails = {
title: options.title, title: options.title,

View File

@ -2,19 +2,14 @@ import { ChatUtility } from "./chat-utility.js";
import { HIDE_DICE, SHOW_DICE } from "./constants.js"; import { HIDE_DICE, SHOW_DICE } from "./constants.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
function img(src) { const imgHeures = [1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12].map(heure => {
return `<img src="${src}" class="dice-img" />`
}
function iconHeure(heure) {
if (heure < 10) { if (heure < 10) {
heure = '0' + heure; heure = '0' + heure;
} }
return `systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure}.webp` return `<img src="systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure}.webp" class="dice-img" />`
} })
const imagesHeures = [1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12].map(it => iconHeure(it));
const imgSigneDragon = img(imagesHeures[4]); const imgSigneDragon = imgHeures[4]
/** De pour les jets de rencontre */ /** De pour les jets de rencontre */
export class DeTMR extends Die { export class DeTMR extends Die {
@ -25,7 +20,7 @@ export class DeTMR extends Die {
return { return {
type: "dt", type: "dt",
font: "HeuresDraconiques", font: "HeuresDraconiques",
fontScale: 0.7, fontScale: 0.8,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'], labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system system: system
} }
@ -36,14 +31,14 @@ export class DeTMR extends Die {
super(termData); super(termData);
} }
async evaluate() { async evaluate(options) {
super.evaluate(); await super.evaluate(options)
this.explode("x=8"); await this.reroll('r=8', { recursive: true })
return this; return this;
} }
get total() { get total() {
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0); return this.values.map(it => Misc.modulo(it, 8)).reduce(Misc.sum(), 0);
} }
getResultLabel(diceTerm) { getResultLabel(diceTerm) {
@ -56,13 +51,14 @@ export class DeTMR extends Die {
/** DeDraconique pour le D8 sans limite avec 8=>0 */ /** DeDraconique pour le D8 sans limite avec 8=>0 */
export class DeDraconique extends Die { export class DeDraconique extends Die {
/** @override */
static DENOMINATION = "r"; static DENOMINATION = "r";
static diceSoNiceData(system) { static diceSoNiceData(system) {
return { return {
type: "dr", type: "dr",
font: "HeuresDraconiques", font: "HeuresDraconiques",
fontScale: 0.7, fontScale: 0.8,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'], labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system system: system
} }
@ -73,9 +69,9 @@ export class DeDraconique extends Die {
super(termData); super(termData);
} }
async evaluate() { async evaluate(options) {
super.evaluate(); await super.evaluate(options);
this.explode("x=7"); await this.explode("x=7");
return this; return this;
} }
@ -85,7 +81,7 @@ export class DeDraconique extends Die {
getResultLabel(diceTerm) { getResultLabel(diceTerm) {
switch (diceTerm.result) { switch (diceTerm.result) {
case 7: return imgSigneDragon; case 7: return imgSigneDragon
case 8: return '0'; case 8: return '0';
} }
return diceTerm.result.toString(); return diceTerm.result.toString();
@ -102,6 +98,7 @@ export class DeHeure extends Die {
return { return {
type: "dh", type: "dh",
font: "HeuresDraconiques", font: "HeuresDraconiques",
fontScale: 1.2,
labels: ['v', 'i', 'f', 'o', 'd', 'e', 'l', 's', 'p', 'a', 'r', 'c'], labels: ['v', 'i', 'f', 'o', 'd', 'e', 'l', 's', 'p', 'a', 'r', 'c'],
system: system system: system
} }
@ -113,15 +110,15 @@ export class DeHeure extends Die {
} }
getResultLabel(diceTerm) { getResultLabel(diceTerm) {
return img(imagesHeures[diceTerm.result - 1]); return imgHeures[diceTerm.result - 1]
} }
} }
export class RdDDice { export class RdDDice {
static init() { static init() {
CONFIG.Dice.terms[DeTMR.DENOMINATION] = DeTMR; CONFIG.Dice.terms[DeTMR.DENOMINATION] = DeTMR
CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique; CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure; CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure
} }
static onReady() { static onReady() {
@ -132,13 +129,25 @@ export class RdDDice {
} }
} }
static diceSoNiceReady(dice3d) {
dice3d.DiceFactory.systems.keys().forEach(system => {
dice3d.addDicePreset(DeTMR.diceSoNiceData(system));
dice3d.addDicePreset(DeDraconique.diceSoNiceData(system));
dice3d.addDicePreset(DeHeure.diceSoNiceData(system));
})
}
static async rollHeure(options = { showDice: HIDE_DICE }) {
return await RdDDice.rollTotal("1dh", options) - 1
}
static async rollTotal(formula, options = { showDice: HIDE_DICE }) { static async rollTotal(formula, options = { showDice: HIDE_DICE }) {
return (await RdDDice.roll(formula, options)).total; return (await RdDDice.roll(formula, options)).total;
} }
static async roll(formula, options = { showDice: SHOW_DICE, rollMode: undefined }) { static async roll(formula, options = { showDice: SHOW_DICE, rollMode: undefined }) {
const roll = new Roll(RdDDice._formulaOrFake(formula, options)); const roll = new Roll(RdDDice._formulaOrFake(formula, options));
await roll.evaluate({ async: true }); await roll.evaluate();
await this.showDiceSoNice(roll, options); await this.showDiceSoNice(roll, options);
return roll; return roll;
} }
@ -151,21 +160,13 @@ export class RdDDice {
return array[roll - 1]; return array[roll - 1];
} }
static diceSoNiceReady(dice3d) {
for (const system of Object.keys(dice3d.DiceFactory.systems)) {
dice3d.addDicePreset(DeTMR.diceSoNiceData(system));
dice3d.addDicePreset(DeDraconique.diceSoNiceData(system));
dice3d.addDicePreset(DeHeure.diceSoNiceData(system));
}
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async showDiceSoNice(roll, options) { static async showDiceSoNice(roll, options) {
if (options.showDice == HIDE_DICE || !game.modules.get("dice-so-nice")?.active || !game.dice3d) { if (options.showDice == HIDE_DICE || !game.modules.get("dice-so-nice")?.active || !game.dice3d) {
return; return;
} }
let { whisper, blind } = RdDDice._getWhisperBlind(options); let { whisper, blind } = ChatUtility.applyRollMode({}, options?.rollMode);
if (options.forceDiceResult?.total) { if (options.forceDiceResult?.total) {
let terms = await RdDDice._getForcedTerms(options); let terms = await RdDDice._getForcedTerms(options);
if (terms) { if (terms) {
@ -216,27 +217,7 @@ export class RdDDice {
static async fakeD10(faces) { static async fakeD10(faces) {
let roll = new Roll(`1d${faces}`); let roll = new Roll(`1d${faces}`);
await roll.evaluate({ async: true }); await roll.evaluate();
return roll.total; return roll.total;
} }
static _getWhisperBlind(options) {
let whisper = undefined;
let blind = false;
let rollMode = options.rollMode ?? game.settings.get("core", "rollMode");
switch (rollMode) {
case "blindroll": //GM only
blind = true;
case "gmroll": //GM + rolling player
whisper = ChatUtility.getUsers(user => user.isGM);
break;
case "roll": //everybody
whisper = ChatUtility.getUsers(user => user.active);
break;
case "selfroll":
whisper = [game.user.id];
break;
}
return { whisper, blind };
}
} }

View File

@ -5,7 +5,7 @@ import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { STATUSES } from "./settings/status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -92,18 +92,18 @@ export class RdDEmpoignade {
/* -------------------------------------------- */ /* -------------------------------------------- */
static isEmpoignadeEnCours(actor) { static isEmpoignadeEnCours(actor) {
return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0) return actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.pointsemp > 0)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getEmpoignadeById(actor, id) { static getEmpoignadeById(actor, id) {
let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id) let emp = actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
return emp && foundry.utils.duplicate(emp) || undefined; return emp && foundry.utils.duplicate(emp) || undefined;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getEmpoignade(attacker, defender) { static getEmpoignade(attacker, defender) {
let emp = attacker.itemTypes[TYPES.empoignade].find(it => let emp = attacker.itemTypes[ITEM_TYPES.empoignade].find(it =>
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) || (it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id) (it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
) )
@ -158,9 +158,12 @@ export class RdDEmpoignade {
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender)) empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
//console.log("W.", empoignade, defender.hasArmeeMeleeEquipee()) //console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) { if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
ChatUtility.createChatWithRollMode(attacker.name, { ChatUtility.createChatWithRollMode(
{
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender }) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
}) },
attacker
)
} else { } else {
await this.onAttaqueEmpoignadeValidee(attacker, defender) await this.onAttaqueEmpoignadeValidee(attacker, defender)
} }
@ -213,7 +216,7 @@ export class RdDEmpoignade {
competence: attacker.getCompetenceCorpsACorps() competence: attacker.getCompetenceCorpsACorps()
} }
const msg = await ChatMessage.create({ const msg = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name), whisper: ChatUtility.getOwners(attacker),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
}) })
RdDEmpoignade.$storeRollEmpoignade(msg, rollData); RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
@ -248,7 +251,7 @@ export class RdDEmpoignade {
if (rollData.rolled.isPart) { if (rollData.rolled.isPart) {
rollData.particuliere = "finesse"; rollData.particuliere = "finesse";
} }
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html'); let msg = await RdDResolutionTable.displayRollData(rollData, defender, 'chat-empoignade-resultat.html');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData); RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
} }
@ -427,7 +430,7 @@ export class RdDEmpoignade {
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name, name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name,
type: 'empoignade', type: 'empoignade',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: { description: "", empoignadeid: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name } system: { description: "", empoignadeid: foundry.utils.randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
}, },
{ {
temporary: true temporary: true

View File

@ -6,7 +6,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
export class RdDHerbes extends Item { export class RdDHerbes extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async initializeHerbes() { static async onReady() {
this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin'); this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin');
this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos'); this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos');
} }

View File

@ -1,6 +1,6 @@
import { RdDItemArme } from "./item-arme.js"; import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
export class RdDHotbar { export class RdDHotbar {
@ -35,7 +35,7 @@ export class RdDHotbar {
static async addToHotbar(item, slot) { static async addToHotbar(item, slot) {
switch (item?.type ?? '') { switch (item?.type ?? '') {
case TYPES.arme: case ITEM_TYPES.arme:
{ {
// Les armes peuvent avoir plusieurs usages // Les armes peuvent avoir plusieurs usages
if (item.system.competence != '') { if (item.system.competence != '') {
@ -54,12 +54,12 @@ export class RdDHotbar {
} }
} }
return return
case TYPES.competencecreature: case ITEM_TYPES.competencecreature:
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence'; const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
await this.createItemMacro(item, slot, categorie) await this.createItemMacro(item, slot, categorie)
return return
default: default:
case 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')
@ -79,8 +79,7 @@ export class RdDHotbar {
* Actor - open actor sheet * Actor - open actor sheet
* Journal - open journal sheet * Journal - open journal sheet
*/ */
static initDropbar() { static initHooks() {
Hooks.on('hotbarDrop', (bar, documentData, slot) => { Hooks.on('hotbarDrop', (bar, documentData, slot) => {
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill // Create item macro if rollable item - weapon, spell, prayer, trait, or skill
@ -88,9 +87,9 @@ export class RdDHotbar {
const item = fromUuidSync(documentData.uuid) ?? this.actor.items.get(documentData.uuid) const item = fromUuidSync(documentData.uuid) ?? this.actor.items.get(documentData.uuid)
console.log('DROP', documentData, item) console.log('DROP', documentData, item)
switch (item?.type) { switch (item?.type) {
case TYPES.arme: case ITEM_TYPES.arme:
case TYPES.competence: case ITEM_TYPES.competence:
case TYPES.competencecreature: case ITEM_TYPES.competencecreature:
this.addToHotbar(item, slot) this.addToHotbar(item, slot)
return false return false
} }
@ -116,9 +115,9 @@ export class RdDHotbar {
// Trigger the item roll // Trigger the item roll
switch (item.type) { switch (item.type) {
case TYPES.arme: case ITEM_TYPES.arme:
return actor.rollArme(item, categorieArme); return actor.rollArme(item, categorieArme);
case TYPES.competence: case ITEM_TYPES.competence:
if (item.isCorpsACorps()) { if (item.isCorpsACorps()) {
switch (categorieArme) { switch (categorieArme) {
case 'pugilat': case 'pugilat':
@ -128,7 +127,7 @@ export class RdDHotbar {
} }
} }
return actor.rollCompetence(item); return actor.rollCompetence(item);
case TYPES.competencecreature: case ITEM_TYPES.competencecreature:
return item.system.iscombat && !item.system.isparade return item.system.iscombat && !item.system.isparade
? actor.rollArme(item, categorieArme) ? actor.rollArme(item, categorieArme)
: actor.rollCompetence(item); : actor.rollCompetence(item);

View File

@ -1,69 +1,74 @@
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG } from "./constants.js"; import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG } from "./constants.js"
import { Migrations } from './migrations.js'; import { Migrations } from './migrations.js'
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js"
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js"
import { TMRRencontres } from "./tmr-rencontres.js"; import { TMRRencontres } from "./tmr-rencontres.js"
import { RdDCalendrier } from "./time/rdd-calendrier.js"; import { RdDCalendrier } from "./time/rdd-calendrier.js"
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js"
import { DialogChronologie } from "./dialog-chronologie.js"; import { DialogChronologie } from "./dialog-chronologie.js"
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js"
import { RdDTokenHud } from "./rdd-token-hud.js"; import { RdDTokenHud } from "./rdd-token-hud.js"
import { RdDCommands } from "./rdd-commands.js"; import { RdDCommands } from "./rdd-commands.js"
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"; import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js"
import { StatusEffects } from "./settings/status-effects.js"; import { StatusEffects } from "./settings/status-effects.js"
import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"; import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"
import { RdDHotbar } from "./rdd-hotbar-drop.js" import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js"
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js"
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js"
import { RdDPossession } from "./rdd-possession.js"; import { RdDPossession } from "./rdd-possession.js"
import { Misc } from "./misc.js"; import { Misc } from "./misc.js"
import { SystemCompendiums } from "./settings/system-compendiums.js"; import { SystemCompendiums } from "./settings/system-compendiums.js"
import { Environnement } from "./environnement.js"; import { Environnement } from "./environnement.js"
import { RdDActor } from "./actor.js"; import { RdDActor } from "./actor.js"
import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDBaseActor } from "./actor/base-actor.js"
import { RdDCommerce } from "./actor/commerce.js"; import { RdDCommerce } from "./actor/commerce.js"
import { RdDEntite } from "./actor/entite.js"; import { RdDEntite } from "./actor/entite.js"
import { RdDVehicule } from "./actor/vehicule.js"; import { RdDVehicule } from "./actor/vehicule.js"
import { RdDActorSheet } from "./actor-sheet.js"; import { RdDActorSheet } from "./actor-sheet.js"
import { RdDCommerceSheet } from "./actor/commerce-sheet.js"; import { RdDCommerceSheet } from "./actor/commerce-sheet.js"
import { RdDCreatureSheet } from "./actor/creature-sheet.js"; import { RdDCreatureSheet } from "./actor/creature-sheet.js"
import { RdDActorEntiteSheet } from "./actor/entite-sheet.js"; import { RdDActorEntiteSheet } from "./actor/entite-sheet.js"
import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js"; import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js"
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js"
import { RdDItemBlessure } from "./item/blessure.js"; import { RdDItemBlessure } from "./item/blessure.js"
import { RdDItemService } from "./item/service.js"; import { RdDItemService } from "./item/service.js"
import { RdDItemMaladie } from "./item/maladie.js"; import { RdDItemMaladie } from "./item/maladie.js"
import { RdDItemPoison } from "./item/poison.js"; import { RdDItemPoison } from "./item/poison.js"
import { RdDItemSigneDraconique } from "./item/signedraconique.js"; import { RdDItemSigneDraconique } from "./item/signedraconique.js"
import { RdDItemQueue } from "./item/queue.js"; import { RdDItemQueue } from "./item/queue.js"
import { RdDItemOmbre } from "./item/ombre.js"; import { RdDItemOmbre } from "./item/ombre.js"
import { RdDItemSouffle } from "./item/souffle.js"; import { RdDItemSouffle } from "./item/souffle.js"
import { RdDRencontre } from "./item/rencontre.js"; import { RdDRencontre } from "./item/rencontre.js"
import { RdDItemSheet } from "./item-sheet.js"; import { RdDItemSheet } from "./item-sheet.js"
import { RdDBlessureItemSheet } from "./item/sheet-blessure.js"; import { RdDBlessureItemSheet } from "./item/sheet-blessure.js"
import { RdDServiceItemSheet } from "./item/sheet-service.js"; import { RdDServiceItemSheet } from "./item/sheet-service.js"
import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js"; import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js"
import { RdDHerbeItemSheet } from "./item/sheet-herbe.js"; import { RdDHerbeItemSheet } from "./item/sheet-herbe.js"
import { RdDPlanteItemSheet } from "./item/sheet-plante.js"; import { RdDPlanteItemSheet } from "./item/sheet-plante.js"
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"; import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"
import { RdDFauneItemSheet } from "./item/sheet-faune.js"; import { RdDFauneItemSheet } from "./item/sheet-faune.js"
import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js"; import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js"
import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js"; import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js"
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"; import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"
import { AppAstrologie } from "./sommeil/app-astrologie.js"; import { AppAstrologie } from "./sommeil/app-astrologie.js"
import { RdDItemArmure } from "./item/armure.js"; import { RdDItemArmure } from "./item/armure.js"
import { AutoAdjustDarkness as AutoAdjustDarkness } from "./time/auto-adjust-darkness.js"; import { AutoAdjustDarkness } from "./time/auto-adjust-darkness.js"
import { RdDCreature } from "./actor/creature.js"; import { RdDCreature } from "./actor/creature.js"
import { RdDTMRDialog } from "./rdd-tmr-dialog.js"; import { RdDTMRDialog } from "./rdd-tmr-dialog.js"
import { OptionsAvancees } from "./settings/options-avancees.js"
import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js"
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"
import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js"
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
/** /**
* RdD system * RdD system
@ -76,12 +81,14 @@ export class SystemReveDeDragon {
const system = new SystemReveDeDragon() const system = new SystemReveDeDragon()
Hooks.once('init', async () => await system.onInit()) Hooks.once('init', async () => await system.onInit())
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)) Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d))
Hooks.once('ready', () => system.onReady()) Hooks.once('ready', async () => await system.onReady())
} }
constructor() { constructor() {
this.RdDUtility = RdDUtility; this.config = RDD_CONFIG
this.RdDHotbar = RdDHotbar; this.RdDUtility = RdDUtility
this.RdDHotbar = RdDHotbar
this.RdDStatBlockParser = RdDStatBlockParser
this.itemClasses = { this.itemClasses = {
armure: RdDItemArmure, armure: RdDItemArmure,
blessure: RdDItemBlessure, blessure: RdDItemBlessure,
@ -107,43 +114,51 @@ export class SystemReveDeDragon {
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
/* -------------------------------------------- */ /* -------------------------------------------- */
async onInit() { async onInit() {
game.system.rdd = this; game.system.rdd = this
game.system.rdd.config = RDD_CONFIG; this.AppAstrologie = AppAstrologie
this.AppAstrologie = AppAstrologie;
console.log(`Initializing Reve de Dragon System Settings`)
console.log(`Initializing Reve de Dragon System`);
// preload handlebars templates // preload handlebars templates
RdDUtility.preloadHandlebarsTemplates(); RdDUtility.preloadHandlebarsTemplates()
AppPersonnageAleatoire.preloadHandlebars()
/* -------------------------------------------- */ /* -------------------------------------------- */
this.initSystemSettings(); ReglesOptionnelles.initSettings()
OptionsAvancees.initSettings()
AutoAdjustDarkness.initSettings()
RdDTimestamp.initSettings()
RdDCalendrier.initSettings()
SystemCompendiums.initSettings()
DialogChronologie.initSettings()
RdDTMRDialog.initSettings()
Environnement.initSettings()
this.initSettings()
/* -------------------------------------------- */ /* -------------------------------------------- */
// Set an initiative formula for the system // Set an initiative formula for the system
CONFIG.Combat.initiative = { CONFIG.Combat.initiative = { formula: "1+(1d6/10)", decimals: 2 }
formula: "1+(1d6/10)",
decimals: 2
};
/* -------------------------------------------- */ /* -------------------------------------------- */
console.log(`Initializing Reve de Dragon Socket handlers`)
game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => { game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
console.log(">>>>> MSG RECV", sockmsg); console.log(">>>>> MSG RECV", sockmsg)
try { try {
RdDUtility.onSocketMessage(sockmsg); RdDUtility.onSocketMessage(sockmsg)
RdDCombat.onSocketMessage(sockmsg); RdDCombat.onSocketMessage(sockmsg)
ChatUtility.onSocketMessage(sockmsg); ChatUtility.onSocketMessage(sockmsg)
RdDBaseActor.onSocketMessage(sockmsg); RdDBaseActor.onSocketMessage(sockmsg)
} catch (e) { } catch (e) {
console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e) console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e)
} }
}); })
/* -------------------------------------------- */ /* -------------------------------------------- */
// Define custom Entity classes // Define custom Entity classes
CONFIG.Actor.documentClass = RdDBaseActor; console.log(`Initializing Reve de Dragon Documents`)
CONFIG.Item.documentClass = RdDItem; CONFIG.Actor.documentClass = RdDBaseActor
CONFIG.Item.documentClass = RdDItem
CONFIG.RDD = { CONFIG.RDD = {
resolutionTable: RdDResolutionTable.resolutionTable, resolutionTable: RdDResolutionTable.resolutionTable,
carac_array: RdDUtility.getCaracArray(), carac_array: RdDUtility.getCaracArray(),
@ -153,30 +168,31 @@ export class SystemReveDeDragon {
/* -------------------------------------------- */ /* -------------------------------------------- */
// Register sheet application classes // Register sheet application classes
Actors.unregisterSheet("core", ActorSheet); Actors.unregisterSheet("core", ActorSheet)
Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true })
Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true })
Actors.registerSheet(SYSTEM_RDD, RdDCreatureSheet, { types: ["creature"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDCreatureSheet, { types: ["creature"], makeDefault: true })
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true })
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true }); Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true })
Items.unregisterSheet("core", ItemSheet); Items.unregisterSheet("core", ItemSheet)
await RdDActorExportSheet.init()
RdDItemSheet.register(RdDSigneDraconiqueItemSheet); RdDItemSheet.register(RdDSigneDraconiqueItemSheet)
RdDItemSheet.register(RdDRencontreItemSheet); RdDItemSheet.register(RdDRencontreItemSheet)
RdDItemSheet.register(RdDConteneurItemSheet); RdDItemSheet.register(RdDConteneurItemSheet)
RdDItemSheet.register(RdDHerbeItemSheet); RdDItemSheet.register(RdDHerbeItemSheet)
RdDItemSheet.register(RdDFauneItemSheet); RdDItemSheet.register(RdDFauneItemSheet)
RdDItemSheet.register(RdDPlanteItemSheet); RdDItemSheet.register(RdDPlanteItemSheet)
RdDItemSheet.register(RdDIngredientItemSheet); RdDItemSheet.register(RdDIngredientItemSheet)
RdDItemSheet.register(RdDServiceItemSheet); RdDItemSheet.register(RdDServiceItemSheet)
RdDItemSheet.register(RdDBlessureItemSheet); RdDItemSheet.register(RdDBlessureItemSheet)
Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, { Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, {
types: [ types: [
"objet", "arme", "armure", "livre", "potion", "munition", "objet", "arme", "armure", "livre", "potion", "munition",
"monnaie", "nourritureboisson", "gemme", "monnaie", "nourritureboisson", "gemme",
], makeDefault: true ], makeDefault: true
}); })
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
types: [ types: [
"competence", "competencecreature", "competence", "competencecreature",
@ -185,34 +201,29 @@ export class SystemReveDeDragon {
"nombreastral", "tache", "maladie", "poison", "possession", "nombreastral", "tache", "maladie", "poison", "possession",
"tarot", "extraitpoetique", "empoignade" "tarot", "extraitpoetique", "empoignade"
], makeDefault: true ], makeDefault: true
}); })
CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules // préparation des différents modules
AutoAdjustDarkness.init(); console.log(`Initializing Reve de Dragon Hooks and handlers`)
RdDTimestamp.init(); CONFIG.Combat.documentClass = RdDCombatManager
RdDCalendrier.init(); ChatUtility.init()
SystemCompendiums.init(); RdDUtility.initHooks()
DialogChronologie.init(); RdDDice.init()
ReglesOptionnelles.init(); RdDCommands.init()
RdDUtility.init(); RdDCombatManager.init()
RdDDice.init(); RdDTokenHud.init()
RdDCommands.init(); RdDBaseActor.init()
RdDCombatManager.init(); RdDCompendiumOrganiser.init()
RdDTokenHud.init();
RdDBaseActor.init();
RdDCompendiumOrganiser.init();
EffetsDraconiques.init() EffetsDraconiques.init()
TMRUtility.init(); TMRUtility.init()
await RdDTMRDialog.init() RdDHotbar.initHooks()
RdDHotbar.initDropbar(); RdDPossession.init()
RdDPossession.init(); TMRRencontres.init()
TMRRencontres.init(); ExportScriptarium.init()
Environnement.init();
} }
initSystemSettings() { initSettings() {
// TODO: déplacer vers les modules correspondants
game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", { game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", {
name: "Accorder le rêve aux entités", name: "Accorder le rêve aux entités",
hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar", hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
@ -225,7 +236,7 @@ export class SystemReveDeDragon {
"avant-encaissement": "Avant l'encaissement", "avant-encaissement": "Avant l'encaissement",
}, },
default: "avant-encaissement" default: "avant-encaissement"
}); })
/* -------------------------------------------- */ /* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
@ -235,7 +246,7 @@ export class SystemReveDeDragon {
config: true, config: true,
default: true, default: true,
type: Boolean type: Boolean
}); })
/* -------------------------------------------- */ /* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "activer-sons-audio", { game.settings.register(SYSTEM_RDD, "activer-sons-audio", {
@ -245,7 +256,8 @@ export class SystemReveDeDragon {
config: true, config: true,
default: true, default: true,
type: Boolean type: Boolean
}); })
/* -------------------------------------------- */ /* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", { game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", {
name: "Notifier de la famine et la soif pour", name: "Notifier de la famine et la soif pour",
@ -259,7 +271,7 @@ export class SystemReveDeDragon {
"famine-soif": "la famine et la soif", "famine-soif": "la famine et la soif",
}, },
default: "aucun" default: "aucun"
}); })
} }
async onReady() { async onReady() {
@ -267,47 +279,48 @@ export class SystemReveDeDragon {
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
/* -------------------------------------------- */ /* -------------------------------------------- */
game.system.rdd.calendrier = new RdDCalendrier(); game.system.rdd.calendrier = new RdDCalendrier()
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
new Migrations().migrate(); new Migrations().migrate()
this.messageDeBienvenue(); this.messageDeBienvenue()
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter=>{ import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
console.log("ClassCounter loaded", moduleCounter) console.log("ClassCounter loaded", moduleCounter)
moduleCounter.ClassCounter.registerUsageCount() moduleCounter.ClassCounter.registerUsageCount()
}).catch(err=> }).catch(err =>
console.log("No stats available, giving up.") console.log("No stats available, giving up.")
) )
} }
StatusEffects.onReady(); StatusEffects.onReady()
RdDHerbes.initializeHerbes(); RdDHerbes.onReady()
RdDDice.onReady(); RdDDice.onReady()
RdDStatBlockParser.parseStatBlock()
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Affiche/Init le calendrier */ /* Affiche/Init le calendrier */
game.system.rdd.calendrier.display(); game.system.rdd.calendrier.display()
// Avertissement si joueur sans personnage // Avertissement si joueur sans personnage
if (!game.user.isGM && game.user.character == undefined) { if (!game.user.isGM && game.user.character == undefined) {
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !"); ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !")
ChatMessage.create({ ChatMessage.create({
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !", content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
user: game.user.id user: game.user.id
}); })
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
messageDeBienvenue() { messageDeBienvenue() {
if (game.user.isGM) { if (game.user.isGM) {
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">'); ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">')
ChatMessage.create({ ChatMessage.create({
user: game.user.id, user: game.user.id,
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span> content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
<br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs} <br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
<br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div> <br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
` }); ` })
} }
} }
} }
SystemReveDeDragon.start(); SystemReveDeDragon.start()

View File

@ -1,3 +1,4 @@
import { ChatUtility } from "./chat-utility.js"
const vents = [ const vents = [
{ min: 0, max: 0, valeur: 'Calme' }, { min: 0, max: 0, valeur: 'Calme' },
@ -56,7 +57,7 @@ const temperatures = [
export class RdDMeteo { export class RdDMeteo {
static async getForce() { static async getForce() {
const roll = new Roll(`1dr`); const roll = new Roll(`1dr`);
await roll.evaluate({ async: true }); await roll.evaluate();
return roll.total; return roll.total;
} }
@ -67,14 +68,14 @@ export class RdDMeteo {
static async getTemperature() { static async getTemperature() {
const degre = await RdDMeteo.getForce(); const degre = await RdDMeteo.getForce();
const rollChaudFroid = new Roll('1d2'); const rollChaudFroid = new Roll('1d2');
await rollChaudFroid.evaluate({ async: true }); await rollChaudFroid.evaluate();
const chaudFroid = rollChaudFroid.total == 1; const chaudFroid = rollChaudFroid.total == 1;
return chaudFroid.total ? degre : -degre; return chaudFroid.total ? degre : -degre;
} }
static async getDirection(direction) { static async getDirection(direction) {
const roll = new Roll(`1d16`); const roll = new Roll(`1d16`);
await roll.evaluate({ async: true }); await roll.evaluate();
switch (roll.total % 16) { switch (roll.total % 16) {
case 0: return 'Nord'; case 0: return 'Nord';
case 1: return 'Nord Nord Est'; case 1: return 'Nord Nord Est';
@ -117,7 +118,7 @@ export class RdDMeteo {
ChatMessage.create({ ChatMessage.create({
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-meteo.html', meteo), content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-meteo.html', meteo),
whisper: ChatMessage.getWhisperRecipients('GM') whisper: ChatUtility.getGMs()
}); });
} }

View File

@ -1,4 +1,5 @@
import { RdDBaseActor } from "./actor/base-actor.js"; import { RdDBaseActor } from "./actor/base-actor.js";
import { ChatUtility } from "./chat-utility.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
@ -11,11 +12,15 @@ const words = ['pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i',
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDNameGen { export class RdDNameGen {
static async getName(msg, params) { static async proposeName(msg, params) {
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-command-nom.html`, { const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-command-nom.html`, {
nom: Misc.upperFirst(await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words)) nom: await RdDNameGen.generate()
}); });
ChatMessage.create({ content: html, whisper: ChatMessage.getWhisperRecipients("GM") }); ChatMessage.create({ content: html, whisper: ChatUtility.getGMs() });
}
static async generate() {
return Misc.upperFirst(await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words));
} }
static async onCreerActeur(event) { static async onCreerActeur(event) {

View File

@ -3,7 +3,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js"; import { RdDRoll } from "./rdd-roll.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"; import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { Targets } from "./targets.js"; import { Targets } from "./targets.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs /* On part du principe qu'une entité démarre tjs
@ -20,9 +20,9 @@ export class RdDPossession {
/* -------------------------------------------- */ /* -------------------------------------------- */
static searchPossessionFromEntite(attacker, defender) { static searchPossessionFromEntite(attacker, defender) {
let poss = attacker.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id); let poss = attacker.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
if (!poss) { if (!poss) {
poss = defender.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id); poss = defender.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
} }
return poss && foundry.utils.duplicate(poss) || undefined; return poss && foundry.utils.duplicate(poss) || undefined;
} }
@ -131,7 +131,7 @@ export class RdDPossession {
} }
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid) const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
RdDPossession.storePossessionAttaque(possession, rollData) RdDPossession.storePossessionAttaque(possession, rollData)
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html'); await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -171,7 +171,7 @@ export class RdDPossession {
rollData.possession = possession rollData.possession = possession
RdDPossession.$updateEtatPossession(rollData.possession) RdDPossession.$updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html') await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) { if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration // conjuration
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id]) victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
@ -230,7 +230,7 @@ export class RdDPossession {
system: { system: {
description: "", typepossession: attacker.name, description: "", typepossession: attacker.name,
possede: false, possede: false,
possessionid: randomID(16), possessionid: foundry.utils.randomID(16),
entite: { actorid: attacker.id }, entite: { actorid: attacker.id },
victime: { actorid: defender.id }, victime: { actorid: defender.id },
compteur: 0 compteur: 0

View File

@ -91,13 +91,14 @@ export class RdDResolutionTable {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') { static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
return await ChatUtility.createChatWithRollMode(RdDResolutionTable.actorChatName(actor), { return await ChatUtility.createChatWithRollMode(
content: await RdDResolutionTable.buildRollDataHtml(rollData, template) { content: await RdDResolutionTable.buildRollDataHtml(rollData, template) },
}); actor
)
} }
static actorChatName(actor) { static actorChatName(actor) {
return actor?.userName ?? game.user.name; return actor ?? game.user.name;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -138,14 +139,14 @@ export class RdDResolutionTable {
if (carac == 0) { if (carac == 0) {
return NaN; return NaN;
} }
if (rolled >= carac){ if (rolled >= carac) {
const upper = Math.ceil(rolled/carac); const upper = Math.ceil(rolled / carac);
return 2*upper -10 return 2 * upper - 10
} }
if (rolled > Math.floor(carac/2)) { if (rolled > Math.floor(carac / 2)) {
return -8 return -8
} }
if (rolled > Math.floor(carac/4)) { if (rolled > Math.floor(carac / 4)) {
return -9 return -9
} }
if (rolled > 1) { if (rolled > 1) {
@ -265,7 +266,7 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static subTable(carac, level, delta = { carac: 2, level: 5}) { static subTable(carac, level, delta = { carac: 2, level: 5 }) {
return { return {
carac, carac,
level, level,
@ -287,8 +288,8 @@ export class RdDResolutionTable {
carac: carac, carac: carac,
difficulte: level, difficulte: level,
min: minLevel, min: minLevel,
rows: Misc.intArray(minCarac, maxCarac+1), rows: Misc.intArray(minCarac, maxCarac + 1),
cols: Misc.intArray(minLevel, maxLevel+1) cols: Misc.intArray(minLevel, maxLevel + 1)
}); });
} }

View File

@ -72,6 +72,6 @@ export class RdDEncaisser extends Dialog {
encaisserSpecial: this.encaisserSpecial, encaisserSpecial: this.encaisserSpecial,
mortalite: mortalite mortalite: mortalite
} }
}); })
} }
} }

View File

@ -307,7 +307,7 @@ export class RdDRoll extends Dialog {
async updateRollResult(html) { async updateRollResult(html) {
const rollData = this.rollData; const rollData = this.rollData;
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat()) rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor)
rollData.caracValue = parseInt(rollData.selectedCarac.value) rollData.caracValue = parseInt(rollData.selectedCarac.value)
rollData.dmg.mortalite = rollData.dmg.mortalite ?? 'mortel'; rollData.dmg.mortalite = rollData.dmg.mortalite ?? 'mortel';
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac); rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);

View File

@ -16,7 +16,7 @@ import { RdDDice } from "./rdd-dice.js";
import { STATUSES } from "./settings/status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { RdDRencontre } from "./item/rencontre.js"; import { RdDRencontre } from "./item/rencontre.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js"; import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { TYPES } from "./item.js"; import { ITEM_TYPES } from "./item.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
const TMR_DISPLAY_SIZE = { const TMR_DISPLAY_SIZE = {
@ -34,7 +34,7 @@ const TMR_DISPLAY_SIZE = {
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDTMRDialog extends Dialog { export class RdDTMRDialog extends Dialog {
static async init() { static initSettings() {
game.settings.register(SYSTEM_RDD, TMR_DISPLAY_SIZE.code, { game.settings.register(SYSTEM_RDD, TMR_DISPLAY_SIZE.code, {
name: 'Taille des cases des TMR', name: 'Taille des cases des TMR',
hint: "Taille en pixel des cases des TMR (réglable directement dans la fenêtre des TMR)", hint: "Taille en pixel des cases des TMR (réglable directement dans la fenêtre des TMR)",
@ -50,7 +50,7 @@ export class RdDTMRDialog extends Dialog {
await PixiTMR.init() await PixiTMR.init()
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', tmrData); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', 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: ChatMessage.getWhisperRecipients("GM") }); ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() });
} }
return new RdDTMRDialog(html, actor, tmrData) return new RdDTMRDialog(html, actor, tmrData)
} }
@ -82,7 +82,7 @@ export class RdDTMRDialog extends Dialog {
this.rencontreState = 'aucune'; this.rencontreState = 'aucune';
this.subdialog = undefined this.subdialog = undefined
this.displaySize = undefined this.displaySize = undefined
if (!this.viewOnly) { if (!this.viewOnly && !game.user.isGM) {
this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")"); this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
} }
this.callbacksOnAnimate = []; this.callbacksOnAnimate = [];
@ -129,7 +129,7 @@ export class RdDTMRDialog extends Dialog {
this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop()); this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop());
// Roll Sort // Roll Sort
this.html.find('.lancer-sort').click(event => this.actor.rollUnSort(this._getCoordActor())); this.html.find('.lancer-sort').click(event => this.lancerUnSort());
this.html.find('.lire-signe-draconique').click(event => this.actor.rollLireSigneDraconique(this._getCoordActor())); this.html.find('.lire-signe-draconique').click(event => this.actor.rollLireSigneDraconique(this._getCoordActor()));
this.html.find('img.tmr-move').click(event => this.deplacementTMR(this.html.find(event.currentTarget)?.data('move'))); this.html.find('img.tmr-move').click(event => this.deplacementTMR(this.html.find(event.currentTarget)?.data('move')));
@ -142,6 +142,13 @@ export class RdDTMRDialog extends Dialog {
this.updateValuesDisplay(); this.updateValuesDisplay();
} }
lancerUnSort() {
if (this.subdialog) {
return this.forceTMRContinueAction();
}
return this.actor.rollUnSort(this._getCoordActor());
}
async onDeplacement() { async onDeplacement() {
await this.manageRencontre(TMRUtility.getTMR(this._getCoordActor())); await this.manageRencontre(TMRUtility.getTMR(this._getCoordActor()));
} }
@ -164,23 +171,25 @@ export class RdDTMRDialog extends Dialog {
async forceTMRDisplay() { async forceTMRDisplay() {
if (this.rendered) { if (this.rendered) {
this.bringToTop() this.bringToTop()
if (this.subdialog?.bringToTop) { this.bringSubDialogToTop();
this.subdialog.bringToTop();
} }
} }
bringSubDialogToTop() {
if (this.subdialog?.bringToTop && this.subdialog?.element[0]) {
this.subdialog.bringToTop();
}
} }
async restoreTMRAfterAction() { async restoreTMRAfterAction() {
this.subdialog = undefined this.subdialog = undefined
await this.maximize(); await this.maximize()
this.bringToTop(); this.bringToTop()
} }
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');
if (this.subdialog?.bringToTop) { this.bringSubDialogToTop();
this.subdialog.bringToTop();
}
return; return;
} }
@ -199,11 +208,11 @@ export class RdDTMRDialog extends Dialog {
} }
get sortsReserve() { get sortsReserve() {
return this.actor.itemTypes[TYPES.sortreserve]; return this.actor.itemTypes[ITEM_TYPES.sortreserve];
} }
getSortsReserve(coord) { getSortsReserve(coord) {
return this.actor.itemTypes[TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale return this.actor.itemTypes[ITEM_TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale
TMRUtility.getTMR(coord).type == 'fleuve' TMRUtility.getTMR(coord).type == 'fleuve'
? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve' ? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve'
: it => it.system.coord == coord : it => it.system.coord == coord
@ -261,7 +270,7 @@ export class RdDTMRDialog extends Dialog {
} }
_getTokensSortsReserve() { _getTokensSortsReserve() {
const sortsReserve = this.actor.itemTypes[TYPES.sortreserve]; const sortsReserve = this.actor.itemTypes[ITEM_TYPES.sortreserve];
return Misc.concat(sortsReserve.map(sortReserve => return Misc.concat(sortsReserve.map(sortReserve =>
EffetsDraconiques.sortReserve.tokens(this.pixiTMR, sortReserve, () => sortReserve.system.coord))) EffetsDraconiques.sortReserve.tokens(this.pixiTMR, sortReserve, () => sortReserve.system.coord)))
} }
@ -487,7 +496,7 @@ export class RdDTMRDialog extends Dialog {
rencData.message = this.formatMessageRencontre(rencData, result.message); rencData.message = this.formatMessageRencontre(rencData, result.message);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData)
}); });
@ -562,12 +571,20 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
_tellToGM(message) { _tellToGM(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: ChatMessage.getWhisperRecipients("GM") }); ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getGMs()
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_tellToUserAndGM(message) { _tellToUserAndGM(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id].concat(ChatMessage.getWhisperRecipients("GM")) }); ChatMessage.create({
user: game.user.id,
content: message,
whisper: ChatUtility.getUserAndGMs()
})
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -706,7 +723,7 @@ export class RdDTMRDialog extends Dialog {
} }
rollData.poesie = await Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
}); });
if (rollData.rolled.isEchec) { if (rollData.rolled.isEchec) {
@ -730,7 +747,7 @@ export class RdDTMRDialog extends Dialog {
if (this.isCaseMaitrisee(tmr.coord)) { if (this.isCaseMaitrisee(tmr.coord)) {
ChatMessage.create({ ChatMessage.create({
content: tmr.label + ": cette case humide est déja maitrisée grâce à votre Tête <strong>Quête des Eaux</strong>", content: tmr.label + ": cette case humide est déja maitrisée grâce à votre Tête <strong>Quête des Eaux</strong>",
whisper: ChatMessage.getWhisperRecipients(game.user.name) whisper: ChatUtility.getOwners(this.actor)
}); });
return false; return false;
} }
@ -742,14 +759,14 @@ export class RdDTMRDialog extends Dialog {
if (tmr.type == 'pont' && EffetsDraconiques.isPontImpraticable(this.actor)) { if (tmr.type == 'pont' && EffetsDraconiques.isPontImpraticable(this.actor)) {
ChatMessage.create({ ChatMessage.create({
content: tmr.label + ": Vous êtes sous le coup d'une Impraticabilité des Ponts : ce pont doit être maîtrisé comme une case humide.", content: tmr.label + ": Vous êtes sous le coup d'une Impraticabilité des Ponts : ce pont doit être maîtrisé comme une case humide.",
whisper: ChatMessage.getWhisperRecipients(game.user.name) whisper: ChatUtility.getOwners(this.actor)
}); });
return true; return true;
} }
if (this.isCaseInondee(tmr.coord)) { if (this.isCaseInondee(tmr.coord)) {
ChatMessage.create({ ChatMessage.create({
content: tmr.label + ": cette case est inondée, elle doit être maîtrisée comme une case humide.", content: tmr.label + ": cette case est inondée, elle doit être maîtrisée comme une case humide.",
whisper: ChatMessage.getWhisperRecipients(game.user.name) whisper: ChatUtility.getOwners(this.actor)
}); });
return true; return true;
} }
@ -823,7 +840,7 @@ export class RdDTMRDialog extends Dialog {
} }
rollData.poesie = await Poetique.getExtrait(); rollData.poesie = await Poetique.getExtrait();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
}); });
if (rollData.rolled.isEchec) { if (rollData.rolled.isEchec) {
@ -873,17 +890,16 @@ export class RdDTMRDialog extends Dialog {
const reserveSecurite = EffetsDraconiques.isReserveEnSecurite(this.actor); const reserveSecurite = EffetsDraconiques.isReserveEnSecurite(this.actor);
const reserveExtensible = this.isReserveExtensible(coord); const reserveExtensible = this.isReserveExtensible(coord);
if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && (reserveSecurite || reserveExtensible)) { if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && (reserveSecurite || reserveExtensible)) {
const msg = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-demande-declencher-sort.hbs`, { ChatMessage.create({
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-demande-declencher-sort.hbs`, {
actor: this.actor, actor: this.actor,
sorts: sorts, sorts: sorts,
coord: coord, coord: coord,
tete: { reserveSecurite: reserveSecurite, reserveExtensible: reserveExtensible } tete: { reserveSecurite: reserveSecurite, reserveExtensible: reserveExtensible }
}),
whisper: ChatUtility.getOwners(this.actor)
}) })
ChatMessage.create({ return
content: msg,
whisper: ChatMessage.getWhisperRecipients(game.user.name)
});
return;
} }
await this.processSortReserve(sorts[0]); await this.processSortReserve(sorts[0]);
} }
@ -897,9 +913,8 @@ export class RdDTMRDialog extends Dialog {
this.processSortReserve(sort); this.processSortReserve(sort);
} else { } else {
ChatMessage.create({ ChatMessage.create({
content: content: "Une erreur est survenue : impossible de récupérer le sort en réserve demandé.",
"Une erreur est survenue : impossible de récupérer le sort en réserve demandé.", whisper: ChatUtility.getOwners(this.actor)
whisper: ChatMessage.getWhisperRecipients(game.user.name),
}); });
} }
} }
@ -1082,7 +1097,7 @@ export class RdDTMRDialog extends Dialog {
async notifierResonanceSigneDraconique(coord) { async notifierResonanceSigneDraconique(coord) {
if (!this.viewOnly && this.actor.isResonanceSigneDraconique(coord)) { if (!this.viewOnly && this.actor.isResonanceSigneDraconique(coord)) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(this.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) }) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) })
}); });
} }

View File

@ -28,16 +28,15 @@ export class RdDTokenHud {
await RdDTokenHud.addExtensionHudSoins(html, actor); await RdDTokenHud.addExtensionHudSoins(html, actor);
if (isCombat) { if (isCombat) {
let combatant = game.combat.combatants.find(c => c.tokenId == tokenId); const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
if (!(combatant?.actor)) { const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
ui.notifications.warn(`Le combatant ${token.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) if (actor) {
return; let actions = RdDCombatManager.listActionsActorCombatant(actor)
}
let actions = RdDCombatManager.listActionsCombat(combatant);
// initiative // initiative
await RdDTokenHud.addExtensionHudInit(html, combatant, actions); await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
// combat // combat
await RdDTokenHud.addExtensionHudCombat(html, combatant, actions); await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions)
}
} }
@ -68,8 +67,8 @@ export class RdDTokenHud {
}); });
} }
static async addExtensionHudCombat(html, combatant, actions) { static async addExtensionHudCombat(html, combatant, token, actions) {
const hudData = { combatant, actions, commandes: [] }; const hudData = { combatant, token, actions, commandes: [] };
const controlIconTarget = html.find('.control-icon[data-action=target]'); const controlIconTarget = html.find('.control-icon[data-action=target]');
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData, await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => { (event) => {
@ -80,7 +79,7 @@ export class RdDTokenHud {
combatant.actor.conjurerPossession(possession); combatant.actor.conjurerPossession(possession);
} }
else { else {
combatant.actor.rollArme(action); combatant.actor.rollArme(action, 'competence', token)
} }
}); });
} }

View File

@ -4,7 +4,7 @@ import { RdDCombat } from "./rdd-combat.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { DialogItemAchat } from "./dialog-item-achat.js"; import { DialogItemAchat } from "./achat-vente/dialog-item-achat.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"; import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js";
@ -19,6 +19,7 @@ import { RdDEmpoignade } from "./rdd-empoignade.js";
import { ExperienceLog } from "./actor/experience-log.js"; import { ExperienceLog } from "./actor/experience-log.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js"; import { RdDCoeur } from "./coeur/rdd-coeur.js";
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js"; import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
import { RDD_CONFIG } from "./constants.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@ -98,9 +99,7 @@ export class RdDUtility {
// persistent handling of conteneur show/hide // persistent handling of conteneur show/hide
static afficheContenu = {} static afficheContenu = {}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async init() { static async initHooks() {
Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg))
Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id))
Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html)) Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html))
} }
@ -262,8 +261,6 @@ export class RdDUtility {
]; ];
Handlebars.registerHelper('either', (a, b) => a ?? b); Handlebars.registerHelper('either', (a, b) => a ?? b);
Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col));
Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col));
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null')); Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null')); Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null'));
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? ''); Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? '');
@ -272,6 +269,10 @@ export class RdDUtility {
Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str)); Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str));
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str)); Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args)); Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col));
Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col));
Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); }); Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); });
Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); }); Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); });
Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); }); Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); });
@ -289,6 +290,7 @@ export class RdDUtility {
Handlebars.registerHelper('array-includes', (array, value) => array.includes(value)); Handlebars.registerHelper('array-includes', (array, value) => array.includes(value));
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('isLastIndex', (index, list) => index + 1 >= list.length);
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option)); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name))); Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name)));
Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences)); Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences));
@ -300,6 +302,14 @@ export class RdDUtility {
Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff)) Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff))
Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic)); Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic));
// Handle v12 removal of this helper
Handlebars.registerHelper('select', function (selected, options) {
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
const html = options.fn(this);
return html.replace(rgx, "$& selected");
});
return loadTemplates(templatePaths); return loadTemplates(templatePaths);
} }
@ -347,16 +357,18 @@ export class RdDUtility {
let objetVersConteneur = {}; let objetVersConteneur = {};
// Attribution des objets aux conteneurs // Attribution des objets aux conteneurs
for (let conteneur of conteneurs) { for (let conteneur of conteneurs) {
if (conteneur.isConteneur()) {
conteneur.subItems = []; conteneur.subItems = [];
for (let id of conteneur.system.contenu ?? []) { for (let id of conteneur.system.contenu ?? []) {
let objet = inventaires.find(objet => (id == objet._id)); let objet = inventaires.find(objet => (id == objet._id));
if (objet) { if (objet) {
objet.estContenu = true; // Permet de filtrer ce qui est porté dans le template objet.estContenu = true;
objetVersConteneur[id] = conteneur._id; objetVersConteneur[id] = conteneur._id;
conteneur.subItems.push(objet); conteneur.subItems.push(objet);
} }
} }
} }
}
for (let conteneur of conteneurs) { for (let conteneur of conteneurs) {
conteneur.system.encTotal = RdDUtility.calculEncContenu(conteneur, inventaires); conteneur.system.encTotal = RdDUtility.calculEncContenu(conteneur, inventaires);
} }
@ -551,14 +563,14 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async jetEncaissement(rollData, armure, options = { showDice: HIDE_DICE }) { static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
const diff = Math.abs(rollData.diffLibre); const diff = Math.abs(rollData.diffLibre);
let formula = RdDUtility.formuleEncaissement(diff, options) let formula = RdDUtility.formuleEncaissement(diff, options)
const roll = await RdDDice.roll(formula, options); const roll = await RdDDice.roll(formula, options);
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options); RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
return await RdDUtility.prepareEncaissement(rollData, roll, armure); return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
} }
static remplaceDeMinParDifficulte(roll, diff, options) { static remplaceDeMinParDifficulte(roll, diff, options) {
@ -590,15 +602,20 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async prepareEncaissement(rollData, roll, armure) { static async prepareEncaissement(actor, rollData, roll, armure) {
// La difficulté d'ataque s'ajoute aux dégâts // La difficulté d'ataque s'ajoute aux dégâts
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0 const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite); const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
const over20 = Math.max(jetTotal - 20, 0); const over20 = Math.max(jetTotal - 20, 0);
encaissement.dmg = rollData.dmg; encaissement.dmg = rollData.dmg
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(this.type); if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'; encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
}
else {
encaissement.dmg.loc = { label: '' }
}
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
encaissement.roll = roll; encaissement.roll = roll;
encaissement.armure = armure; encaissement.armure = armure;
@ -624,25 +641,23 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async _evaluatePerte(formula, over20) { static async _evaluatePerte(formula, over20) {
let perte = new Roll(formula, { over20: over20 }); let perte = new Roll(formula, { over20: over20 });
await perte.evaluate({ async: true }); await perte.evaluate();
return perte.total; return perte.total;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static onSocketMessage(sockmsg) { static onSocketMessage(sockmsg) {
switch (sockmsg.msg) { switch (sockmsg.msg) {
case "msg_gm_chat_message":
return ChatUtility.handleGMChatMessage(sockmsg.data);
case "msg_app_astrologie_refresh": case "msg_app_astrologie_refresh":
return Hooks.callAll(APP_ASTROLOGIE_REFRESH); return Hooks.callAll(APP_ASTROLOGIE_REFRESH)
case "msg_request_nombre_astral": case "msg_request_nombre_astral":
return game.system.rdd.calendrier.requestNombreAstral(sockmsg.data); return game.system.rdd.calendrier.requestNombreAstral(sockmsg.data)
case "msg_tmr_move": case "msg_tmr_move":
let actor = game.actors.get(sockmsg.data.actorId); let actor = game.actors.get(sockmsg.data.actorId);
if (actor.isOwner || game.user.isGM) { if (actor.isOwner || game.user.isGM) {
actor.refreshTMRView(); actor.refreshTMRView()
} }
break; break
} }
} }
@ -731,6 +746,15 @@ export class RdDUtility {
return undefined; return undefined;
} }
static getSelectedToken(actor) {
if (canvas.tokens.controlled.length > 0) {
const tokens = canvas.tokens.controlled
.filter(it => it.actor.id == actor.id)
return tokens[0]
}
return undefined
}
static getSelectedActor(msgPlayer = undefined) { static getSelectedActor(msgPlayer = undefined) {
if (canvas.tokens.controlled.length == 1) { if (canvas.tokens.controlled.length == 1) {
let token = canvas.tokens.controlled[0]; let token = canvas.tokens.controlled[0];
@ -756,7 +780,7 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static createMonnaie(name, cout, img = "", enc = 0.01) { static createMonnaie(name, cout, img = "", enc = 0.01) {
let piece = { let piece = {
name: name, type: 'monnaie', img: img, _id: randomID(16), name: name, type: 'monnaie', img: img, _id: foundry.utils.randomID(16),
dasystemta: { dasystemta: {
quantite: 0, quantite: 0,
cout: cout, cout: cout,
@ -794,17 +818,13 @@ export class RdDUtility {
user: game.user.id, user: game.user.id,
rollMode: modeOverride || game.settings.get("core", "rollMode"), rollMode: modeOverride || game.settings.get("core", "rollMode"),
content: content content: content
}; }
ChatUtility.applyRollMode(chatData)
if (["gmroll", "blindroll"].includes(chatData.rollMode)) chatData["whisper"] = ChatMessage.getWhisperRecipients("GM").map(u => u.id);
if (chatData.rollMode === "blindroll") chatData["blind"] = true;
else if (chatData.rollMode === "selfroll") chatData["whisper"] = [game.user];
if (forceWhisper) { // Final force ! if (forceWhisper) { // Final force !
chatData["speaker"] = ChatMessage.getSpeaker(); chatData.speaker = ChatMessage.getSpeaker();
chatData["whisper"] = ChatMessage.getWhisperRecipients(forceWhisper); chatData.whisper = ChatMessage.getWhisperRecipients(forceWhisper);
} }
return chatData; return chatData;
} }
@ -861,13 +881,13 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static afficherHeuresChanceMalchance(heureNaissance) { static afficherHeuresChanceMalchance(heureNaissance) {
if (game.user.isGM) { if (game.user.isGM) {
const heure = RdDTimestamp.findHeure(heureNaissance - 1); const heure = RdDTimestamp.findHeure(heureNaissance)
if (heureNaissance && heure) { if (heureNaissance && heure) {
let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance); const ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance)
const current = game.system.rdd.calendrier.heureCourante(); const current = game.system.rdd.calendrier.heureCourante()
ChatMessage.create({ ChatMessage.create({
content: `A l'heure de <strong>${current.label}</strong>, le modificateur de Chance/Malchance est de <strong>${Misc.toSignedString(ajustement)}</strong> pour l'heure de naissance <strong>${heure.label}</strong>.`, content: `A l'heure de <strong>${current.label}</strong>, le modificateur de Chance/Malchance est de <strong>${Misc.toSignedString(ajustement)}</strong> pour l'heure de naissance <strong>${heure.label}</strong>.`,
whisper: ChatMessage.getWhisperRecipients("GM") whisper: ChatUtility.getGMs()
}); });
} }
else if (heureNaissance) { else if (heureNaissance) {
@ -886,7 +906,7 @@ export class RdDUtility {
if (compName.includes('Thanatos')) { if (compName.includes('Thanatos')) {
let message = "Vous avez mis des points d'Expérience dans la Voie de Thanatos !<br>Vous devez réduire manuellement d'un même montant d'XP une autre compétence Draconique."; let message = "Vous avez mis des points d'Expérience dans la Voie de Thanatos !<br>Vous devez réduire manuellement d'un même montant d'XP une autre compétence Draconique.";
ChatMessage.create({ ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients(game.user.name), whisper: ChatUtility.getUserAndGMs(),
content: message content: message
}); });
} }

View File

@ -111,7 +111,7 @@ export const referenceAjustements = {
isVisible: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0, isVisible: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0,
isUsed: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0, isUsed: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0,
getLabel: (rollData, actor) => "Ecaille d'Efficacité: ", getLabel: (rollData, actor) => "Ecaille d'Efficacité: ",
getValue: (rollData, actor) => Math.max(Number(rollData.arme?.system.ecaille_efficacite), 0), getValue: (rollData, actor) => rollData.arme?.system.magique ? Math.max(Number(rollData.arme?.system.ecaille_efficacite), 0) : 0,
}, },
finesse: { finesse: {
isUsed: (rollData, actor) => RdDBonus.isDefenseAttaqueFinesse(rollData), isUsed: (rollData, actor) => RdDBonus.isDefenseAttaqueFinesse(rollData),

View File

@ -0,0 +1,91 @@
import { SYSTEM_RDD } from "../constants.js"
import { Misc } from "../misc.js"
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
const OPTIONS_AVANCEES = [
{ group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium" },
]
export class OptionsAvancees extends FormApplication {
static initSettings() {
for (const regle of OPTIONS_AVANCEES) {
const name = regle.name
const id = OptionsAvancees._getId(name)
game.settings.register(SYSTEM_RDD, id, { name: id, scope: regle.scope ?? "world", config: false, default: regle.default == undefined ? true : regle.default, type: Boolean })
}
game.settings.registerMenu(SYSTEM_RDD, "rdd-options-avancees", {
name: "Configurer les options avancées",
label: "Options avancées",
hint: "Ouvre la fenêtre de configuration des options avancées",
icon: "fas fa-bars",
type: OptionsAvancees
})
}
constructor(...args) {
super(...args)
}
static _getId(name) {
return `rdd-advanced-${name}`
}
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "options-avancees",
template: "systems/foundryvtt-reve-de-dragon/templates/settings/options-avancees.hbs",
height: 650,
width: 550,
minimizable: false,
closeOnSubmit: true,
title: "Options avancées"
}, { inplace: false })
}
getData() {
let formData = super.getData()
const regles = OPTIONS_AVANCEES.filter(it => game.user.isGM || it.scope == "client")
.map(it => {
it = foundry.utils.duplicate(it)
it.id = OptionsAvancees._getId(it.name)
it.active = OptionsAvancees.isSet(it.name)
return it
})
formData.regles = regles
formData.groups = Misc.classify(regles, it => it.group)
return formData
}
static getSettingKey(name){
return `${SYSTEM_RDD}.${this._getId(name)}`
}
static isUsing(name) {
return OptionsAvancees.isSet(name)
}
static isSet(name) {
return game.settings.get(SYSTEM_RDD, OptionsAvancees._getId(name))
}
static set(name, value) {
return game.settings.set(SYSTEM_RDD, OptionsAvancees._getId(name), value ? true : false)
}
activateListeners(html) {
html.find(".select-option").click((event) => {
if (event.currentTarget.attributes.name) {
let id = event.currentTarget.attributes.name.value
let isChecked = event.currentTarget.checked
game.settings.set(SYSTEM_RDD, id, isChecked)
}
})
}
async _updateObject(event, formData) {
this.close()
}
}

View File

@ -11,6 +11,7 @@ const listeReglesOptionnelles = [
{ group: 'Récupération', name: 'recuperation-moral', descr: "Le moral revient vers 0 durant Château Dormant"}, { group: 'Récupération', name: 'recuperation-moral', descr: "Le moral revient vers 0 durant Château Dormant"},
{ group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" },
{ group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" }, { group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
{ group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" }, { group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
{ group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" }, { group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },
@ -46,7 +47,7 @@ const listeReglesOptionnelles = [
const uniquementJoueur = listeReglesOptionnelles.filter(it => it.uniquementJoueur).map(it=>it.name); const uniquementJoueur = listeReglesOptionnelles.filter(it => it.uniquementJoueur).map(it=>it.name);
export class ReglesOptionnelles extends FormApplication { export class ReglesOptionnelles extends FormApplication {
static init() { static initSettings() {
for (const regle of listeReglesOptionnelles) { for (const regle of listeReglesOptionnelles) {
const name = regle.name; const name = regle.name;
const id = ReglesOptionnelles._getIdRegle(name); const id = ReglesOptionnelles._getIdRegle(name);
@ -71,17 +72,15 @@ export class ReglesOptionnelles extends FormApplication {
} }
static get defaultOptions() { static get defaultOptions() {
const options = super.defaultOptions; return foundry.utils.mergeObject(super.defaultOptions, {
foundry.utils.mergeObject(options, {
id: "regles-optionnelles", id: "regles-optionnelles",
template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionnelles.html", template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionnelles.hbs",
height: 650, height: 650,
width: 550, width: 550,
minimizable: false, minimizable: false,
closeOnSubmit: true, closeOnSubmit: true,
title: "Règles optionnelles" title: "Règles optionnelles"
}); }, { inplace: false })
return options;
} }
getData() { getData() {

View File

@ -1,3 +1,4 @@
import { ChatUtility } from "../chat-utility.js";
import { HIDE_DICE, SYSTEM_RDD } from "../constants.js"; import { HIDE_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItem } from "../item.js"; import { RdDItem } from "../item.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
@ -24,7 +25,7 @@ const CONFIGURABLE_COMPENDIUMS = {
* ======= Gestion des accès aux compendiums systèmes (ou surchargés) ======= * ======= Gestion des accès aux compendiums systèmes (ou surchargés) =======
*/ */
export class SystemCompendiums extends FormApplication { export class SystemCompendiums extends FormApplication {
static init() { static initSettings() {
Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => { Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => {
const definition = CONFIGURABLE_COMPENDIUMS[compendium]; const definition = CONFIGURABLE_COMPENDIUMS[compendium];
foundry.utils.mergeObject(definition, { foundry.utils.mergeObject(definition, {
@ -152,7 +153,7 @@ export class SystemCompendiums extends FormApplication {
getData() { getData() {
const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS) const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS)
.map(it => foundry.utils.mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) })); .map(it => foundry.utils.mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) }, { inplace: false }))
const availableCompendiums = game.packs.map(pack => { const availableCompendiums = game.packs.map(pack => {
return { return {
name: pack.collection, name: pack.collection,
@ -163,7 +164,7 @@ export class SystemCompendiums extends FormApplication {
return foundry.utils.mergeObject(super.getData(), { return foundry.utils.mergeObject(super.getData(), {
systemCompendiums: systemCompendiums, systemCompendiums: systemCompendiums,
availableCompendiums: availableCompendiums availableCompendiums: availableCompendiums
}); }, { inplace: false })
} }
activateListeners(html) { activateListeners(html) {
@ -235,12 +236,12 @@ export class CompendiumTableHelpers {
let max = 0; let max = 0;
const total = rows.map(it => it.frequence).reduce(Misc.sum(), 0); const total = rows.map(it => it.frequence).reduce(Misc.sum(), 0);
return rows.map(row => { return rows.map(row => {
const frequence = row.frequence; const frequence = row.frequence
row.min = max + 1; row.min = max + 1
row.max = max + frequence; row.max = max + frequence
row.total = total row.total = total
max += frequence; max += frequence
return row; return row
}) })
} }
static async getRandom(table, type, subTypes = ['objet'], forcedRoll = undefined, localisation = undefined) { static async getRandom(table, type, subTypes = ['objet'], forcedRoll = undefined, localisation = undefined) {
@ -259,8 +260,8 @@ export class CompendiumTableHelpers {
} }
const total = table[0].total; const total = table[0].total;
const formula = `1d${total}`; const formula = `1d${total}`;
if (forcedRoll == undefined && (forcedRoll > total || forcedRoll <= 0)) { if (forcedRoll != undefined && (forcedRoll > total || forcedRoll <= 0)) {
ui.notifications.warn(`Jet de rencontre ${forcedRoll} en dehors de la table [1..${total}], le jet est relancé`); ui.notifications.warn(`Jet forcé ${forcedRoll} en dehors de la table [1..${total}], le jet est relancé`);
forcedRoll = undefined; forcedRoll = undefined;
} }
const roll = forcedRoll ? { total: forcedRoll, formula } : await RdDDice.roll(formula, { showDice: HIDE_DICE }); const roll = forcedRoll ? { total: forcedRoll, formula } : await RdDDice.roll(formula, { showDice: HIDE_DICE });
@ -275,7 +276,7 @@ export class CompendiumTableHelpers {
return; return;
} }
const percentages = (row.total == 100) ? '%' : '' const percentages = (row.total == 100) ? '%' : ''
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.html', { const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.hbs', {
roll: row.roll, roll: row.roll,
document: row.document, document: row.document,
percentages, percentages,
@ -290,12 +291,12 @@ export class CompendiumTableHelpers {
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
content: flavorContent content: flavorContent
}; };
ChatMessage.create(messageData, { rollMode: "gmroll" }); await ChatUtility.createChatWithRollMode(messageData)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async tableToChatMessage(table, type, subTypes, typeName = undefined) { static async tableToChatMessage(table, type, subTypes, typeName = undefined) {
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.html', { const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.hbs', {
img: RdDItem.getDefaultImg(subTypes[0]), img: RdDItem.getDefaultImg(subTypes[0]),
typeName: typeName ?? Misc.typeName(type, subTypes[0]), typeName: typeName ?? Misc.typeName(type, subTypes[0]),
table, table,
@ -303,10 +304,10 @@ export class CompendiumTableHelpers {
}); });
const messageData = { const messageData = {
user: game.user.id, user: game.user.id,
whisper: game.user.id, whisper: [game.user],
content: flavorContent content: flavorContent
}; };
ChatMessage.create(messageData, { rollMode: "gmroll" }); await ChatUtility.createChatWithRollMode(messageData)
} }
} }

View File

@ -25,7 +25,7 @@ export class AppAstrologie extends Application {
classes: ['calendar-astrologie'], classes: ['calendar-astrologie'],
popOut: true, popOut: true,
resizable: false resizable: false
}); }, { inplace: false })
} }
constructor(actor, options = {}) { constructor(actor, options = {}) {
@ -49,7 +49,7 @@ export class AppAstrologie extends Application {
signeNaissance: RdDTimestamp.definition(0) signeNaissance: RdDTimestamp.definition(0)
} }
}) })
return this.appData; return this.appData
} }
getActorAstrologie() { getActorAstrologie() {
@ -186,7 +186,7 @@ export class AppAstrologie extends Application {
date: this.html.find('[name="joursAstrologie"]').val(), date: this.html.find('[name="joursAstrologie"]').val(),
userId: game.user.id userId: game.user.id
} }
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
game.system.rdd.calendrier.requestNombreAstral(socketData); game.system.rdd.calendrier.requestNombreAstral(socketData);
} else { } else {
game.socket.emit(SYSTEM_SOCKET_ID, { game.socket.emit(SYSTEM_SOCKET_ID, {

View File

@ -13,18 +13,21 @@ export class Targets {
static extractTokenData(target) { static extractTokenData(target) {
return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' }; return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' };
} }
static buildActorTokenData(tokenId, actor) {
return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' };
}
static isTargetEntite(target) { static isTargetEntite(target) {
return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE; return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
} }
static async selectOneToken(onSelectTarget = target => { }) { static async selectOneTargetToken(onSelectTarget = target => { }) {
const targets = Targets.listTargets(); const targets = Targets.listTargets()
switch (targets.length) { switch (targets.length) {
case 0: return; case 0:
return
case 1: case 1:
onSelectTarget(targets[0]); onSelectTarget(targets[0])
return; return
default: default:
{ {
const selectData = { const selectData = {
@ -32,7 +35,7 @@ export class Targets {
label: "Choisir une seule des cibles", label: "Choisir une seule des cibles",
list: targets.map(it => Targets.extractTokenData(it)) list: targets.map(it => Targets.extractTokenData(it))
}; };
DialogSelect.select(selectData, onSelectTarget); DialogSelect.select(selectData, onSelectTarget)
} }
} }
} }

View File

@ -4,7 +4,7 @@ export const AUTO_ADJUST_DARKNESS = "auto-adjust-darkness";
export class AutoAdjustDarkness { export class AutoAdjustDarkness {
static init() { static initSettings() {
game.settings.register(SYSTEM_RDD, AUTO_ADJUST_DARKNESS, { game.settings.register(SYSTEM_RDD, AUTO_ADJUST_DARKNESS, {
name: AUTO_ADJUST_DARKNESS, name: AUTO_ADJUST_DARKNESS,
scope: "world", scope: "world",
@ -15,9 +15,9 @@ export class AutoAdjustDarkness {
} }
static async adjust(darkness) { static async adjust(darkness) {
if (AutoAdjustDarkness.isAuto()) { if (game.user.isGM && AutoAdjustDarkness.isAuto()) {
const scene = game.scenes.viewed; const scene = game.scenes.viewed;
if (scene?.globalLight && scene?.tokenVision) { if (scene?.environment?.globalLight?.enabled && scene?.tokenVision) {
await scene.update({ darkness }); await scene.update({ darkness });
} }
} }

View File

@ -1,7 +1,6 @@
import { MAX_NOMBRE_ASTRAL, RdDTimestamp, WORLD_TIMESTAMP_SETTING } from "./rdd-timestamp.js"; import { MAX_NOMBRE_ASTRAL, RdDTimestamp, WORLD_TIMESTAMP_SETTING } from "./rdd-timestamp.js";
import { RdDCalendrierEditor } from "./rdd-calendrier-editor.js"; import { RdDCalendrierEditor } from "./rdd-calendrier-editor.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js"; import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDDice } from "../rdd-dice.js"; import { RdDDice } from "../rdd-dice.js";
import { Misc } from "../misc.js"; import { Misc } from "../misc.js";
import { DialogChronologie } from "../dialog-chronologie.js"; import { DialogChronologie } from "../dialog-chronologie.js";
@ -16,7 +15,7 @@ const TEMPLATE_CALENDRIER = "systems/foundryvtt-reve-de-dragon/templates/time/ca
const INITIAL_CALENDAR_POS = { top: 200, left: 200, horlogeAnalogique: true }; const INITIAL_CALENDAR_POS = { top: 200, left: 200, horlogeAnalogique: true };
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDCalendrier extends Application { export class RdDCalendrier extends Application {
static init() { static initSettings() {
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", { game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
name: "liste-nombre-astral", name: "liste-nombre-astral",
scope: "world", scope: "world",
@ -43,13 +42,13 @@ export class RdDCalendrier extends Application {
resizable: false, resizable: false,
width: 'fit-content', width: 'fit-content',
height: 'fit-content', height: 'fit-content',
}); }, { inplace: false })
} }
constructor() { constructor() {
super(); super();
this.timestamp = RdDTimestamp.getWorldTime(); this.timestamp = RdDTimestamp.getWorldTime();
if (Misc.isUniqueConnectedGM()) { // Uniquement si GM if (Misc.isFirstConnectedGM()) { // Uniquement si GM
RdDTimestamp.setWorldTime(this.timestamp); RdDTimestamp.setWorldTime(this.timestamp);
this.rebuildNombresAstraux(); // Ensure always up-to-date this.rebuildNombresAstraux(); // Ensure always up-to-date
} }
@ -123,9 +122,9 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
fillCalendrierData(formData = {}) { fillCalendrierData(formData = {}) {
foundry.utils.mergeObject(formData, this.timestamp.toCalendrier()); foundry.utils.mergeObject(formData, this.timestamp.toCalendrier());
formData.isGM = game.user.isGM; formData.isGM = game.user.isGM
formData.heures = RdDTimestamp.definitions() formData.heures = RdDTimestamp.definitions()
formData.horlogeAnalogique = this.horlogeAnalogique; formData.horlogeAnalogique = this.horlogeAnalogique
formData.autoDarkness = AutoAdjustDarkness.isAuto() formData.autoDarkness = AutoAdjustDarkness.isAuto()
return formData; return formData;
} }
@ -228,7 +227,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
async ajouterNombreAstral(indexDate) { async ajouterNombreAstral(indexDate) {
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: HIDE_DICE, rollMode: "selfroll" }); const nombreAstral = await RdDDice.rollHeure( { showDice: HIDE_DICE, rollMode: "selfroll" });
return { return {
nombreAstral: nombreAstral, nombreAstral: nombreAstral,
lectures: [], lectures: [],
@ -259,7 +258,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
async rebuildNombresAstraux() { async rebuildNombresAstraux() {
if (Misc.isUniqueConnectedGM()) { if (Misc.isFirstConnectedGM()) {
const nombresAstraux = this.getNombresAstraux() const nombresAstraux = this.getNombresAstraux()
let newNombresAstraux = []; let newNombresAstraux = [];
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) { for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
@ -338,7 +337,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
async requestNombreAstral(request) { async requestNombreAstral(request) {
const actor = game.actors.get(request.id); const actor = game.actors.get(request.id);
if (Misc.isUniqueConnectedGM()) { // Only once if (Misc.isFirstConnectedGM()) { // Only once
console.log(request); console.log(request);
let jourDiff = this.getLectureAstrologieDifficulte(request.date); let jourDiff = this.getLectureAstrologieDifficulte(request.date);
let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat); let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);

View File

@ -15,18 +15,18 @@ export const RDD_MINUTES_PAR_JOUR = 1440; //RDD_HEURES_PAR_JOUR * RDD_MINUTES_PA
const ROUNDS_PAR_MINUTE = 10; const ROUNDS_PAR_MINUTE = 10;
const DEFINITION_HEURES = [ const DEFINITION_HEURES = [
{ key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 }, { key: "vaisseau", article: "du ", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 },
{ key: "sirene", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 }, { key: "sirene", article: "de la ", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 },
{ key: "faucon", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 }, { key: "faucon", article: "du ", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 },
{ key: "couronne", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 }, { key: "couronne", article: "de la ", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 },
{ key: "dragon", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 }, { key: "dragon", article: "du ", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 },
{ key: "epees", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 }, { key: "epees", article: "des ", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 },
{ key: "lyre", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 }, { key: "lyre", article: "de la ", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 },
{ key: "serpent", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 }, { key: "serpent", article: "du ", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 },
{ key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 }, { key: "poissonacrobate", article: "du ", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 },
{ key: "araignee", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 }, { key: "araignee", article: "de l'", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 },
{ key: "roseau", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 }, { key: "roseau", article: "du ", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 },
{ key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 }, { key: "chateaudormant", article: "du ", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 },
] ]
const FORMULES_DUREE = [ const FORMULES_DUREE = [
@ -49,7 +49,7 @@ const FORMULES_PERIODE = [
export class RdDTimestamp { export class RdDTimestamp {
static init() { static initSettings() {
game.settings.register(SYSTEM_RDD, WORLD_TIMESTAMP_SETTING, { game.settings.register(SYSTEM_RDD, WORLD_TIMESTAMP_SETTING, {
name: WORLD_TIMESTAMP_SETTING, name: WORLD_TIMESTAMP_SETTING,
scope: "world", scope: "world",
@ -64,6 +64,7 @@ export class RdDTimestamp {
DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i); DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i);
DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i); DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i);
DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp"); DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp");
DEFINITION_HEURES[i].avecArticle = DEFINITION_HEURES[i].article + DEFINITION_HEURES[i].label
} }
} }
@ -159,15 +160,21 @@ export class RdDTimestamp {
} }
static findHeure(heure) { static findHeure(heure) {
heure = Grammar.toLowerCaseNoAccentNoSpace(heure); let filtered
let parHeureOuLabel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR)); if (Number.isInteger(Number(heure))) {
if (parHeureOuLabel.length == 1) { filtered = DEFINITION_HEURES.filter(it => it.heure == Misc.modulo(Number(heure) - 1, RDD_HEURES_PAR_JOUR))
return parHeureOuLabel[0];
} }
let parLabelPartiel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure)); else {
if (parLabelPartiel.length > 0) { heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
parLabelPartiel.sort(Misc.ascending(h => h.label.length)); filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR));
return parLabelPartiel[0]; }
if (filtered.length == 1) {
return filtered[0]
}
filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
if (filtered.length > 0) {
filtered.sort(Misc.ascending(h => h.label.length));
return filtered[0]
} }
return undefined; return undefined;
} }

View File

@ -125,7 +125,7 @@ export class FenetreRechercheTirage extends Application {
popOut: true, popOut: true,
dragDrop: [{ dragSelector: "a.content-link" }], dragDrop: [{ dragSelector: "a.content-link" }],
resizable: true resizable: true
}); }, { inplace: false })
} }
static async create() { static async create() {

View File

@ -105,7 +105,7 @@ export class TMRRencontres {
/* -------------------------------------------- */ /* -------------------------------------------- */
async $chatRolledRencontre(row, rencontre, tmr) { async $chatRolledRencontre(row, rencontre, tmr) {
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.html', const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.hbs',
{ {
roll: row.roll, roll: row.roll,
rencontre, rencontre,

View File

@ -1,4 +1,4 @@
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { TMRUtility } from "../tmr-utility.js"; import { TMRUtility } from "../tmr-utility.js";
import { PixiTMR } from "./pixi-tmr.js"; import { PixiTMR } from "./pixi-tmr.js";
@ -12,10 +12,10 @@ export class Draconique {
static init() { static init() {
} }
static isCaseTMR(item) { return item.type == TYPES.casetmr; } static isCaseTMR(item) { return item.type == ITEM_TYPES.casetmr; }
static isQueueDragon(item) { return item.isQueueDragon(); } static isQueueDragon(item) { return item.isQueueDragon(); }
static isSouffleDragon(item) { return item.type == TYPES.souffle; } static isSouffleDragon(item) { return item.type == ITEM_TYPES.souffle; }
static isTeteDragon(item) { return item.type == TYPES.tete; } static isTeteDragon(item) { return item.type == ITEM_TYPES.tete; }
static isQueueSouffle(item) { return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item); } static isQueueSouffle(item) { return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item); }
static register(draconique, code = undefined) { static register(draconique, code = undefined) {

View File

@ -18,7 +18,7 @@ import { Periple } from "./periple.js";
import { UrgenceDraconique } from "./urgence-draconique.js"; import { UrgenceDraconique } from "./urgence-draconique.js";
import { Grammar } from "../grammar.js"; import { Grammar } from "../grammar.js";
import { AugmentationSeuil } from "./augmentation-seuil.js"; import { AugmentationSeuil } from "./augmentation-seuil.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
export class EffetsDraconiques { export class EffetsDraconiques {
static carteTmr = new CarteTmr(); static carteTmr = new CarteTmr();
@ -122,11 +122,11 @@ export class EffetsDraconiques {
} }
static tetesDragon(actor, name) { static tetesDragon(actor, name) {
return actor.itemTypes[TYPES.tete].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name)); return actor.itemTypes[ITEM_TYPES.tete].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
} }
static soufflesDragon(actor, name) { static soufflesDragon(actor, name) {
return actor.itemTypes[TYPES.souffle].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name)); return actor.itemTypes[ITEM_TYPES.souffle].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
} }
static queuesDragon(actor, name) { static queuesDragon(actor, name) {
@ -134,7 +134,7 @@ export class EffetsDraconiques {
} }
static queuesSoufflesDragon(actor, name) { static queuesSoufflesDragon(actor, name) {
return actor.filterItems(it => [TYPES.queue, TYPES.ombre, TYPES.souffle].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, name)); return actor.filterItems(it => [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, name));
} }
static countAugmentationSeuil(actor) { static countAugmentationSeuil(actor) {

View File

@ -30,7 +30,7 @@ export class EffetsRencontre {
static $reve_plus = async (actor, reve) => { static $reve_plus = async (actor, reve) => {
if (!ReglesOptionnelles.isUsing("recuperation-reve") && reve < 0) { if (!ReglesOptionnelles.isUsing("recuperation-reve") && reve < 0) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name), whisper: ChatUtility.getOwners(actor),
content: `Pas de récupération de rêve (${reve} points ignorés)` content: `Pas de récupération de rêve (${reve} points ignorés)`
}); });
return return
@ -112,7 +112,7 @@ export class EffetsRencontre {
poesie: await Poetique.getExtrait() poesie: await Poetique.getExtrait()
}) })
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name), whisper: ChatUtility.getOwners(context.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
}); });
} }
@ -127,7 +127,7 @@ export class EffetsRencontre {
} }
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name), whisper: ChatUtility.getOwners(context.actor),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context) content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
}); });
} }

View File

@ -28,7 +28,7 @@ export class PresentCites extends Draconique {
let existants = actor.items.filter(it => this.isCase(it)).map(it => it.system.coord); let existants = actor.items.filter(it => this.isCase(it)).map(it => it.system.coord);
if (existants.length > 0) { if (existants.length > 0) {
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(actor),
content: "Vous avez encore des présents dans des cités, vous devrez tirer une autre tête pour remplacer celle ci!" content: "Vous avez encore des présents dans des cités, vous devrez tirer une autre tête pour remplacer celle ci!"
}) })
} }

View File

@ -5,7 +5,7 @@ import { RdDRollTables } from "../rdd-rolltables.js";
import { TMRUtility } from "../tmr-utility.js"; import { TMRUtility } from "../tmr-utility.js";
import { tmrTokenZIndex } from "../tmr-constants.js"; import { tmrTokenZIndex } from "../tmr-constants.js";
import { Draconique } from "./draconique.js"; import { Draconique } from "./draconique.js";
import { TYPES } from "../item.js"; import { ITEM_TYPES } from "../item.js";
import { TMRAnimations } from "./animation.js"; import { TMRAnimations } from "./animation.js";
export class UrgenceDraconique extends Draconique { export class UrgenceDraconique extends Draconique {
@ -14,12 +14,12 @@ export class UrgenceDraconique extends Draconique {
match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); } match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); }
manualMessage() { return false } manualMessage() { return false }
async onActorCreateOwned(actor, queue) { async onActorCreateOwned(actor, queue) {
const coordSortsReserve = actor.itemTypes[TYPES.sortreserve].map(it => it.system.coord) ?? []; const coordSortsReserve = actor.itemTypes[ITEM_TYPES.sortreserve].map(it => it.system.coord) ?? [];
if (coordSortsReserve.length == 0) { if (coordSortsReserve.length == 0) {
// La queue se transforme en idée fixe // La queue se transforme en idée fixe
const ideeFixe = await RdDRollTables.getIdeeFixe(); const ideeFixe = await RdDRollTables.getIdeeFixe();
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getOwners(actor),
content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${ideeFixe.name}` content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${ideeFixe.name}`
}); });
await actor.createEmbeddedDocuments('Item', [ideeFixe]); await actor.createEmbeddedDocuments('Item', [ideeFixe]);

View File

@ -1,6 +1,7 @@
import { TYPES } from "../item.js" import { ITEM_TYPES } from "../item.js"
import { RdDItemCompetence } from "../item-competence.js" import { RdDItemCompetence } from "../item-competence.js"
import { ChatUtility } from "../chat-utility.js" import { ChatUtility } from "../chat-utility.js"
import { Misc } from "../misc.js"
const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation'] const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation']
const TABLEAU_FATIGUE_MARCHE = [ const TABLEAU_FATIGUE_MARCHE = [
@ -36,7 +37,7 @@ export class DialogFatigueVoyage extends Dialog {
const parameters = { const parameters = {
tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE, tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE,
playerActors: game.actors.filter(actor => actor.isPersonnageJoueur()) playerActors: game.actors.filter(actor => actor.isPersonnageJoueur())
.map(actor => DialogFatigueVoyage.prepareActor(actor)), .map(actor => DialogFatigueVoyage.prepareActorParameters(actor)),
nombreHeures: 1, nombreHeures: 1,
} }
DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined) DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined)
@ -53,21 +54,37 @@ export class DialogFatigueVoyage extends Dialog {
parameters.typeTerrain = ligneFatigueMarche parameters.typeTerrain = ligneFatigueMarche
parameters.vitesseDeplacement = rythme.vitesse parameters.vitesseDeplacement = rythme.vitesse
parameters.fatigueHoraire = rythme.fatigue parameters.fatigueHoraire = rythme.fatigue
parameters.playerActors.forEach(voyageur =>
DialogFatigueVoyage.selectSurvie(voyageur, parameters.typeTerrain.code)
)
} }
static prepareActor(actor) { static prepareActorParameters(actor) {
const competencesVoyage = {} const actorParameters = {
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => id: actor.id,
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[TYPES.competence], codeSurvie, { onMessage: () => { } })
)
return {
actor: actor, actor: actor,
selected: true, selected: true,
ajustementFatigue: 0, ajustementFatigue: 0,
competencesVoyage: competencesVoyage survies: {}
} }
const competencesVoyage = {}
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => {
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[ITEM_TYPES.competence], codeSurvie, { onMessage: () => { } })
})
TABLEAU_FATIGUE_MARCHE.forEach(terrain => {
actorParameters.survies[terrain.code] = Misc.join(
terrain.survies.map(survie => {
const niveau = competencesVoyage[survie]?.system.niveau
return `${survie}: ${niveau}`
}),
', ')
})
return actorParameters
} }
static selectSurvie(actorParameters, code) {
actorParameters.survieCourante = actorParameters.survies[code]
}
constructor(html, parameters) { constructor(html, parameters) {
const options = { const options = {
@ -97,6 +114,7 @@ export class DialogFatigueVoyage extends Dialog {
this.html.find('select[name="code-terrain"]').change(event => this.changeParameters()) this.html.find('select[name="code-terrain"]').change(event => this.changeParameters())
this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters()) this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters())
this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters()) this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters())
this.html.find('.list-item input[name="ajustement-fatigue"]').change(event => this.changeParameters())
this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue()) this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue())
} }
@ -118,6 +136,10 @@ export class DialogFatigueVoyage extends Dialog {
selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme)) selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme))
}) })
selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change() selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change()
Promise.all(this.getActorRows()
.map(async row => row.find('label.voyage-liste-survies').text(this.$extractActorParameters(row).survieCourante)
))
} }
} }
@ -132,44 +154,61 @@ export class DialogFatigueVoyage extends Dialog {
} }
async setFatigue() { async setFatigue() {
this.html.find('input[name="base-fatigue"]').val(this.parameters.nombreHeures * this.parameters.fatigueHoraire) const baseFatigue = this.parameters.nombreHeures * this.parameters.fatigueHoraire
this.html.find('input[name="base-fatigue"]').val(baseFatigue)
this.updateActorTotalFatigue(baseFatigue)
}
async updateActorTotalFatigue(baseFatigue) {
Promise.all(this.getActorRows()
.map(async row => {
const actor = this.$extractActorParameters(row)
row.find('input[name="total-fatigue"]').val(actor.ajustement + baseFatigue)
}))
} }
async appliquerFatigue() { async appliquerFatigue() {
const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0) const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0)
const actors = jQuery.map( this.getActorRows()
this.html.find('div.fatigue-actors-list li.list-item'), .map(row => this.$extractActorParameters(row))
it => this.$extractActor(this.html.find(it)) .filter(it => it.selected)
)
actors.filter(it => it.selected)
.forEach(async it => { .forEach(async it => {
const perteFatigue = fatigueBase + it.ajustement const perteFatigue = fatigueBase + it.ajustement
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(it.actor.name), whisper: ChatUtility.getOwners(it.actor),
content: await renderTemplate( content: await renderTemplate(
'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs', foundry.utils.mergeObject(it, 'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs',
foundry.utils.mergeObject(it,
{ {
parameters: this.parameters, parameters: this.parameters,
fatigueBase: fatigueBase, fatigueBase: fatigueBase,
perteFatigue: perteFatigue, perteFatigue: perteFatigue,
isVoyage: fatigueBase == this.parameters.nombreHeures * this.parameters.fatigueHoraire isVoyage: fatigueBase == this.parameters.nombreHeures * this.parameters.fatigueHoraire
}) }, { inplace: false })
), ),
}) })
await it.actor.santeIncDec("fatigue", perteFatigue) await it.actor.santeIncDec("fatigue", perteFatigue)
}) })
} }
$extractActor(actorRow) { getActorRows() {
const actor = game.actors.get(actorRow.data('actor-id')) return jQuery.map(
this.html.find('div.fatigue-actors-list li.list-item'),
it => this.html.find(it))
}
$extractActorParameters(actorRow) {
const actorId = actorRow.data('actor-id')
const actorParameters = this.parameters.playerActors.find(it => it.id == actorId)
const actor = game.actors.get(actorId)
if (!actor) { if (!actor) {
ui.notifications.warn(`Acteur ${it.actorId} introuvable`) ui.notifications.warn(`Acteur ${it.actorId} introuvable`)
return {}
} }
return { actorParameters.ajustement = parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0)
actor: actor, actorParameters.selected = actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
ajustement: parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0), return actorParameters
selected: actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
}
} }
async close() { async close() {

View File

@ -65,6 +65,7 @@
{"_id":"MQxgfYTEQEUhG116","name":"Épée bâtarde","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_batarde.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.MQxgfYTEQEUhG116"}},"system":{"description":"<p>Comme son nom l&rsquo;indique, c&rsquo;est une <em>b&acirc;tarde </em>de l'&eacute;p&eacute;e longue et de l'&eacute;p&eacute;e sorde, &agrave; la fois longue et large, pouvant s&rsquo;utiliser &agrave; une ou deux mains.</p>","descriptionmj":"","equipe":false,"encombrement":3,"quantite":1,"qualite":0,"cout":30,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"resistance":14,"categorie_parade":"epees-lourdes","dommages":"4/5","penetration":0,"force":"13/12","competence":"Epée à 1 main","lancer":"","tir":"","portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":false,"deuxmains":true,"unemain":true,"initpremierround":"epeebatarde"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"MQxgfYTEQEUhG116","name":"Épée bâtarde","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_batarde.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.MQxgfYTEQEUhG116"}},"system":{"description":"<p>Comme son nom l&rsquo;indique, c&rsquo;est une <em>b&acirc;tarde </em>de l'&eacute;p&eacute;e longue et de l'&eacute;p&eacute;e sorde, &agrave; la fois longue et large, pouvant s&rsquo;utiliser &agrave; une ou deux mains.</p>","descriptionmj":"","equipe":false,"encombrement":3,"quantite":1,"qualite":0,"cout":30,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"resistance":14,"categorie_parade":"epees-lourdes","dommages":"4/5","penetration":0,"force":"13/12","competence":"Epée à 1 main","lancer":"","tir":"","portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":false,"deuxmains":true,"unemain":true,"initpremierround":"epeebatarde"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"Mbh2M8JS1Rf0vxEX","name":"Harpe","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/harpe.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.Mbh2M8JS1Rf0vxEX"}},"system":{"description":"","descriptionmj":"","encombrement":1,"quantite":1,"qualite":0,"cout":5,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"Mbh2M8JS1Rf0vxEX","name":"Harpe","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/harpe.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.Mbh2M8JS1Rf0vxEX"}},"system":{"description":"","descriptionmj":"","encombrement":1,"quantite":1,"qualite":0,"cout":5,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"NCp2kdTKmQGyAh1U","name":"Dague","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/dague.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sheetClass":"","sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NCp2kdTKmQGyAh1U"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":0.5,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Frequente","frequence":18},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":8,"categorie_parade":"dagues","dommages":"1","penetration":0,"force":"7","competence":"Dague","lancer":"Dague de jet","tir":"","portee_courte":3,"portee_moyenne":8,"portee_extreme":15,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":true,"deuxmains":false,"unemain":true,"initpremierround":"dague"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"NCp2kdTKmQGyAh1U","name":"Dague","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/dague.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sheetClass":"","sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NCp2kdTKmQGyAh1U"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":0.5,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Frequente","frequence":18},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":8,"categorie_parade":"dagues","dommages":"1","penetration":0,"force":"7","competence":"Dague","lancer":"Dague de jet","tir":"","portee_courte":3,"portee_moyenne":8,"portee_extreme":15,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":true,"deuxmains":false,"unemain":true,"initpremierround":"dague"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"NCp2kdTKmJVdFuit","name":"Dague mêlée","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/dague.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sheetClass":"","sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NCp2kdTKmQGyAh1U"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":0.5,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Frequente","frequence":18},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":8,"categorie_parade":"dagues","dommages":"1","penetration":0,"force":"7","competence":"Dague","lancer":"Dague de jet","tir":"","portee_courte":3,"portee_moyenne":8,"portee_extreme":15,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":true,"deuxmains":false,"unemain":true,"initpremierround":"dague"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"NNLhxjFsoJVdFuit","name":"Bouteille de verre (1 litre)","type":"conteneur","img":"systems/foundryvtt-reve-de-dragon/icons/objets/bouteille_verre.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NNLhxjFsoJVdFuit"}},"system":{"description":"","descriptionmj":"","encombrement":0.2,"quantite":1,"qualite":0,"cout":0.7,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"contenu":[],"capacite":0.5,"equipe":false},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"NNLhxjFsoJVdFuit","name":"Bouteille de verre (1 litre)","type":"conteneur","img":"systems/foundryvtt-reve-de-dragon/icons/objets/bouteille_verre.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NNLhxjFsoJVdFuit"}},"system":{"description":"","descriptionmj":"","encombrement":0.2,"quantite":1,"qualite":0,"cout":0.7,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"contenu":[],"capacite":0.5,"equipe":false},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"OXFFRZOqlhZDJas3","name":"Béret de velours","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/beret_velours.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.OXFFRZOqlhZDJas3"}},"system":{"description":"","descriptionmj":"","encombrement":0.05,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"OXFFRZOqlhZDJas3","name":"Béret de velours","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/beret_velours.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.OXFFRZOqlhZDJas3"}},"system":{"description":"","descriptionmj":"","encombrement":0.05,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
{"_id":"OYWzXiQUFsjU5AF2","name":"Perles de Bjwal","type":"potion","img":"systems/foundryvtt-reve-de-dragon/icons/objets/perles_bjwal.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.OYWzXiQUFsjU5AF2"}},"system":{"description":"<p>Petits granul&eacute;s translucides.</p>","descriptionmj":"","encombrement":0.1,"quantite":1,"qualite":0,"cout":1,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"temporel":{"debut":{"indexDate":-1,"indexMinute":0},"fin":{"indexDate":-1,"indexMinute":0}},"rarete":"","categorie":"Remede","herbe":"","herbebrins":0,"herbebonus":0,"reposalchimique":false,"pr":0,"prpermanent":false,"prdate":0,"soinherbe":"","soinherbebonus":0},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}} {"_id":"OYWzXiQUFsjU5AF2","name":"Perles de Bjwal","type":"potion","img":"systems/foundryvtt-reve-de-dragon/icons/objets/perles_bjwal.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.OYWzXiQUFsjU5AF2"}},"system":{"description":"<p>Petits granul&eacute;s translucides.</p>","descriptionmj":"","encombrement":0.1,"quantite":1,"qualite":0,"cout":1,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"temporel":{"debut":{"indexDate":-1,"indexMinute":0},"fin":{"indexDate":-1,"indexMinute":0}},"rarete":"","categorie":"Remede","herbe":"","herbebrins":0,"herbebonus":0,"reposalchimique":false,"pr":0,"prpermanent":false,"prdate":0,"soinherbe":"","soinherbebonus":0},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}

View File

@ -11,4 +11,3 @@
{"name":"Thème astral","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/magic/nature/symbol-moon-stars-white.webp","command":"game.system.rdd.AppAstrologie.create()","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.oA0HPFeFK6YMspAX"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.19","coreVersion":"10.291","createdTime":1678127868791,"modifiedTime":1678237392810,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"koqhiDJSGP4gQ4vf"} {"name":"Thème astral","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/magic/nature/symbol-moon-stars-white.webp","command":"game.system.rdd.AppAstrologie.create()","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.oA0HPFeFK6YMspAX"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.19","coreVersion":"10.291","createdTime":1678127868791,"modifiedTime":1678237392810,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"koqhiDJSGP4gQ4vf"}
{"name":"Jet d'éthylisme","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/consumables/drinks/alcohol-beer-stein-wooden-metal-brown.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.jetEthylisme();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233646086,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"mvub1dRHNFmWjRr7"} {"name":"Jet d'éthylisme","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/consumables/drinks/alcohol-beer-stein-wooden-metal-brown.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.jetEthylisme();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233646086,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"mvub1dRHNFmWjRr7"}
{"name":"Tirer le tarot","type":"chat","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp","command":"/tirer tarot","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.HBZSKR9OHCQbLcTC"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1669469547231,"modifiedTime":1671237401618,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"vTfJTFYYiRu8X5LM"} {"name":"Tirer le tarot","type":"chat","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp","command":"/tirer tarot","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.HBZSKR9OHCQbLcTC"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1669469547231,"modifiedTime":1671237401618,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"vTfJTFYYiRu8X5LM"}
{"name": "Mon personnage","type": "script","author": "Hp9ImM4o9YRTSdfu","img": "systems/foundryvtt-reve-de-dragon/icons/voyageurs/token_hr_dilettante.webp","scope": "global","command": "if (game.user.isGM) {\n ui.notifications.warn(\"En tant que gardien, vous n'avez pas de personnage attitré\")\n return\n}\nconst actor = game.users.get(game.userId)?.character\nif (!actor) {\n ui.notifications.warn(\"Vous n'avez pas de personnage attitré\")\n return\n}\nactor.sheet.render(true)","folder": null,"flags": {"core": {},"exportSource": {"world": "graine","system": "foundryvtt-reve-de-dragon","coreVersion": "11.313","systemVersion": "11.1.1"}},"_stats": {"systemId": "foundryvtt-reve-de-dragon","systemVersion": "11.1.1","coreVersion": "11.313","createdTime": 1699477824379,"modifiedTime": 1699485023429,"lastModifiedBy": "Hp9ImM4o9YRTSdfu"}}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -326,7 +326,7 @@ table {border: 1px solid #7a7971;}
display: grid; display: grid;
grid-column: span 2 / span 2; grid-column: span 2 / span 2;
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px; gap: 30px;
margin: 10px 0; margin: 10px 0;
padding: 0; padding: 0;
} }
@ -411,6 +411,11 @@ table {border: 1px solid #7a7971;}
text-align: left; text-align: left;
} }
.flex-group-top {
vertical-align: top;
align-self: start;
}
.flex-group-right { .flex-group-right {
-webkit-box-pack: end; -webkit-box-pack: end;
-ms-flex-pack: end; -ms-flex-pack: end;
@ -562,7 +567,11 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
.dice-img { .dice-img {
border-width: 0; border-width: 0;
max-width: 1.5rem;
max-height: 1.5rem;
vertical-align: top;
} }
.in-text-img { .in-text-img {
max-width: 1.2em; max-width: 1.2em;
max-height: 1.2em; max-height: 1.2em;
@ -572,6 +581,15 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
border: none; border: none;
padding: 0.1rem; padding: 0.1rem;
} }
.context-menu-img {
max-width: 2rem;
max-height: 1rem;
flex-grow: 0;
margin: 0.2rem 0.3rem 0 0;
vertical-align: middle;
border: none;
padding: 0rem;
}
.button-img { .button-img {
vertical-align: baseline; vertical-align: baseline;
@ -666,6 +684,7 @@ input:is(.blessure-premiers_soins, .blessure-soins_complets) {
} }
.carac-label { .carac-label {
font-weight: bold;
flex-basis: 40%; flex-basis: 40%;
} }
.rdd.sheet .window-content .sheet-body .carac-list .caracteristique > .utiliser-attribut { .rdd.sheet .window-content .sheet-body .carac-list .caracteristique > .utiliser-attribut {
@ -1174,9 +1193,6 @@ ul.chat-list li:nth-child(odd) {
padding: 0.5rem; padding: 0.5rem;
cursor: pointer; cursor: pointer;
} }
.carac-label {
font-weight: bold;
}
.list-item { .list-item {
margin: 0.1rem; margin: 0.1rem;
box-shadow: inset 0px 0px 1px #00000096; box-shadow: inset 0px 0px 1px #00000096;
@ -1374,7 +1390,7 @@ table.table-nombres-astraux tr:hover {
flex-direction: column; flex-direction: column;
position: absolute; position: absolute;
top: 4.6rem; top: 4.6rem;
right: 3.5rem; left: -19rem;
} }
.token-hud-ext.soins { .token-hud-ext.soins {
flex-direction: column; flex-direction: column;
@ -1545,6 +1561,11 @@ div.control-icon.token-hud-icon {
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
} }
.chat-inline-icon {
border: 0;
padding: 1px;
vertical-align: text-top;
}
#sidebar-tabs { #sidebar-tabs {
flex: 0 0 28px; flex: 0 0 28px;

View File

@ -1,13 +1,13 @@
{ {
"id": "foundryvtt-reve-de-dragon", "id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon", "title": "Rêve de Dragon",
"version": "11.2.21", "version": "12.0.19",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.2.21.zip", "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.19.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": { "compatibility": {
"minimum": "11", "minimum": "11",
"verified": "11" "verified": "12"
}, },
"description": "Rêve de Dragon RPG for FoundryVTT", "description": "Rêve de Dragon RPG for FoundryVTT",
"authors": [ "authors": [
@ -534,6 +534,7 @@
}, },
"primaryTokenAttribute": "sante.vie", "primaryTokenAttribute": "sante.vie",
"secondaryTokenAttribute": "sante.endurance", "secondaryTokenAttribute": "sante.endurance",
"background": "systems/foundryvtt-reve-de-dragon/styles/img/reve-de-dragon-cover.webp",
"media": [ "media": [
{ {
"type": "icon", "type": "icon",

View File

@ -15,12 +15,14 @@
} }
}, },
"background": { "background": {
"metier": "",
"biographie": "Histoire personnelle...", "biographie": "Histoire personnelle...",
"notes": "Notes", "notes": "Notes",
"notesmj": "Notes du MJ", "notesmj": "Notes du MJ",
"race": "Humain", "race": "Humain",
"yeux": "", "yeux": "",
"cheveux": "", "cheveux": "",
"taille": "",
"poids": "", "poids": "",
"heure": "", "heure": "",
"sexe": "", "sexe": "",

View File

@ -9,9 +9,9 @@
<div class="flexrow"> <div class="flexrow">
<h1 class="charname"><input name="name" type="text" value="{{name}}" placeholder="Name" /></h1> <h1 class="charname"><input name="name" type="text" value="{{name}}" placeholder="Name" /></h1>
<div class="header-buttons"> <div class="header-buttons">
<span class="encaisser-direct"><a><img class="button-img" src="icons/svg/bones.svg" data-tooltip="Encaisser des dommages"/></a></span> <span><a class="button-encaissement"><img class="button-img" src="icons/svg/bones.svg" data-tooltip="Encaisser des dommages"/></a></span>
{{#if @root.options.isGM}} {{#if @root.options.isGM}}
<span class="remise-a-neuf"><a><img class="button-img" src="icons/svg/regen.svg" data-tooltip="Remise à neuf"/></a></span> <span><a class="button-remise-a-neuf"><img class="button-img" src="icons/svg/regen.svg" data-tooltip="Remise à neuf"/></a></span>
{{/if}} {{/if}}
</div> </div>
</div> </div>

View File

@ -9,9 +9,9 @@
<div class="flexrow"> <div class="flexrow">
<h1 class="charname"><input name="name" type="text" value="{{name}}" placeholder="Name" /></h1> <h1 class="charname"><input name="name" type="text" value="{{name}}" placeholder="Name" /></h1>
<div class="header-buttons"> <div class="header-buttons">
<span class="encaisser-direct"><a><img class="button-img" src="icons/svg/bones.svg" data-tooltip="Encaisser des dommages"/></a></span> <span><a class="button-encaissement"><img class="button-img" src="icons/svg/bones.svg" data-tooltip="Encaisser des dommages"/></a></span>
{{#if @root.options.isGM}} {{#if @root.options.isGM}}
<span class="remise-a-neuf"><a><img class="button-img" src="icons/svg/regen.svg" data-tooltip="Remise à neuf"/></a></span> <span><a class="button-remise-a-neuf"><img class="button-img" src="icons/svg/regen.svg" data-tooltip="Remise à neuf"/></a></span>
{{/if}} {{/if}}
</div> </div>
</div> </div>

View File

@ -172,6 +172,10 @@
<label for="system.poids">Poids :</label> <label for="system.poids">Poids :</label>
<input class="flex-grow" type="text" name="system.poids" value="{{system.poids}}" data-dtype="String"/> <input class="flex-grow" type="text" name="system.poids" value="{{system.poids}}" data-dtype="String"/>
</li> </li>
<li class="item flexrow list-item">
<label for="system.metier">Métier :</label>
<input class="flex-grow" type="text" name="system.metier" value="{{system.metier}}" data-dtype="String"/>
</li>
</ul> </ul>
<ul class="item-list alterne-list"> <ul class="item-list alterne-list">
<li class="item flexrow list-item"> <li class="item flexrow list-item">
@ -201,6 +205,7 @@
<label for="system.yeux">Yeux :</label> <label for="system.yeux">Yeux :</label>
<input class="flex-grow" type="text" name="system.yeux" value="{{system.yeux}}" data-dtype="String"/> <input class="flex-grow" type="text" name="system.yeux" value="{{system.yeux}}" data-dtype="String"/>
</li> </li>
<a class="chat-card-button description-aleatoire" data-tooltip="Déterminer aléatoirement les détails de description">Description <i class="fa-solid fa-dice-d20"></i></a>
</ul> </ul>
</article> </article>

View File

@ -55,7 +55,7 @@
<li class="caracteristique flexrow list-item" data-tooltip="Niveau d'éthylisme"> <li class="caracteristique flexrow list-item" data-tooltip="Niveau d'éthylisme">
<label class="derivee-label" for="system.compteurs.ethylisme.value">{{system.compteurs.ethylisme.label}}</label> <label class="derivee-label" for="system.compteurs.ethylisme.value">{{system.compteurs.ethylisme.label}}</label>
<select class="derivee-value" name="system.compteurs.ethylisme.value" data-dtype="Number"> <select class="derivee-value" name="system.compteurs.ethylisme.value" data-dtype="Number">
{{selectOptions @root.config.niveauEthylisme selected=system.compteurs.ethylisme.value valueAttr="value" nameAttr="value" labelAttr="label"}} {{selectOptions (RDD_CONFIG 'niveauEthylisme') selected=system.compteurs.ethylisme.value valueAttr="value" nameAttr="value" labelAttr="label"}}
</select> </select>
</li> </li>

View File

@ -2,13 +2,13 @@
<li class="caracteristique flexrow list-item"> <li class="caracteristique flexrow list-item">
<span class="carac-label" name="catEntite">Catégorie : </span> <span class="carac-label" name="catEntite">Catégorie : </span>
<select name="system.definition.categorieentite" value="{{system.definition.categorieentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}> <select name="system.definition.categorieentite" value="{{system.definition.categorieentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}>
{{selectOptions @root.config.categorieEntite selected=system.definition.categorieentite}} {{selectOptions (RDD_CONFIG 'categorieEntite') selected=system.definition.categorieentite}}
</select> </select>
</li> </li>
<li class="caracteristique flexrow list-item"> <li class="caracteristique flexrow list-item">
<span class="carac-label" name="typeEntite">Type d'entité : </span> <span class="carac-label" name="typeEntite">Type d'entité : </span>
<select name="system.definition.typeentite" value="{{system.definition.typeentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}> <select name="system.definition.typeentite" value="{{system.definition.typeentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}>
{{selectOptions @root.config.typeEntite selected=system.definition.typeentite}} {{selectOptions (RDD_CONFIG 'typeEntite') selected=system.definition.typeentite}}
</select> </select>
</li> </li>
{{#each system.attributs as |attr key|}} {{#each system.attributs as |attr key|}}

View File

@ -7,7 +7,7 @@
<label class="carac-xp"/> <label class="carac-xp"/>
{{else}} {{else}}
{{#if carac.derivee}} {{#if carac.derivee}}
<span class="carac-label" name="system.carac.{{key}}.label"><a name={{key}}>{{carac.label}}</a></span> <span class="carac-label" name="system.carac.{{key}}.label"><a class="roll-carac" data-carac-name={{key}}>{{carac.label}}</a></span>
<label class="competence-value">{{carac.value}}</label> <label class="competence-value">{{carac.value}}</label>
<label class="carac-xp"/> <label class="carac-xp"/>
{{else}} {{else}}
@ -22,7 +22,7 @@
</a> </a>
</span> </span>
{{else}} {{else}}
<span class="carac-label tooltip" name="system.carac.{{key}}.label"><a name={{key}}>{{carac.label}}</a></span> <span class="carac-label tooltip" name="system.carac.{{key}}.label"><a class="roll-carac" data-carac-name={{key}}>{{carac.label}}</a></span>
{{/if}} {{/if}}
<input class="carac-value" type="text" name="system.carac.{{key}}.value" value="{{carac.value}}" data-dtype="{{carac.type}}" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} /> <input class="carac-value" type="text" name="system.carac.{{key}}.value" value="{{carac.value}}" data-dtype="{{carac.type}}" {{#unless @root.options.vueDetaillee}}disabled{{/unless}} />
<span class="carac-xp tooltip"> <span class="carac-xp tooltip">

View File

@ -13,7 +13,7 @@
data-competence-name="{{arme.system.competence}}" data-competence-name="{{arme.system.competence}}"
data-tooltip="{{arme.name}}: niveau {{plusMoins arme.system.niveau}}"> data-tooltip="{{arme.name}}: niveau {{plusMoins arme.system.niveau}}">
<span class="arme-label"> <span class="arme-label">
<a> <a class="roll-arme">
{{#if arme.img}} {{#if arme.img}}
<img class="sheet-competence-img" src="{{arme.img}}" data-tooltip="{{arme.name}}"/> <img class="sheet-competence-img" src="{{arme.img}}" data-tooltip="{{arme.name}}"/>
{{/if}} {{/if}}
@ -25,14 +25,14 @@
<span class="competence-value">{{plusMoins arme.system.niveau}}</span> <span class="competence-value">{{plusMoins arme.system.niveau}}</span>
<span class="competence-value">{{plusMoins arme.system.dommagesReels}}</span> <span class="competence-value">{{plusMoins arme.system.dommagesReels}}</span>
<span class="competence-value"></span> <span class="competence-value"></span>
<span class="initiative-value arme-initiative"><a data-tooltip="{{arme.name}}: initiative {{plusMoins arme.system.initiative}}">{{arme.system.initiative}}</a></span> <span class="initiative-value"><a class="roll-init-arme" data-tooltip="{{arme.name}}: initiative {{arme.system.initiative}}">{{arme.system.initiative}}</a></span>
</li> </li>
{{/each}} {{/each}}
{{#each esquives as |esq key|}} {{#each esquives as |esq key|}}
<li class="item flexrow list-item" data-item-id="{{esq._id}}" <li class="item flexrow list-item" data-item-id="{{esq._id}}"
data-tooltip="{{esq.name}}: niveau {{plusMoins esq.system.niveau}}"> data-tooltip="{{esq.name}}: niveau {{plusMoins esq.system.niveau}}">
<span class="competence-label"> <span class="competence-label">
<a class="competence-label" name="{{esq.name}}"> <a class="roll-competence" name="{{esq.name}}">
<img class="sheet-competence-img" src="{{esq.img}}" /> <img class="sheet-competence-img" src="{{esq.img}}" />
<span>{{esq.name}}</span> <span>{{esq.name}}</span>
</a> </a>

View File

@ -1,7 +1,7 @@
<ol class="item-list alterne-list"> <ol class="item-list alterne-list">
{{#each (trier competences) as |comp key|}} {{#each (trier competences) as |comp key|}}
<li class="item flexrow list-item" data-item-id="{{comp._id}}"> <li class="item flexrow list-item" data-item-id="{{comp._id}}">
<a class="competence-label"> <a class="competence-label roll-competence">
<img class="sheet-competence-img" src="{{comp.img}}" data-tooltip="{{comp.name}}"/> <img class="sheet-competence-img" src="{{comp.img}}" data-tooltip="{{comp.name}}"/>
<span>{{comp.name}}</span> <span>{{comp.name}}</span>
</a> </a>

View File

@ -1,6 +1,7 @@
{{#unless system.isHidden}} {{#unless system.isHidden}}
<li class="item flexrow list-item {{#if system.isLevelUp}}xp-level-up tooltip{{/if}}" data-item-id="{{_id}}"> <li class="item flexrow list-item {{#if system.isLevelUp}}xp-level-up{{/if}}" data-item-id="{{_id}}">
<a class="competence-label" name="{{name}}" data-tooltip="Niveau {{plusMoins system.niveau}} en {{name}}"> <span class="tooltip">
<a class="competence-label roll-competence" name="{{name}}" data-tooltip="Niveau {{plusMoins system.niveau}} en {{name}}">
<img class="sheet-competence-img" src="{{img}}"/> <img class="sheet-competence-img" src="{{img}}"/>
<span>{{name}}</span> <span>{{name}}</span>
</a> </a>
@ -11,6 +12,7 @@
<i class="fas fa-arrow-alt-circle-up"></i> <i class="fas fa-arrow-alt-circle-up"></i>
</a> </a>
{{/if}} {{/if}}
</span>
<input class="competence-value" type="text" compname="{{name}}" name="comp-value-{{name}}" <input class="competence-value" type="text" compname="{{name}}" name="comp-value-{{name}}"
value="{{plusMoins system.niveau}}" data-dtype="number" value="{{plusMoins system.niveau}}" data-dtype="number"
@ -52,5 +54,5 @@
<a class="item-montrer" data-tooltip="Montrer"><i class="fas fa-comment"></i></a> <a class="item-montrer" data-tooltip="Montrer"><i class="fas fa-comment"></i></a>
</div> </div>
{{/if}} {{/if}}
</li> </li>
{{/unless}} {{/unless}}

View File

@ -0,0 +1,132 @@
<form class="{{cssClass}}" autocomplete="off" >
<section class="sheet-header flexrow">
<div class="flex-grow-0-5">
<img class="profile-img" src="{{img}}" data-edit="img" data-tooltip="{{name}}" />
</div>
<div class="flexcol flex-grow-2">
<div>
<h1 class="charname">{{name}}</h1>
</div>
<div>
<a class="button-appel-chance"><img class="button-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/appel-chance.svg" data-tooltip="Appel à la chance"/></a>
<a class="button-encaissement"><img class="button-img" src="icons/svg/bones.svg" data-tooltip="Encaisser des dommages"/></a>
<a class="button-ethylisme"><img class="button-img" src="icons/svg/tankard.svg" data-tooltip="Boire"/></a>
<a class="button-repos"><img class="button-img" src="icons/svg/sleep.svg" data-tooltip="Se reposer"/></a>
{{#if system.attributs.hautrevant.value}}
<a class="button-tmr" data-tooltip="Montée dans les Terres M&eacute;dianes !" {{#if hautreve.isDemiReve}}disabled{{/if}}>
<img class="button-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/icon-tmr-normal.svg"/>
</a>
<a class="button-tmr-rapide" data-tooltip="Montée accélérée dans les Terres M&eacute;dianes !" {{#if hautreve.isDemiReve}}disabled{{/if}}>
<img class="button-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/icon-tmr-rapide.svg"/>
</a>
<a class="button-tmr-visu" data-tooltip="Regarder les Terres M&eacute;dianes">
<img class="button-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/icon-tmr-view.svg"/>
</a>
{{/if}}
{{#if @root.options.isGM}}
<a class="button-remise-a-neuf"><img class="button-img" src="icons/svg/regen.svg" data-tooltip="Remise à neuf"/></a>
{{/if}}
{{#if options.exportScriptarium}}
<a class="button-export">
<img class="button-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/scriptarium.svg" data-tooltip="Export format Scriptarium"/>
</a>
{{/if}}
</div>
</div>
</section>
<section class="sheet-body" style=:"margin-bottom: 3rem;">
<div>
<strong>{{export.name.value}}</strong>{{#if export.description.value}}, {{export.description.value}}{{/if}}
</div>
<hr>
<div class="grid-2col">
<div class="flexcol flex-group-top">
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.taille}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.apparence}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.constitution}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.force}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.agilite}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.dexterite}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.vue}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.ouie}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.odoratgout}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.volonte}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.empathie}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.intellect}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-compteur.hbs" carac=export.reve actuel=export.reve_actuel button-name='ptreve-actuel'}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs" carac=export.chance}}
</div>
<div class="flexcol flex-group-top">
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs" carac=export.melee}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs" carac=export.tir}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs" carac=export.lancer}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs" carac=export.derobee}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs" carac=export.vie actuel=export.vie_actuel}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs" carac=export.endurance actuel=export.endurance_actuel}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/fatigue.hbs" }}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs" carac=export.plusdom}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs" export}}
<div class="flexrow">&nbsp;</div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs" }}
</div>
</div>
<hr>
<div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs" name='' niveau='Niv' init='Init' dommages='+dom'}}
{{#each context.armes as |arme|}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs"
name=arme.name niveau=arme.niveau init=arme.init dommages=arme.dommages
arme=arme.arme competence=arme.competence
}}
{{/each}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs" name='Esquive' niveau=context.esquive.value competence=context.esquive.competence}}
{{#if (gt export.malue_armure.value 0)}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs" name='Esquive (avec armure)' niveau=export.esquive_armure.value
competence=context.esquive.competence}}
{{/if}}
</div>
<hr>
<div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs" competences=competences}}
</div>
<hr>
<div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs" competences=draconic }}
</div>
<hr>
<div>
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_0.value description=export.sort_description_0.value bonus=export.sort_bonus_0.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_1.value description=export.sort_description_1.value bonus=export.sort_bonus_1.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_2.value description=export.sort_description_2.value bonus=export.sort_bonus_2.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_3.value description=export.sort_description_3.value bonus=export.sort_bonus_3.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_4.value description=export.sort_description_4.value bonus=export.sort_bonus_4.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_5.value description=export.sort_description_5.value bonus=export.sort_bonus_5.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_6.value description=export.sort_description_6.value bonus=export.sort_bonus_6.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_7.value description=export.sort_description_7.value bonus=export.sort_bonus_7.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_8.value description=export.sort_description_8.value bonus=export.sort_bonus_8.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_9.value description=export.sort_description_9.value bonus=export.sort_bonus_9.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_10.value description=export.sort_description_10.value bonus=export.sort_bonus_10.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_11.value description=export.sort_description_11.value bonus=export.sort_bonus_11.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_12.value description=export.sort_description_12.value bonus=export.sort_bonus_12.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_13.value description=export.sort_description_13.value bonus=export.sort_bonus_13.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_14.value description=export.sort_description_14.value bonus=export.sort_bonus_14.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_15.value description=export.sort_description_15.value bonus=export.sort_bonus_15.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_16.value description=export.sort_description_16.value bonus=export.sort_bonus_16.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_17.value description=export.sort_description_17.value bonus=export.sort_bonus_17.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_18.value description=export.sort_description_18.value bonus=export.sort_bonus_18.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_19.value description=export.sort_description_19.value bonus=export.sort_bonus_19.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_20.value description=export.sort_description_20.value bonus=export.sort_bonus_20.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_21.value description=export.sort_description_21.value bonus=export.sort_bonus_21.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_22.value description=export.sort_description_22.value bonus=export.sort_bonus_22.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_23.value description=export.sort_description_23.value bonus=export.sort_bonus_23.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_24.value description=export.sort_description_24.value bonus=export.sort_bonus_24.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_25.value description=export.sort_description_25.value bonus=export.sort_bonus_25.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_26.value description=export.sort_description_26.value bonus=export.sort_bonus_26.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_27.value description=export.sort_description_27.value bonus=export.sort_bonus_27.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_28.value description=export.sort_description_28.value bonus=export.sort_bonus_28.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs" voie=export.sort_voie_29.value description=export.sort_description_29.value bonus=export.sort_bonus_29.value}}
<div>&nbsp;</div>
<div>&nbsp;</div>
</div>
</section>
</form>

View File

@ -0,0 +1,24 @@
<div class="flexrow item"
data-item-id="{{arme._id}}"
data-arme-name="{{arme.name}}"
data-competence-name="{{competence.name}}">
{{#if name}}
<a class="roll-arme">{{upperFirst name}}</a>
{{else}}
<div></div>
{{/if}}
<div class="flexrow">
<div>{{niveau}}</div>
{{#if init}}
{{#if name}}
<div><a class="roll-init-arme">{{init}}</a></div>
{{else}}
<div>{{init}}</div>
{{/if}}
<div>{{dommages}}</div>
{{else}}
<div></div>
<div></div>
{{/if}}
</div>
</div>

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