Compare commits

..

159 Commits

Author SHA1 Message Date
57d52c1966 Inc release 2022-12-11 10:35:51 +01:00
e3a29cdab5 Merge pull request 'Fix taille du texte des boutons' (#593) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #593
2022-12-11 10:34:36 +01:00
Vincent Vandemeulebrouck
10e4f14eb2 Fix taille du texte des boutons 2022-12-11 02:10:39 +01:00
04273dfcf1 Inc release 2022-12-10 18:14:52 +01:00
8c5c01114e Merge pull request 'Corrections esthétiques' (#592) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #592
2022-12-10 18:13:44 +01:00
Vincent Vandemeulebrouck
19e6124330 Suppression scripts vides 2022-12-10 16:38:18 +01:00
Vincent Vandemeulebrouck
1c908b50cb Dialog repos 2022-12-10 16:38:18 +01:00
Vincent Vandemeulebrouck
969cedfc3d Fix espace avant boutons 2022-12-10 16:28:08 +01:00
Vincent Vandemeulebrouck
830e66749d Lien des label vers les champs 2022-12-10 16:09:55 +01:00
Vincent Vandemeulebrouck
df26e654ae Fix des tailles de polices 2022-12-10 16:09:35 +01:00
Vincent Vandemeulebrouck
153bfe2e75 Simplification hbs pour la vue détaillée 2022-12-10 16:07:33 +01:00
Vincent Vandemeulebrouck
f6d42875ae Stress et archétype
Déplacement du stress et de l'archétype avant les compétences

Les lignes d'archétypes totalement réparties disparaissent
2022-12-10 15:49:09 +01:00
Vincent Vandemeulebrouck
450cb8e899 Largeur des compétences
Ajustement de la largeur des colonnes de compétenes en vue
simplifiée

Déplacement de l'en-tête dans la première ligne de la liste (avec les
boutons en vue détaillée)
2022-12-10 15:44:08 +01:00
0202938910 Ajout faune 2022-12-09 22:50:23 +01:00
512a056e59 Merge pull request 'Poissons, coquillages, crustacés' (#591) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #591
2022-12-09 22:49:29 +01:00
Vincent Vandemeulebrouck
214377c66d Poissons, coquillages, crustacés
Ils sont frais, mes poissons!
2022-12-09 22:36:17 +01:00
752e534350 Ajout faune 2022-12-09 21:50:12 +01:00
c85a544cc9 Ajout faune + fix sur suppression milieux 2022-12-09 12:01:44 +01:00
3a90c693d9 Release 2022-12-09 10:39:21 +01:00
c04b179176 Merge pull request 'Permettre d'avoir plusieurs fenêtres' (#590) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #590
2022-12-09 10:36:48 +01:00
Vincent Vandemeulebrouck
63770790b9 Fix multi-dialogs
Arrêter d'utiliser le jQuery $(selector) qui cause des effets de bord si
plusieurs élements de la page (ie: foundry) correspondent
au selector.

Stocker le html dans les Sheet/Dialogs lors de l'appel
activateListeners  afin de pouvoir s'y référer ensuite.

Utiliser this.html.find pour chercher dans le html de la fenêtre
courante.

Eliminer les référence par id html car l'id est unique (donc ne marche
pas en multi-fenêtres)
2022-12-09 02:07:59 +01:00
Vincent Vandemeulebrouck
aefc7a434b Fix: lien vers rencontre du compendium 2022-12-09 02:07:59 +01:00
Vincent Vandemeulebrouck
f02959adee Cleanup
Construction du message de jet de constitution par template hbs
2022-12-09 02:07:59 +01:00
Vincent Vandemeulebrouck
e652027b02 Cleanup accorder entité
Méthode pour accorder une entité en double (dont une version sans xp,
et message mal formaté)
2022-12-09 02:07:45 +01:00
Vincent Vandemeulebrouck
2122a54db7 Cleanup roll windows
- permettre plusieurs fenêtres de jets en même temps en éliminant les
  id dans le html et les jquery sur id pour éviter les interactions
- génération de la table par handlebars
2022-12-06 01:30:31 +01:00
f027e3318b Merge pull request 'Ragoût de Klampin' (#588) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #588
2022-12-05 16:50:33 +01:00
Vincent Vandemeulebrouck
31b4d1cfcc Version 10.3.6 2022-12-05 16:39:24 +01:00
Vincent Vandemeulebrouck
5056c35038 Faune et flore comestibles
- permettre de cuisiner les ingrédients (faune & flore)
- permettre de manger des ingrédients "crus"
2022-12-05 16:38:26 +01:00
Vincent Vandemeulebrouck
7b58407634 Cleanup 2022-12-05 16:36:27 +01:00
Vincent Vandemeulebrouck
7efa7be1c0 L'art ne s'encombre de rien
Ne pas appliquer le surencombrement (ou l'encombrement) aux oeuvres
d'art: on considère que pour faire de l'art, on pose son sac.
2022-12-05 16:36:27 +01:00
Vincent Vandemeulebrouck
717bb6fc6e Fix ouverture conteneur 2022-12-05 16:36:27 +01:00
51273bcc3e Merge pull request 'Gestion de la Faune' (#587) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #587
2022-12-03 23:16:36 +01:00
Vincent Vandemeulebrouck
b8f3a9af27 Version 10.3.5 2022-12-03 22:31:56 +01:00
Vincent Vandemeulebrouck
ab704c46d2 Ajout de l'Item "faune" pour tables environnement 2022-12-03 22:31:42 +01:00
Vincent Vandemeulebrouck
db8fd6dbf8 Meilleur post to tchat 2022-12-03 22:27:21 +01:00
Vincent Vandemeulebrouck
d998a4cb08 Amélioration Classes ItemSheet séparées
Meilleur support des feuilles ItemSheet séparés
Séparation de la feuille Conteneurs

Mise en commun de la logique drag&drop
2022-12-03 22:27:20 +01:00
Vincent Vandemeulebrouck
b1e27a9597 On ne peut pas tout donner
Limitation des types d'objets pouvant être donnés à différents acteurs
2022-12-03 18:31:14 +01:00
eaac9564b4 Merge pull request 'La recherche par milieu fonctionnelle' (#586) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #586
2022-12-03 10:05:49 +01:00
Vincent Vandemeulebrouck
0826c7e9e3 Version 10.3.4 2022-12-03 01:26:39 +01:00
Vincent Vandemeulebrouck
bdd3802e72 Amélioration de la recherche dans un milieu
- gestion correcte de la case
- recherche insensitive
- correction de la liste des milieux à ajouter dans la feuille
- si aucun milieu ne correspond à la recherche, affiche la
  liste des milieux disponibles
2022-12-03 01:25:24 +01:00
Vincent Vandemeulebrouck
b07cea40e2 Fallback sur compendium system
quand le compendium configuré n'existe plus, fallback sur le
compendium du système
2022-12-03 01:25:23 +01:00
Vincent Vandemeulebrouck
bb7f4c42ad Feuilles Ingrédient&Herbe extends RdDItemSheet
Pour bénéficier de certains comportements (description...)
2022-12-03 01:25:23 +01:00
Vincent Vandemeulebrouck
ac15a022df Fréquences dans les milieux standard
Saisie dans le compendiums de fréquences pour la liste de milieux
par défaut
2022-12-03 01:25:23 +01:00
a43c725b06 Merge pull request '10.3.3' (#585) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #585
2022-12-02 23:51:15 +01:00
Vincent Vandemeulebrouck
1276c64835 Version 10.3.3 2022-12-02 21:22:43 +01:00
Vincent Vandemeulebrouck
4b4d778d9c Entrée ajoute le milieu aux fréquences 2022-12-02 21:22:11 +01:00
Vincent Vandemeulebrouck
86f9c37b30 Liste des milieux par défaut 2022-12-02 21:22:11 +01:00
Vincent Vandemeulebrouck
ac77c6da9e Fix calcul valeur équipement 2022-12-02 21:22:11 +01:00
344540ea8e Merge pull request 'Fix initiative' (#584) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #584
2022-12-01 08:05:14 +01:00
Vincent Vandemeulebrouck
8a5cf3cb09 Version 10.3.2 2022-12-01 01:25:06 +01:00
Vincent Vandemeulebrouck
3a29570bae Fix message d'expérience invisibles
Les messages d'expérience sur mêlée/tir/lancer (à répartir)
n'étaient plus visibles
2022-12-01 01:22:25 +01:00
Vincent Vandemeulebrouck
02c48f4796 Fix initiative 2022-12-01 00:28:23 +01:00
ee01878fae Fixes suite à dernières modifs 2022-11-30 16:41:39 +01:00
2e1005e909 Merge pull request 'Fixes mineurs' (#583) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #583
2022-11-30 16:40:35 +01:00
Vincent Vandemeulebrouck
98c016696d Correction de l'ajout de milieux parfois KO
Pas sûr du pourquoi, il semble qu'il y a un souci jQuery
(avec deux fenêtres?)
2022-11-30 16:03:56 +01:00
Vincent Vandemeulebrouck
e67ac96e93 Fix: /roll
Regression sur /roll causée par méthode async:
return Promise(false)=>true au lieu de false...
2022-11-30 14:28:11 +01:00
Vincent Vandemeulebrouck
979a48e4d9 Amélioration recherche dans un milieu
Si la recherche est sur un milieu exact, seul ce millieu est considéré.
ie: chercher en "Forêts" ne cherchera pas en "Forêts humides".

Le recherche en "for" cherchera dans tous les milieux contenant "for".
Un message d'avertissement est affiché, et la description de la table
contient la liste des milieux correspondants.

Si plusieurs milieux cherchés ont une fréquence pour une ressource,
la fréquence la plus élevée est utilisée.
2022-11-30 14:24:09 +01:00
Vincent Vandemeulebrouck
faff6e54ef Fix arborescence de conteneur 2022-11-30 14:24:08 +01:00
d493e99bcb Merge pull request 'Tables de compendiums et feuilles de personnages' (#582) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #582
2022-11-30 09:37:49 +01:00
Vincent Vandemeulebrouck
92ae0b7431 Correction aide /tirer milieu 2022-11-30 02:35:12 +01:00
Vincent Vandemeulebrouck
13135ff2ca Version 10.3.0 2022-11-30 02:16:59 +01:00
Vincent Vandemeulebrouck
453e7da848 Création du compendium Faune, Flore, Minéraux
- les tables d'environnement se basent sur ce seul compendium
- les tables de compendiums peuvent chercher plusieurs types d'items
- déplacement de la botanique
- déplacement des sels alchimiques depuis l'équipement
- modification de l'équipement de départ
- modification des acteurs (lien vers compendium de l'item source)
2022-11-30 02:12:31 +01:00
Vincent Vandemeulebrouck
b7a0e5d034 Fréquences par milieu pour l'environnement
Les herbes et les ingrédients peuvent être cherchées/tirées
2022-11-30 02:06:46 +01:00
Vincent Vandemeulebrouck
b7a8b0c08d Standardisation inventaire et prix
Les objets d'inventaire ont maintenant tous:
coût, encombrement, qualité, quantité

Le coût est toujours exprimé en sols, y compris pour les monnaies.
Les paiements et achat-ventes sont fait en sols.
2022-11-29 11:37:49 +01:00
Vincent Vandemeulebrouck
7557d33c73 Feuille de véhicule avec compteurs 2022-11-29 11:37:49 +01:00
Vincent Vandemeulebrouck
e35f77b5a8 Cleanup
- Partage méthode pour label des types
- Methode joining pour concaténation
- suppression template obsolete
- Déplacement de singleton rencontre dans game.system.rdd
- init des commandes lazy
2022-11-29 11:37:11 +01:00
Vincent Vandemeulebrouck
dd4484c17b En-tête de feuille de personnage
Affichage des portraits plus grands
Les boutons sont sur la ligne du nom du personnage
Les états sont affichés sur une colonne
2022-11-29 00:04:50 +01:00
Vincent Vandemeulebrouck
4bd2c1c2b4 Notion d'équipement/inventaire 2022-11-29 00:04:38 +01:00
Vincent Vandemeulebrouck
42c4fe0b29 Standardisation des descriptions
Utilisation des templates sur les items pour la description
2022-11-28 21:02:32 +01:00
Vincent Vandemeulebrouck
39c6478422 Affichage des images de tarot 2022-11-28 21:02:32 +01:00
Vincent Vandemeulebrouck
c06491eb2f Ne pas tronquer les images
Corrections des tailles d'images pour éviter de tronquer
2022-11-28 21:02:32 +01:00
Vincent Vandemeulebrouck
e869d15b24 Correction mise à jour état général 2022-11-28 21:02:32 +01:00
Vincent Vandemeulebrouck
7045b6d8e1 Amélioration du message de confirmation 2022-11-28 21:02:32 +01:00
431d3199db Merge pull request 'v10.2.10: Gestion des tables depuis les compendiums' (#581) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #581
2022-11-26 18:42:10 +01:00
Vincent Vandemeulebrouck
5555705912 10.2.10 2022-11-26 18:12:44 +01:00
Vincent Vandemeulebrouck
4a51f698ab Fix regressions liste dans conteneurs
Les lignes étaient affichées de manière étrange et peu lisible
2022-11-26 18:12:31 +01:00
Vincent Vandemeulebrouck
029bece877 Gestion des désir lancinant/idée fixe
Ajout d'un flag pour les identifier.
2022-11-26 16:58:53 +01:00
Vincent Vandemeulebrouck
31eabbce23 Fix fréquence Mauvais reflet d'ancien rêve 2022-11-26 16:58:53 +01:00
Vincent Vandemeulebrouck
7200ff529f Cleanup 2022-11-26 16:58:53 +01:00
Vincent Vandemeulebrouck
0dacbefd6b Tirer dans les compendiums selon les fréquences 2022-11-26 16:58:53 +01:00
970be67537 Increase release, VincentVK fixes 2022-11-25 07:35:19 +01:00
53aa9cd643 Merge pull request 'Corrections des jets de dés' (#580) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #580
2022-11-25 07:33:53 +01:00
Vincent Vandemeulebrouck
c435bfa343 Chronologie et année
Fix jour dans chronologie
Permettre de saisir l'année
2022-11-25 03:17:27 +01:00
Vincent Vandemeulebrouck
8667d77169 Ajout de champs pour les tables-compendium
Le champ "frequence" sert à rêgler le nombre d'occurences d'une entrée
du compendium. Le total des fréquences donnera le dé à lancer pour
tirer dans la table. Il servira pour réguler l'apparition des
queues/souffles/... d'un compendium sans avoir besoin de déclarer une
RollTable.

Le champ "hautrevant" permet d'indiquer les queues/souffles/...
réservés aux haut-rêvants.
2022-11-25 03:17:27 +01:00
Vincent Vandemeulebrouck
5e7fcf3c9b fit-content pour toutes les fenêtres roll
C'est le comportement par défaut, donc enlever les surcharges
Corrections pour les fenêtres de combat
2022-11-25 03:17:27 +01:00
Vincent Vandemeulebrouck
e78ae3b292 Chargement depuis les compendium sélectionnés
Fix, les compendiums systèmes n'étaient pas utilisés pour les herbes
et les compétences
2022-11-25 03:17:27 +01:00
Vincent Vandemeulebrouck
97ee5bc331 Amélioration possession
- Créer la possession lors de la première attaque
- Le personnage ciblé par la possession est affiché
2022-11-25 03:17:27 +01:00
Vincent Vandemeulebrouck
c3c0bbc922 Fix jets de caracs dérivées
Appel à la chance, jets de rêve actuel: pas de liste de compétences
2022-11-25 03:17:26 +01:00
Vincent Vandemeulebrouck
9992b64cae Corrections sur les ajustements
- le malus de sur-encombrement est correctement calculé (dans la
  zone d'état)
- par défaut, le sur-encombrement est appliqué
- le sur-encombrement est affiché sur les actions physiques
- l'encombrement s'applique à agilité/dérobée, avec natation/acrobatie
  (par défaut)
- le moral est géré dans le noeud 'use' du rollData
- le moral est associé aux actions physiques
2022-11-25 03:17:26 +01:00
Vincent Vandemeulebrouck
7698147e97 Affichage de la cible dans la fenêtre d'attaque 2022-11-23 22:42:18 +01:00
81aaf9e8d7 Merge pull request 'Choisir parmi plusieurs cibles' (#579) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #579
2022-11-23 08:24:17 +01:00
Vincent Vandemeulebrouck
8e1b33d964 Version 10.2.8 2022-11-23 00:14:55 +01:00
Vincent Vandemeulebrouck
eca61fff57 Fix: hauteur des onglets Foundry
Le texte des onglets de configuration Foundry (vision des tokens,
lumières par exemple) sont sur plusieurs lignes.

La réduction de la hauteur des lignes éviter que le titre de l'onglet
soit par dessus le contenu.

Fixe aussi l'onglêt "haut-rêve" si la fenêtre d'acteur est de largeur
réduite.
2022-11-23 00:13:33 +01:00
Vincent Vandemeulebrouck
acc5ddac08 Simplifier la sélection
Lorsque plusieurs tokens sont ciblés, laisser le joueur choisir parmi
ceux-là
2022-11-23 00:13:33 +01:00
06024a0007 Merg/Increase release 2022-11-22 07:39:31 +01:00
da9158e718 Merge pull request 'Autoriser le combat sans cible' (#578) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #578
2022-11-22 07:38:11 +01:00
Vincent Vandemeulebrouck
f57f03547a Autoriser le combat sans cible 2022-11-22 02:15:51 +01:00
Vincent Vandemeulebrouck
5424763ad6 Cleanup 2022-11-22 02:15:51 +01:00
3543ce60cb Fix armes naturelles/corps à corps 2022-11-20 16:08:48 +01:00
5ba86f12df Merge pull request 'v10.2.5' (#577) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #577
2022-11-19 16:47:17 +01:00
Vincent Vandemeulebrouck
424cdd3e65 v10.2.5 2022-11-19 01:49:38 +01:00
Vincent Vandemeulebrouck
3362f2473a Jet de Carac avec compétence
Pour faire plus rapidement les jets depuis les caracs
2022-11-19 01:38:30 +01:00
Vincent Vandemeulebrouck
5565bb7a48 Fix des malus encombrement 2022-11-19 01:38:29 +01:00
Vincent Vandemeulebrouck
f953348f4e Séparation des tir/mêlée/lancer
Migration automatique des objets du monde et de ses acteurs
Migration des objets des compendiums
2022-11-19 01:38:29 +01:00
Vincent Vandemeulebrouck
702af37961 Cleanup 2022-11-19 01:38:29 +01:00
73718070cf Mrege Vincent + suppression doublons 2022-11-18 11:33:46 +01:00
091ce15dce Merge pull request 'v10' (#576) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #576
2022-11-18 11:24:12 +01:00
Vincent Vandemeulebrouck
cdde7c5f2f Le lancer des armes
On peut maintenant configurer une arme de mélée pour
être lancée
2022-11-18 03:38:32 +01:00
Vincent Vandemeulebrouck
eb0afffbd6 Information sur le mode de TMR
Affichage d'information en cas de mode visualisation, ou si le MJ
monte dans les TMR avec le personnage d'un joueur
2022-11-18 03:38:32 +01:00
6b0c7f4d38 Merge Vincent fixes + carquois en double 2022-11-17 10:38:11 +01:00
dd2109735d Merge pull request 'Fix de régressions, stabilisation' (#575) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #575
2022-11-17 10:34:57 +01:00
Vincent Vandemeulebrouck
0b192d66c3 Fix commandes et aides
- corrections de commandes sans paramêtre pour proposer l'aide
- correction de l'aide /tmrr (qui peut lancer des dés différents si les
  compendiums sont changés)
2022-11-17 01:57:36 +01:00
Vincent Vandemeulebrouck
472cbb372e Fix du calcul des données calendrier
- Utilisation de la méthode getDefSigne pour obtenir le détail
du signe de l'heure / du mois

- fix d'une initialisation du mois qui faussait le calendrier
2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
8d2e7fd0c8 Fit content pour dialog chronologie/calendrier
Suppression de l'espace perdu
2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
c8526a2270 Amélioration /tmrr
- support des mauvaises rencontres avec /tmrr Mauvaise
- recherche "intelligente": /tmrr ci pour lancer une rencontre en cité
2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
8b6abcc8bb Suppression bouton default
Pour éviter qu'un dialog ouvert depuis le tchat se valide tout seul
aux ouvertures suivantes
2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
468982b07b Fix décrément qty ChatMessage vente
Régression suite aux fix sur les achat-vente
2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
95179ffff2 Cleanup 2022-11-17 01:25:50 +01:00
Vincent Vandemeulebrouck
884733e54b Suppression de modèle non utlisé
Sans doute rémanensce d'un état intermédiare de l'extraction des
Item rencontres
2022-11-17 01:25:49 +01:00
a2d4b1049e Inc release 2022-11-16 21:48:41 +01:00
3ce3898326 Merge pull request 'Amélioration esthétique' (#574) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #574
2022-11-16 20:59:24 +01:00
Vincent Vandemeulebrouck
32fc0019d5 Compendium d'extraits poétiques
Permet de surcharger le compendium. Un compendium vide permet de
ne plus avoir d'extraits. D'autres textes peuvent être utilisés avec
un compendium personalisé.
2022-11-16 03:00:55 +01:00
Vincent Vandemeulebrouck
f3f928e43f Cleanup 2022-11-16 03:00:55 +01:00
Vincent Vandemeulebrouck
374a0e1846 Fix: Affichage de l'heure plutôt que du code
Dans le message de déclenchement de sorts en réserve
2022-11-16 03:00:55 +01:00
Vincent Vandemeulebrouck
1e5a99e009 Hauteur des fenêtre 'fit-content'
Evite d'avoir tout le temps des tailles mal ajustées
2022-11-16 03:00:55 +01:00
64320fc260 Merge Vincent fixes pour la boisson 2022-11-13 23:16:39 +01:00
ff923ebab2 Merge pull request '10.0.2.1' (#573) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #573
2022-11-13 23:15:44 +01:00
Vincent Vandemeulebrouck
bcd25dd0ed Affichage de dialog en 2 temps
Sinon, la touche entrée est appliqué sur une commande et ferme
le dialogue
2022-11-13 21:57:48 +01:00
Vincent Vandemeulebrouck
ccb6709f5b Fix: Nourriture consommée par le bon user 2022-11-13 21:57:48 +01:00
2fe6b472a2 Upgrade version to 10.2.0 2022-11-10 07:25:42 +01:00
01642ba495 Merge pull request 'Les rencontres sont configurables' (#572) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #572
2022-11-10 07:24:52 +01:00
Vincent Vandemeulebrouck
191d23e903 Nouveaux effets de rencontre
Gain de 1 point de rêve
Perte de (force) points de vie
Gain de 1 point de moral
Perte de 1 point de moral
Gain de (force) xp sort
Perte de 1 point d'endurance
Perte de (force) points d'endurance
Coup de fatigue de 1 point
Coup de fatigue de (force) points
Récupération de 1 point de fatigue
Récupération de (force) points de fatigue
Perte de chance actuelle
Perte de 1 point de chance actuelle
Gain de 1 point de stress
2022-11-10 02:05:16 +01:00
Vincent Vandemeulebrouck
be57a52f61 Suppression du jet de rencontre de test 2022-11-10 00:59:25 +01:00
Vincent Vandemeulebrouck
c2e8621405 Idées de nouvelles rencontres 2022-11-10 00:42:01 +01:00
Vincent Vandemeulebrouck
d3533f5627 Fix description mauvaise rencontre
Le tirage est fait automatiquement
2022-11-10 00:42:01 +01:00
Vincent Vandemeulebrouck
db448028f9 Gestion de la tête Augmentation de seuil 2022-11-10 00:42:01 +01:00
Vincent Vandemeulebrouck
f659a7508a Remplacement progressif rencontres 2022-11-10 00:42:01 +01:00
Vincent Vandemeulebrouck
d20a6a1506 Suppression de setForceRencontre
On pourra se créer des rencontres et les placer sur la feuille du
personnage
2022-11-10 00:42:00 +01:00
Vincent Vandemeulebrouck
d724e9eb17 Affichage des Items rencontres sur Actor 2022-11-10 00:42:00 +01:00
Vincent Vandemeulebrouck
2106e6ebef Table de rencontre sur une TMR
Au lieu de passer le type de TMR, passer la TMR {type,
coordonnées}

Ce qui permettra de créer une rencontre avec les coordonnées
si disponible
2022-11-10 00:42:00 +01:00
Vincent Vandemeulebrouck
dc07b60acf Compendium de rencontres 2022-11-10 00:42:00 +01:00
Vincent Vandemeulebrouck
d77f046a6a Ajout d'Item rencontre
Pour l'instant, pas utilisée. Une rencontre permettra de
définir les différents effets de la rencontre.

Un compendium dédié donnera les rencontres possibles.
2022-11-10 00:41:47 +01:00
Vincent Vandemeulebrouck
73c490a91d Compendiums paramétrables 2022-11-10 00:41:47 +01:00
Vincent Vandemeulebrouck
ce562b6b8a Déplacement des différents settings 2022-11-10 00:41:47 +01:00
Vincent Vandemeulebrouck
9ea4c05199 Compendiums privés par défaut
Pour que le Gardien n'ait pas à configurer tout en privé à la main
2022-11-10 00:41:47 +01:00
Vincent Vandemeulebrouck
e198cb60b1 Cleanup & Reformatage 2022-11-10 00:41:47 +01:00
Vincent Vandemeulebrouck
d183ce505a gitignore dossier "ignored"
Pour stocker des fichiers temporaires/intermédiaires
2022-11-07 00:05:55 +01:00
Vincent Vandemeulebrouck
9d1dec4179 Amélioration de l'apparence de recherche 2022-11-05 18:20:24 +01:00
e5e4ca75ea New relase v10.1.0 - Chrono features 2022-11-04 23:55:49 +01:00
adc8645453 Merge pull request 'Notes chronologiques et autres' (#571) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: #571
2022-11-04 23:53:44 +01:00
Vincent Vandemeulebrouck
708d00e75c Version 10.0.33
- petite amélioration visuelle de la recherche de compétence
- ajout de notes chronologiques
- utilisation des noms de compétences draconiques (ce qui permet
  au gardien de créer ses propres voies draconiques)

Technique:
- normalisation des noms de fichiers templates enum
- suppressions de templates inutiles
- petit nettoyage de paramêtres et imports en passant
- petite factorisation css
2022-11-04 20:45:52 +01:00
Vincent Vandemeulebrouck
ecd1652403 Ajout de notes chronologiques 2022-11-04 20:41:16 +01:00
Vincent Vandemeulebrouck
42e4f5b391 Simplification css
Utiliser :is(...)  permet de factoriser
2022-11-01 23:45:17 +01:00
Vincent Vandemeulebrouck
afb0f58ec1 Renommage paramètre 2022-11-01 23:44:18 +01:00
Vincent Vandemeulebrouck
42e3caa448 Suppression import inutile 2022-11-01 23:43:53 +01:00
Vincent Vandemeulebrouck
12a5cebc2d Amélioration rendu de la recherche
Icône dans la zone de saisie pour plus de clarté
2022-11-01 23:43:33 +01:00
Vincent Vandemeulebrouck
65e7574106 Renommage des templates d'enums
(suppression de templates inutilisés)
2022-11-01 01:03:35 +01:00
Vincent Vandemeulebrouck
ca01bc2605 Utilisation de la compétence draconic
Utiliser le nom de la compétence au lieu du nom de la voie:

=> "Voie d'Hypnos" au lieu de "hypnos"

Permet de définir d'autres compétences de draconic.

Fix de la mise de sort en réserve: utilise correctement l'id du sort
Migration des sorts et sorts en réserve du monde
Migration des compendiums
2022-11-01 00:49:28 +01:00
Vincent Vandemeulebrouck
ad9f04de4a Renommage templates options
prefix enum

Objectif long terme: faire le tri des templates partials vs autres
2022-11-01 00:49:28 +01:00
255 changed files with 7653 additions and 5676 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
.vscode/settings.json .vscode/settings.json
.idea .idea
todo.txt
todo.md todo.md
/.vscode /.vscode
/ignored/

BIN
icons/faune/Escargot.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
icons/faune/andurak.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
icons/faune/barbon.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
icons/faune/brocart.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
icons/faune/cancre.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

BIN
icons/faune/cancrelas.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
icons/faune/cerf.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

BIN
icons/faune/chamois.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icons/faune/chevre.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
icons/faune/colimace.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
icons/faune/coquille.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
icons/faune/crabe.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
icons/faune/fretin.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/faune/lapin.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

BIN
icons/faune/oie.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
icons/faune/oiseau.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
icons/faune/ours.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icons/faune/padongre.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
icons/faune/poisson.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
icons/faune/rongeur.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
icons/faune/sanglier.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icons/faune/saumon.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
icons/faune/singe-vert.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
icons/faune/soldieze.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
icons/faune/ver.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
icons/faune/wolf-head.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -15,11 +15,12 @@
"TypeNombreastral": "Nombre astral", "TypeNombreastral": "Nombre astral",
"TypeTarot": "Carte de tarot", "TypeTarot": "Carte de tarot",
"TypeCasetmr": "TMR spéciale", "TypeCasetmr": "TMR spéciale",
"TypeRencontrestmr": "Rencontre TMR", "TypeRencontre": "Rencontre TMR",
"TypeMunition": "Munition", "TypeMunition": "Munition",
"TypeMonnaie": "Monnaie", "TypeMonnaie": "Monnaie",
"TypeHerbe": "Herbe ou plante", "TypeHerbe": "Herbe ou plante",
"TypeIngredient": "Ingrédient", "TypeIngredient": "Ingrédient",
"TypeFaune": "Faune",
"TypeLivre": "Livre", "TypeLivre": "Livre",
"TypePotion": "Potion", "TypePotion": "Potion",
"TypeArme": "Arme", "TypeArme": "Arme",
@@ -42,7 +43,8 @@
"TypeSouffle": "Souffle de Dragon", "TypeSouffle": "Souffle de Dragon",
"TypeTete": "Tête de Dragon", "TypeTete": "Tête de Dragon",
"TypePossession": "Possession", "TypePossession": "Possession",
"TypeSortreserve": "Sort en réserve" "TypeSortreserve": "Sort en réserve",
"TypeExtraitpoetique": "Extrait poetique"
}, },
"EFFECT": { "EFFECT": {
"StatusStunned": "Sonné", "StatusStunned": "Sonné",

View File

@@ -1,14 +1,9 @@
import { RdDActorSheet } from "./actor-sheet.js";
/** /**
* Extend the basic ActorSheet with some very simple modifications * Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet} * @extends {ActorSheet}
*/ */
import { RdDUtility } from "./rdd-utility.js";
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDCarac } from "./rdd-carac.js";
/* -------------------------------------------- */
export class RdDActorCreatureSheet extends RdDActorSheet { export class RdDActorCreatureSheet extends RdDActorSheet {
/** @override */ /** @override */
@@ -19,7 +14,7 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
width: 640, width: 640,
height: 720, height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }] dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
}); });
} }
@@ -32,15 +27,15 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
if (!this.options.editable) return; if (!this.options.editable) return;
// On competence change // On competence change
html.find('.creature-carac').change(async event => { this.html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
}); });
html.find('.creature-niveau').change(async event => { this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
}); });
html.find('.creature-dommages').change(async event => { this.html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value)); this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
}); });

View File

@@ -1,6 +1,4 @@
import { RdDActorSheet } from "./actor-sheet.js"; import { RdDActorSheet } from "./actor-sheet.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDActorEntiteSheet extends RdDActorSheet { export class RdDActorEntiteSheet extends RdDActorSheet {
@@ -12,7 +10,7 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
width: 640, width: 640,
height: 720, height: 720,
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}], tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}],
dragDrop: [{dragSelector: ".item-list .item", dropSelector: null}] dragDrop: [{dragSelector: ".item-list .item", dropSelector: undefined}]
}); });
} }
@@ -25,15 +23,15 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
if (!this.options.editable) return; if (!this.options.editable) return;
// On competence change // On competence change
html.find('.creature-carac').change(async event => { this.html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) ); this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) );
} ); } );
html.find('.creature-niveau').change(async event => { this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) ); this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) );
} ); } );
html.find('.creature-dommages').change(async event => { this.html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) ); this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) );
} ); } );

View File

@@ -1,8 +1,3 @@
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { RdDItemArme } from "./item-arme.js"; import { RdDItemArme } from "./item-arme.js";
@@ -12,12 +7,16 @@ import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js"; import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { DialogRepos } from "./dialog-repos.js"; import { DialogRepos } from "./dialog-repos.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorSheet extends ActorSheet { export class RdDActorSheet extends ActorSheet {
/** @override */ /** @override */
@@ -26,9 +25,9 @@ export class RdDActorSheet extends ActorSheet {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"], classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html", template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
width: 640, width: 550,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }], dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
showCompNiveauBase: false, showCompNiveauBase: false,
vueDetaillee: false vueDetaillee: false
}); });
@@ -37,6 +36,7 @@ export class RdDActorSheet extends ActorSheet {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getData() { async getData() {
this.timerRecherche = undefined; this.timerRecherche = undefined;
this.actor.computeEtatGeneral();
let formData = { let formData = {
title: this.title, title: this.title,
@@ -102,7 +102,6 @@ export class RdDActorSheet extends ActorSheet {
formData.hautreve = { formData.hautreve = {
isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve), isDemiReve: this.actor.getEffect(STATUSES.StatusDemiReve),
rencontres: duplicate(formData.system.reve.rencontre.list),
cacheTMR: this.actor.isTMRCache() cacheTMR: this.actor.isTMRCache()
} }
@@ -119,79 +118,26 @@ export class RdDActorSheet extends ActorSheet {
return formData; return formData;
} }
isCompetenceAffichable(competence) {
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
}
/* -------------------------------------------- */
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid);
this.actor.addSubActeur(dropActor);
super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = $(event.target)?.closest('.item').attr('data-item-id')
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor.id, dragData, this.objetVersConteneur)
const callSuper = await this.actor.processDropItem(dropParams)
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */
async createEmptyTache() {
await this.createItem('Nouvelle tache', 'tache');
}
/* -------------------------------------------- */ /** @override */ /* -------------------------------------------- */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue")); HtmlUtility._showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
// 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;
html.find('.item-split').click(async event => { this.html.find('.item-split').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor); const item = RdDSheetUtility.getItem(event, this.actor);
RdDSheetUtility.splitItem(item, this.actor); RdDSheetUtility.splitItem(item, this.actor);
}); });
html.find('.item-edit').click(async event => { this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true))
const item = RdDSheetUtility.getItem(event, this.actor) this.html.find('.item-delete').click(async event => RdDUtility.confirmerSuppressionItem(this, RdDSheetUtility.getItem(event, this.actor)));
item.sheet.render(true) this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
}) this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItem());
html.find('.display-label a').click(async event => { this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor));
const item = RdDSheetUtility.getItem(event, this.actor); this.html.find('.subacteur-delete').click(async event => {
item.sheet.render(true);
});
html.find('.rencontre-delete').click(async event => {
this.actor.deleteTMRRencontre(RdDSheetUtility.getItemId(event));
});
html.find('.item-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const item = this.actor.getObjet(li.data("item-id"));
RdDUtility.confirmerSuppressionItem(this, item, li);
});
html.find('.item-vendre').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.proposerVente();
});
html.find('.item-montrer').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.postItem();
});
html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor)
this.actor.actionItem(item);
});
html.find('.subacteur-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event); const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id"); const actorId = li.data("actor-id");
if (actorId) { if (actorId) {
@@ -199,54 +145,54 @@ export class RdDActorSheet extends ActorSheet {
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li); RdDUtility.confirmerSuppressionSubacteur(this, subActor, li);
} }
}); });
html.find('.experiencelog-delete').click(async event => { this.html.find('.experiencelog-delete').click(async event => {
const li = $(event.currentTarget)?.parents(".experiencelog"); const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1); const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(key, 1); await this.actor.deleteExperienceLog(key, 1);
}); });
html.find('.experiencelog-delete-previous').click(async event => { this.html.find('.experiencelog-delete-previous').click(async event => {
const li = $(event.currentTarget)?.parents(".experiencelog"); const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1); const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(0, key + 1); await this.actor.deleteExperienceLog(0, key + 1);
}); });
html.find('.encaisser-direct').click(async event => { this.html.find('.encaisser-direct').click(async event => {
this.actor.encaisser(); this.actor.encaisser();
}) })
html.find('.sheet-possession-attack').click(async event => { this.html.find('.sheet-possession-attack').click(async event => {
const poss = RdDSheetUtility.getItem(event, this.actor) const poss = RdDSheetUtility.getItem(event, this.actor)
this.actor.conjurerPossession(poss) this.actor.conjurerPossession(poss)
}) })
html.find('.remise-a-neuf').click(async event => { this.html.find('.remise-a-neuf').click(async event => {
if (game.user.isGM) { if (game.user.isGM) {
this.actor.remiseANeuf(); this.actor.remiseANeuf();
} }
}); });
html.find('.creer-tache').click(async event => { this.html.find('.creer-tache').click(async event => {
this.createEmptyTache(); this.createEmptyTache();
}); });
html.find('.creer-un-objet').click(async event => { this.html.find('.creer-un-objet').click(async event => {
RdDUtility.selectObjetType(this); RdDUtility.selectObjetType(this);
}); });
html.find('.creer-une-oeuvre').click(async event => { this.html.find('.creer-une-oeuvre').click(async event => {
RdDUtility.selectTypeOeuvre(this); RdDUtility.selectTypeOeuvre(this);
}); });
html.find('.nettoyer-conteneurs').click(async event => { this.html.find('.nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs(); this.actor.nettoyerConteneurs();
}); });
// Blessure control // Blessure control
html.find('.blessure-control').click(async event => { this.html.find('.blessure-control').click(async event => {
const tr = $(event.currentTarget).parents(".item"); const tr = this.html.find(event.currentTarget).parents(".item");
let btype = tr.data("blessure-type"); let btype = tr.data("blessure-type");
let index = tr.data('blessure-index'); let index = tr.data('blessure-index');
let active = $(event.currentTarget).data('blessure-active'); let active = this.html.find(event.currentTarget).data('blessure-active');
//console.log(btype, index, active); //console.log(btype, index, active);
await this.actor.manageBlessureFromSheet(btype, index, active); await this.actor.manageBlessureFromSheet(btype, index, active);
}); });
// Blessure data // Blessure data
html.find('.blessure-soins').change(async event => { this.html.find('.blessure-soins').change(async event => {
const tr = $(event.currentTarget).parents(".item"); const tr = this.html.find(event.currentTarget).parents(".item");
let btype = tr.data('blessure-type'); let btype = tr.data('blessure-type');
let index = tr.data('blessure-index'); let index = tr.data('blessure-index');
let psoins = tr.find('.blessure-premiers_soins').val(); let psoins = tr.find('.blessure-premiers_soins').val();
@@ -260,57 +206,57 @@ export class RdDActorSheet extends ActorSheet {
}); });
// Equip Inventory Item // Equip Inventory Item
html.find('.item-equip').click(async event => { this.html.find('.item-equip').click(async event => {
this.actor.equiperObjet(RdDSheetUtility.getItemId(event)); this.actor.equiperObjet(RdDSheetUtility.getItemId(event));
}); });
// Roll Carac // Roll Carac
html.find('.carac-label a').click(async event => { this.html.find('.carac-label a').click(async event => {
let caracName = event.currentTarget.attributes.name.value; let caracName = event.currentTarget.attributes.name.value;
this.actor.rollCarac(caracName.toLowerCase()); this.actor.rollCarac(caracName.toLowerCase());
}); });
html.find('.chance-actuelle').click(async event => { this.html.find('.chance-actuelle').click(async event => {
this.actor.rollCarac('chance-actuelle'); this.actor.rollCarac('chance-actuelle');
}); });
html.find('.chance-appel').click(async event => { this.html.find('.chance-appel').click(async event => {
this.actor.rollAppelChance(); this.actor.rollAppelChance();
}); });
html.find('#jet-astrologie').click(async event => { this.html.find('[name="jet-astrologie"]').click(async event => {
this.actor.astrologieNombresAstraux(); this.actor.astrologieNombresAstraux();
}); });
// Roll Skill // Roll Skill
html.find('a.competence-label').click(async event => { this.html.find('a.competence-label').click(async event => {
this.actor.rollCompetence(RdDSheetUtility.getItemId(event)); this.actor.rollCompetence(RdDSheetUtility.getItemId(event));
}); });
html.find('.tache-label a').click(async event => { this.html.find('.tache-label a').click(async event => {
this.actor.rollTache(RdDSheetUtility.getItemId(event)); this.actor.rollTache(RdDSheetUtility.getItemId(event));
}); });
html.find('.meditation-label a').click(async event => { this.html.find('.meditation-label a').click(async event => {
this.actor.rollMeditation(RdDSheetUtility.getItemId(event)); this.actor.rollMeditation(RdDSheetUtility.getItemId(event));
}); });
html.find('.chant-label a').click(async event => { this.html.find('.chant-label a').click(async event => {
this.actor.rollChant(RdDSheetUtility.getItemId(event)); this.actor.rollChant(RdDSheetUtility.getItemId(event));
}); });
html.find('.danse-label a').click(async event => { this.html.find('.danse-label a').click(async event => {
this.actor.rollDanse(RdDSheetUtility.getItemId(event)); this.actor.rollDanse(RdDSheetUtility.getItemId(event));
}); });
html.find('.musique-label a').click(async event => { this.html.find('.musique-label a').click(async event => {
this.actor.rollMusique(RdDSheetUtility.getItemId(event)); this.actor.rollMusique(RdDSheetUtility.getItemId(event));
}); });
html.find('.oeuvre-label a').click(async event => { this.html.find('.oeuvre-label a').click(async event => {
this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)); this.actor.rollOeuvre(RdDSheetUtility.getItemId(event));
}); });
html.find('.jeu-label a').click(async event => { this.html.find('.jeu-label a').click(async event => {
this.actor.rollJeu(RdDSheetUtility.getItemId(event)); this.actor.rollJeu(RdDSheetUtility.getItemId(event));
}); });
html.find('.recettecuisine-label a').click(async event => { this.html.find('.recettecuisine-label a').click(async event => {
this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)); this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event));
}); });
html.find('.subacteur-label a').click(async event => { this.html.find('.subacteur-label a').click(async event => {
let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id'); let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id');
let actor = game.actors.get(actorId); let actor = game.actors.get(actorId);
if (actor) { if (actor) {
@@ -319,25 +265,25 @@ export class RdDActorSheet extends ActorSheet {
}); });
// Boutons spéciaux MJs // Boutons spéciaux MJs
html.find('.forcer-tmr-aleatoire').click(async event => { this.html.find('.forcer-tmr-aleatoire').click(async event => {
this.actor.reinsertionAleatoire("Action MJ"); this.actor.reinsertionAleatoire("Action MJ");
}); });
html.find('.afficher-tmr').click(async event => { this.html.find('.afficher-tmr').click(async event => {
this.actor.changeTMRVisible(); this.actor.changeTMRVisible();
}); });
// Points de reve actuel // Points de reve actuel
html.find('.ptreve-actuel a').click(async event => { this.html.find('.ptreve-actuel a').click(async event => {
this.actor.rollCarac('reve-actuel'); this.actor.rollCarac('reve-actuel');
}); });
// Roll Weapon1 // Roll Weapon1
html.find('.arme-label a').click(async event => { this.html.find('.arme-label a').click(async event => {
let arme = this._getEventArmeCombat(event); let arme = this._getEventArmeCombat(event);
this.actor.rollArme(duplicate(arme)); this.actor.rollArme(duplicate(arme));
}); });
// Initiative pour l'arme // Initiative pour l'arme
html.find('.arme-initiative a').click(async event => { this.html.find('.arme-initiative a').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); let action = this._getEventArmeCombat(event);
@@ -347,88 +293,88 @@ export class RdDActorSheet extends ActorSheet {
} }
}); });
// Display TMR, visualisation // Display TMR, visualisation
html.find('.visu-tmr').click(async event => { this.html.find('.visu-tmr').click(async event => {
this.actor.displayTMR("visu"); this.actor.displayTMR("visu");
}); });
// Display TMR, normal // Display TMR, normal
html.find('.monte-tmr').click(async event => { this.html.find('.monte-tmr').click(async event => {
this.actor.displayTMR("normal"); this.actor.displayTMR("normal");
}); });
// Display TMR, fast // Display TMR, fast
html.find('.monte-tmr-rapide').click(async event => { this.html.find('.monte-tmr-rapide').click(async event => {
this.actor.displayTMR("rapide"); this.actor.displayTMR("rapide");
}); });
html.find('.repos').click(async event => { this.html.find('.repos').click(async event => {
await DialogRepos.create(this.actor); await DialogRepos.create(this.actor);
}); });
html.find('.delete-active-effect').click(async event => { this.html.find('.delete-active-effect').click(async event => {
if (game.user.isGM) { if (game.user.isGM) {
let effect = $(event.currentTarget).parents(".active-effect").data('effect'); let effect = this.html.find(event.currentTarget).parents(".active-effect").data('effect');
this.actor.removeEffect(effect); this.actor.removeEffect(effect);
} }
}); });
html.find('.enlever-tous-effets').click(async event => { this.html.find('.enlever-tous-effets').click(async event => {
if (game.user.isGM) { if (game.user.isGM) {
await this.actor.removeEffects(); await this.actor.removeEffects();
} }
}); });
html.find('.conteneur-name a').click(async event => { this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event)); RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true); this.render(true);
}); });
html.find('.carac-xp-augmenter').click(async event => { this.html.find('.carac-xp-augmenter').click(async event => {
let caracName = event.currentTarget.name.replace("augmenter.", ""); let caracName = event.currentTarget.name.replace("augmenter.", "");
this.actor.updateCaracXPAuto(caracName); this.actor.updateCaracXPAuto(caracName);
}); });
html.find('.competence-xp-augmenter').click(async event => { this.html.find('.competence-xp-augmenter').click(async event => {
this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)); this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event));
}); });
html.find('.competence-stress-augmenter').click(async event => { this.html.find('.competence-stress-augmenter').click(async event => {
this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)); this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event));
}); });
if (this.options.vueDetaillee) { if (this.options.vueDetaillee) {
// On carac change // On carac change
html.find('.carac-value').change(async event => { this.html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", ""); let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
this.actor.updateCarac(caracName, parseInt(event.target.value)); this.actor.updateCarac(caracName, parseInt(event.target.value));
}); });
html.find('input.carac-xp').change(async event => { this.html.find('input.carac-xp').change(async event => {
let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", ""); let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", "");
this.actor.updateCaracXP(caracName, parseInt(event.target.value)); this.actor.updateCaracXP(caracName, parseInt(event.target.value));
}); });
// On competence change // On competence change
html.find('.competence-value').change(async event => { this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName); //console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value)); this.actor.updateCompetence(compName, parseInt(event.target.value));
}); });
// On competence xp change // On competence xp change
html.find('input.competence-xp').change(async event => { this.html.find('input.competence-xp').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXP(compName, parseInt(event.target.value)); this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
}); });
// On competence xp change // On competence xp change
html.find('input.competence-xp-sort').change(async event => { this.html.find('input.competence-xp-sort').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value)); this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
}); });
// On competence archetype change // On competence archetype change
html.find('.competence-archetype').change(async event => { this.html.find('.competence-archetype').change(async event => {
let compName = event.currentTarget.attributes.compname.value; let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value)); this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
}); });
} }
html.find('.show-hide-competences').click(async event => { this.html.find('.show-hide-competences').click(async event => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase; this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true); this.render(true);
}); });
html.find('.recherche') this.html.find('.recherche')
.each((index, field) => { .each((index, field) => {
if (this.options.recherche) { if (this.options.recherche) {
field.focus(); field.focus();
@@ -451,92 +397,125 @@ export class RdDActorSheet extends ActorSheet {
.change(async event => .change(async event =>
this.options.recherche = this._optionRecherche(event.currentTarget) this.options.recherche = this._optionRecherche(event.currentTarget)
); );
html.find('.vue-detaillee').click(async event => { this.html.find('.vue-detaillee').click(async event => {
this.options.vueDetaillee = !this.options.vueDetaillee; this.options.vueDetaillee = !this.options.vueDetaillee;
this.render(true); this.render(true);
}); });
// On pts de reve change // On pts de reve change
html.find('.pointsreve-value').change(async event => { this.html.find('.pointsreve-value').change(async event => {
let reveValue = event.currentTarget.value; let reveValue = event.currentTarget.value;
this.actor.update({ "system.reve.reve.value": reveValue }); this.actor.update({ "system.reve.reve.value": reveValue });
}); });
// On seuil de reve change // On seuil de reve change
html.find('.seuil-reve-value').change(async event => { this.html.find('.seuil-reve-value').change(async event => {
console.log("seuil-reve-value", event.currentTarget) console.log("seuil-reve-value", event.currentTarget)
this.actor.setPointsDeSeuil(event.currentTarget.value); this.actor.setPointsDeSeuil(event.currentTarget.value);
}); });
html.find('#attribut-protection-edit').change(async event => { this.html.find('#attribut-protection-edit').change(async event => {
this.actor.updateAttributeValue(event.currentTarget.attributes.name.value, parseInt(event.target.value)); this.actor.updateAttributeValue(event.currentTarget.attributes.name.value, parseInt(event.target.value));
}); });
// On stress change // On stress change
html.find('.compteur-edit').change(async event => { this.html.find('.compteur-edit').change(async event => {
let fieldName = event.currentTarget.attributes.name.value; let fieldName = event.currentTarget.attributes.name.value;
this.actor.updateCompteurValue(fieldName, parseInt(event.target.value)); this.actor.updateCompteurValue(fieldName, parseInt(event.target.value));
}); });
html.find('#ethylisme').change(async event => { this.html.find('#ethylisme').change(async event => {
this.actor.setEthylisme(parseInt(event.target.value)); this.actor.setEthylisme(parseInt(event.target.value));
}); });
html.find('.stress-test').click(async event => { this.html.find('.stress-test').click(async event => {
this.actor.transformerStress(); this.actor.transformerStress();
}); });
html.find('.moral-malheureux').click(async event => { this.html.find('.moral-malheureux').click(async event => {
this.actor.jetDeMoral('malheureuse'); this.actor.jetDeMoral('malheureuse');
}); });
html.find('.moral-neutre').click(async event => { this.html.find('.moral-neutre').click(async event => {
this.actor.jetDeMoral('neutre'); this.actor.jetDeMoral('neutre');
}); });
html.find('.moral-heureux').click(async event => { this.html.find('.moral-heureux').click(async event => {
this.actor.jetDeMoral('heureuse'); this.actor.jetDeMoral('heureuse');
}); });
html.find('.ethylisme-test').click(async event => { this.html.find('.ethylisme-test').click(async event => {
this.actor.jetEthylisme(); this.actor.jetEthylisme();
}); });
html.find('.jet-vie').click(async event => { this.html.find('.jet-vie').click(async event => {
this.actor.jetVie(); this.actor.jetVie();
}); });
html.find('.jet-endurance').click(async event => { this.html.find('.jet-endurance').click(async event => {
this.actor.jetEndurance(); this.actor.jetEndurance();
}); });
html.find('.monnaie-plus').click(async event => { this.html.find('.monnaie-plus').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1); this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
}); });
html.find('.monnaie-moins').click(async event => { this.html.find('.monnaie-moins').click(async event => {
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1); this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
}); });
html.find('.vie-plus').click(async event => { this.html.find('.vie-plus').click(async event => {
this.actor.santeIncDec("vie", 1); this.actor.santeIncDec("vie", 1);
}); });
html.find('.vie-moins').click(async event => { this.html.find('.vie-moins').click(async event => {
this.actor.santeIncDec("vie", -1); this.actor.santeIncDec("vie", -1);
}); });
html.find('.endurance-plus').click(async event => { this.html.find('.endurance-plus').click(async event => {
this.actor.santeIncDec("endurance", 1); this.actor.santeIncDec("endurance", 1);
}); });
html.find('.endurance-moins').click(async event => { this.html.find('.endurance-moins').click(async event => {
this.actor.santeIncDec("endurance", -1); this.actor.santeIncDec("endurance", -1);
}); });
html.find('.ptreve-actuel-plus').click(async event => { this.html.find('.ptreve-actuel-plus').click(async event => {
this.actor.reveActuelIncDec(1); this.actor.reveActuelIncDec(1);
}); });
html.find('.ptreve-actuel-moins').click(async event => { this.html.find('.ptreve-actuel-moins').click(async event => {
this.actor.reveActuelIncDec(-1); this.actor.reveActuelIncDec(-1);
}); });
html.find('.fatigue-plus').click(async event => { this.html.find('.fatigue-plus').click(async event => {
this.actor.santeIncDec("fatigue", 1); this.actor.santeIncDec("fatigue", 1);
}); });
html.find('.fatigue-moins').click(async event => { this.html.find('.fatigue-moins').click(async event => {
this.actor.santeIncDec("fatigue", -1); this.actor.santeIncDec("fatigue", -1);
}); });
} }
isCompetenceAffichable(competence) {
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
}
/* -------------------------------------------- */
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid);
this.actor.addSubActeur(dropActor);
super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id')
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur)
if (dropParams) {
const callSuper = await this.actor.processDropItem(dropParams)
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */
async createEmptyTache() {
await this.createItem('Nouvelle tache', 'tache');
}
_optionRecherche(target) { _optionRecherche(target) {
if (!target.value?.length){ if (!target.value?.length){
return undefined; return undefined;
@@ -549,7 +528,7 @@ export class RdDActorSheet extends ActorSheet {
} }
_getEventArmeCombat(event) { _getEventArmeCombat(event) {
const li = $(event.currentTarget)?.parents(".item"); const li = this.html.find(event.currentTarget)?.parents(".item");
let armeName = li.data("arme-name"); let armeName = li.data("arme-name");
let compName = li.data('competence-name'); let compName = li.data('competence-name');
const arme = this.armesList.find(a => a.name == armeName && a.system.competence == compName); const arme = this.armesList.find(a => a.name == armeName && a.system.competence == compName);

View File

@@ -1,5 +1,4 @@
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { RdDActorSheet } from "./actor-sheet.js"; import { RdDActorSheet } from "./actor-sheet.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -15,9 +14,26 @@ export class RdDActorVehiculeSheet extends RdDActorSheet {
width: 640, width: 640,
height: 720, height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }], tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }] dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
}); });
} }
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find('.resistance-moins').click(async event => {
this.actor.vehicleIncDec("resistance", -1);
});
this.html.find('.resistance-plus').click(async event => {
this.actor.vehicleIncDec("resistance", 1);
});
this.html.find('.structure-moins').click(async event => {
this.actor.vehicleIncDec("structure", -1);
});
this.html.find('.structure-plus').click(async event => {
this.actor.vehicleIncDec("structure", 1);
});
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
export class DialogChronologie extends Dialog {
static init() {
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
scope: "client",
config: false,
default: "",
type: String
});
}
static async create() {
const dateRdD = game.system.rdd.calendrier.getCalendrier();
const dialogData = {
auteur: game.user.name,
isGM: game.user.isGM,
information: "",
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
dateRdD: dateRdD,
jourRdD: dateRdD.jour +1,
heureRdD: game.system.rdd.calendrier.getCurrentHeure(),
dateReel: DialogChronologie.getCurrentDateTime()
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
const dialog = new DialogChronologie(html);
dialog.render(true);
}
constructor(html) {
const options = {
classes: ["DialogChronologie"],
width: 500,
height: 'fit-content',
'z-index': 99999
};
const conf = {
title: "Chronologie",
content: html,
buttons: {
ajout: { label: "Ajouter", callback: it => this.ajouter() },
}
};
super(conf, options);
}
static getCurrentDateTime() {
return new Date().toLocaleString("sv-SE", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit"
}).replace(" ", "T");
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
async ajouter() {
await this.forceValidation();
const { journalId, journalEntry } = this.findJournal();
// ajouter à la page ou créer une page
this.addContentToJournal(journalEntry, await this.prepareChronologieEntry());
this.storeLatestUsedJournalEntry(journalId);
}
async forceValidation() {
await this.html.find("form.rdddialogchrono :input").change();
}
findJournal() {
const journalId = this.html.find("form.rdddialogchrono :input[name='journalId']").val();
const journalEntry = game.journal.get(journalId);
return { journalId, journalEntry };
}
async prepareChronologieEntry() {
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", this.extractJournalParameters());
}
extractJournalParameters() {
return {
auteur: this.html.find("form.rdddialogchrono :input[name='auteur']").val(),
information: this.html.find("form.rdddialogchrono :input[name='information']").val(),
dateRdD: {
jour: this.html.find("form.rdddialogchrono :input[name='jourRdD']").val(),
moisRdD: this.html.find("form.rdddialogchrono :input[name='dateRdD.moisRdD.key']").val(),
annee: this.html.find("form.rdddialogchrono :input[name='dateRdD.annee']").val()
},
heureRdD: this.html.find("form.rdddialogchrono :input[name='heureRdD']").val(),
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ')
}
}
addContentToJournal(journalEntry, content) {
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, 'Chronologie'));
if (page) {
page.update({ 'text.content': content + '\n' + page.text.content });
}
else {
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(content)]);
}
}
newPageChronologie(content) {
return new JournalEntryPage({
name: 'Chronologie',
type: 'text',
title: { show: true, level: 1 },
text: { content: content, format: 1 }
});
}
storeLatestUsedJournalEntry(journalId) {
game.settings.set(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, journalId);
}
}

View File

@@ -35,16 +35,16 @@ export class DialogCreateSigneDraconique extends Dialog {
super(conf, options); super(conf, options);
this.dialogData = dialogData; this.dialogData = dialogData;
} }
async _onCreerSigneActeurs() { async _onCreerSigneActeurs() {
await $("[name='signe.system.ephemere']").change(); await this.html.find("[name='signe.system.ephemere']").change();
await $(".signe-xp-sort").change(); await this.html.find(".signe-xp-sort").change();
this.validerSigne(); this.validerSigne();
this.dialogData.actors.filter(it => it.selected) this.dialogData.actors.filter(it => it.selected)
.map(it => game.actors.get(it.id)) .map(it => game.actors.get(it.id))
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe)); .forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
} }
async _createSigneForActor(actor, signe) { async _createSigneForActor(actor, signe) {
actor.createEmbeddedDocuments("Item", [signe]); actor.createEmbeddedDocuments("Item", [signe]);
ChatMessage.create({ ChatMessage.create({
@@ -57,19 +57,20 @@ export class DialogCreateSigneDraconique extends Dialog {
} }
validerSigne() { validerSigne() {
this.dialogData.signe.name = $("[name='signe.name']").val(); this.dialogData.signe.name = this.html.find("[name='signe.name']").val();
this.dialogData.signe.system.valeur.norm = $("[name='signe.system.valeur.norm']").val(); this.dialogData.signe.system.valeur.norm = this.html.find("[name='signe.system.valeur.norm']").val();
this.dialogData.signe.system.valeur.sign = $("[name='signe.system.valeur.sign']").val(); this.dialogData.signe.system.valeur.sign = this.html.find("[name='signe.system.valeur.sign']").val();
this.dialogData.signe.system.valeur.part = $("[name='signe.system.valeur.part']").val(); this.dialogData.signe.system.valeur.part = this.html.find("[name='signe.system.valeur.part']").val();
this.dialogData.signe.system.difficulte = $("[name='signe.system.difficulte']").val(); this.dialogData.signe.system.difficulte = this.html.find("[name='signe.system.difficulte']").val();
this.dialogData.signe.system.ephemere = $("[name='signe.system.ephemere']").prop("checked"); this.dialogData.signe.system.ephemere = this.html.find("[name='signe.system.ephemere']").prop("checked");
this.dialogData.signe.system.duree = $("[name='signe.system.duree']").val(); this.dialogData.signe.system.duree = this.html.find("[name='signe.system.duree']").val();
this.dialogData.signe.system.typesTMR = TMRUtility.buildListTypesTMRSelection(this.dialogData.tmrs); this.dialogData.signe.system.typesTMR = TMRUtility.buildListTypesTMRSelection(this.dialogData.tmrs);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
this.setEphemere(this.dialogData.signe.system.ephemere); this.setEphemere(this.dialogData.signe.system.ephemere);
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire()); html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked)); html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
@@ -81,27 +82,27 @@ export class DialogCreateSigneDraconique extends Dialog {
async setSigneAleatoire() { async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true}); const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
$("[name='signe.name']").val(newSigne.name); this.html.find("[name='signe.name']").val(newSigne.name);
$("[name='signe.system.valeur.norm']").val(newSigne.system.valeur.norm); this.html.find("[name='signe.system.valeur.norm']").val(newSigne.system.valeur.norm);
$("[name='signe.system.valeur.sign']").val(newSigne.system.valeur.sign); this.html.find("[name='signe.system.valeur.sign']").val(newSigne.system.valeur.sign);
$("[name='signe.system.valeur.part']").val(newSigne.system.valeur.part); this.html.find("[name='signe.system.valeur.part']").val(newSigne.system.valeur.part);
$("[name='signe.system.difficulte']").val(newSigne.system.difficulte); this.html.find("[name='signe.system.difficulte']").val(newSigne.system.difficulte);
$("[name='signe.system.duree']").val(newSigne.system.duree); this.html.find("[name='signe.system.duree']").val(newSigne.system.duree);
$("[name='signe.system.ephemere']").prop("checked", newSigne.system.ephemere); this.html.find("[name='signe.system.ephemere']").prop("checked", newSigne.system.ephemere);
this.dialogData.tmrs = TMRUtility.buildSelectionTypesTMR(newSigne.system.typesTMR); this.dialogData.tmrs = TMRUtility.buildSelectionTypesTMR(newSigne.system.typesTMR);
this.dialogData.tmrs.forEach(t => { this.dialogData.tmrs.forEach(t => {
$(`[data-tmr-name='${t.name}']`).prop( "checked", t.selected); this.html.find(`[data-tmr-name='${t.name}']`).prop( "checked", t.selected);
}) })
this.setEphemere(newSigne.system.ephemere); this.setEphemere(newSigne.system.ephemere);
} }
async setEphemere(ephemere) { async setEphemere(ephemere) {
this.dialogData.signe.system.ephemere = ephemere; this.dialogData.signe.system.ephemere = ephemere;
HtmlUtility._showControlWhen($(".signe-system-duree"), ephemere); HtmlUtility._showControlWhen(this.html.find(".signe-system-duree"), ephemere);
} }
async onSelectActor(event) { async onSelectActor(event) {
const actorId = $(event.currentTarget)?.data("actor-id"); const actorId = this.html.find(event.currentTarget)?.data("actor-id");
const actor = this.dialogData.actors.find(it => it.id == actorId); const actor = this.dialogData.actors.find(it => it.id == actorId);
if (actor) { if (actor) {
actor.selected = event.currentTarget.checked; actor.selected = event.currentTarget.checked;
@@ -109,7 +110,7 @@ export class DialogCreateSigneDraconique extends Dialog {
} }
onSelectTmr(event) { onSelectTmr(event) {
const tmrName = $(event.currentTarget)?.data("tmr-name"); const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
const onTmr = this.tmrs.find(it => it.name == tmrName); const onTmr = this.tmrs.find(it => it.name == tmrName);
if (onTmr){ if (onTmr){
onTmr.selected = event.currentTarget.checked; onTmr.selected = event.currentTarget.checked;

View File

@@ -13,18 +13,12 @@ export class DialogFabriquerPotion extends Dialog {
} }
let potionData = DialogFabriquerPotion.prepareData(actor, item); let potionData = DialogFabriquerPotion.prepareData(actor, item);
let conf = { const html = await renderTemplate(dialogConfig.html, potionData);
title: `Fabriquer une potion de ${potionData.system.categorie}`,
content: await renderTemplate(dialogConfig.html, potionData),
default: potionData.buttonName,
};
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 }; let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true }) mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
const dialog = new DialogFabriquerPotion(actor, potionData, conf, options); new DialogFabriquerPotion(actor, potionData, html, options).render(true);
dialog.render(true);
return dialog;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -40,10 +34,15 @@ export class DialogFabriquerPotion extends Dialog {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(actor, potionData, conf, options) { constructor(actor, potionData, html, options) {
conf.buttons = { const conf = {
[potionData.buttonName]: { title: `Fabriquer une potion de ${potionData.system.categorie}`,
label: potionData.buttonName, callback: it => this.onFabriquer(it) content: html,
default: 'fabriquer',
buttons: {
'fabriquer': {
label: potionData.buttonName, callback: it => this.onFabriquer(html)
}
} }
}; };
@@ -53,6 +52,24 @@ export class DialogFabriquerPotion extends Dialog {
this.potionData = potionData; this.potionData = potionData;
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("[name='nbBrins']").change(event => {
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
});
}
/* -------------------------------------------- */
async onFabriquer(html) {
await this.html.find("[name='nbBrins']").change();
this.actor.fabriquerPotion(this.potionData);
this.close();
}
static nombreBrinsMinimum(herbeData) { static nombreBrinsMinimum(herbeData) {
switch (herbeData.system.categorie ?? '') { switch (herbeData.system.categorie ?? '') {
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau); case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau);
@@ -68,22 +85,4 @@ export class DialogFabriquerPotion extends Dialog {
} }
return 1; return 1;
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find("#nbBrins").change(event => {
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
});
}
/* -------------------------------------------- */
async onFabriquer(it) {
await $("#nbBrins").change();
this.actor.fabriquerPotion(this.potionData);
this.close();
}
} }

View File

@@ -1,6 +1,5 @@
import { Monnaie } from "./item-monnaie.js"; import { Monnaie } from "./item-monnaie.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
export class DialogItemAchat extends Dialog { export class DialogItemAchat extends Dialog {
@@ -19,9 +18,10 @@ export class DialogItemAchat extends Dialog {
return undefined; return undefined;
} }
const prixLot = Monnaie.arrondiDeniers(button.attributes['data-prixLot']?.value ?? 0); const prixLot = Number(button.attributes['data-prixLot']?.value ?? 0);
return { return {
item: json ? JSON.parse(json) : undefined, item: json ? JSON.parse(json) : undefined,
actingUserId: game.user.id,
vendeurId: vendeurId, vendeurId: vendeurId,
vendeur: vendeur, vendeur: vendeur,
acheteur: acheteur, acheteur: acheteur,
@@ -39,20 +39,20 @@ export class DialogItemAchat extends Dialog {
chatMessageIdVente: RdDUtility.findChatMessageId(button) chatMessageIdVente: RdDUtility.findChatMessageId(button)
}; };
} }
static async onAcheter(venteData) { static async onAcheter(venteData) {
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);
const dialog = new DialogItemAchat(html, venteData); new DialogItemAchat(html, venteData).render(true);
dialog.render(true);
} }
constructor(html, venteData) { constructor(html, venteData) {
const isConsommable = venteData.item.type == 'nourritureboisson' && venteData.acheteur?.isPersonnage(); const isConsommable = venteData.item.type == 'nourritureboisson' && venteData.acheteur?.isPersonnage();
let options = { classes: ["dialogachat"], width: 400, height: isConsommable ? 450 : 350, 'z-index': 99999 }; let options = { classes: ["dialogachat"], width: 400, height: 'fit-content', 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre"; const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
const buttons = {}; const buttons = {};
if (isConsommable) { if (isConsommable) {
buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => { this.onAchatConsommer(); } } buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => this.onAchatConsommer() }
} }
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } }; buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
buttons["decliner"] = { label: "Décliner", callback: it => { } }; buttons["decliner"] = { label: "Décliner", callback: it => { } };
@@ -64,19 +64,19 @@ export class DialogItemAchat extends Dialog {
}; };
super(conf, options); super(conf, options);
this.venteData = venteData; this.venteData = venteData;
} }
async onAchat() { async onAchat() {
await $(".nombreLots").change(); await this.html.find(".nombreLots").change();
(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({ (this.venteData.vendeur ?? this.venteData.acheteur).achatVente({
userId: game.user.id, userId: game.user.id,
vendeurId: this.venteData.vendeur?.id, vendeurId: this.venteData.vendeur?.id,
acheteurId: this.venteData.acheteur?.id, acheteurId: this.venteData.acheteur?.id,
prixTotal: this.venteData.prixTotal, prixTotal: this.venteData.prixTotal,
chatMessageIdVente: this.venteData.chatMessageIdVente, chatMessageIdVente: this.venteData.chatMessageIdVente,
choix: this.venteData.choix choix: this.venteData.choix,
vente: this.venteData
}); });
} }
@@ -88,9 +88,9 @@ export class DialogItemAchat extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value))); this.html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
html.find(".se-forcer").change(event => this.setSeForcer(event)); this.html.find(".se-forcer").change(event => this.setSeForcer(event));
} }
setSeForcer(event) { setSeForcer(event) {
@@ -103,8 +103,8 @@ export class DialogItemAchat extends Dialog {
} }
this.venteData.choix.nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots); this.venteData.choix.nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2); this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
$(".nombreLots").val(this.venteData.choix.nombreLots); this.html.find(".nombreLots").val(this.venteData.choix.nombreLots);
$(".prixTotal").text(this.venteData.prixTotal); this.html.find(".prixTotal").text(this.venteData.prixTotal);
} }
} }

View File

@@ -2,14 +2,14 @@ import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog { export class DialogConsommer extends Dialog {
static async create(actor, item, onActionItem = async ()=>{}) { static async create(actor, item, onActionItem = async () => { }) {
const consommerData = DialogConsommer.prepareData(actor, item); const consommerData = DialogConsommer.prepareData(actor, item);
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData); const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData);
return new DialogConsommer(actor, item, consommerData, html, onActionItem) return new DialogConsommer(actor, item, consommerData, html, onActionItem)
} }
constructor(actor, item, consommerData, html, onActionItem = async ()=>{}) { constructor(actor, item, consommerData, html, onActionItem = async () => { }) {
const options = { classes: ["dialogconsommer"], width: 350, height: 450, 'z-index': 99999 }; const options = { classes: ["dialogconsommer"], width: 350, height: 'fit-content', 'z-index': 99999 };
let conf = { let conf = {
title: consommerData.title, title: consommerData.title,
content: html, content: html,
@@ -17,8 +17,9 @@ export class DialogConsommer extends Dialog {
buttons: { buttons: {
[consommerData.buttonName]: { [consommerData.buttonName]: {
label: consommerData.buttonName, callback: async it => { label: consommerData.buttonName, callback: async it => {
await this.onConsommer(it); await this.onConsommer();
await onActionItem();} await onActionItem();
}
} }
} }
}; };
@@ -30,17 +31,23 @@ export class DialogConsommer extends Dialog {
this.consommerData = consommerData; this.consommerData = consommerData;
} }
async onConsommer(event) { activateListeners(html) {
await $(".se-forcer").change(); super.activateListeners(html);
await $(".consommer-doses").change(); this.html = html;
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
this.html.find(".consommer-doses").change(event => this.selectDoses(event));
}
async onConsommer() {
await this.html.find(".se-forcer").change();
await this.html.find(".consommer-doses").change();
await this.actor.consommer(this.item, this.consommerData.choix); await this.actor.consommer(this.item, this.consommerData.choix);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static prepareData(actor, item) { static prepareData(actor, item) {
item = duplicate(item);
let consommerData = { let consommerData = {
item: item, item: duplicate(item),
cuisine: actor.getCompetence('cuisine'), cuisine: actor.getCompetence('cuisine'),
choix: { choix: {
doses: 1, doses: 1,
@@ -48,33 +55,47 @@ export class DialogConsommer extends Dialog {
} }
} }
switch (item.type) { switch (item.type) {
case 'herbe': case 'faune':
consommerData.title = 'Manger une portion crue: ';
consommerData.buttonName = "Manger";
break;
case 'nourritureboisson': case 'nourritureboisson':
consommerData.title = item.system.boisson ? `${item.name}: boire une dose` : `${item.name}: manger une portion`; consommerData.title = item.system.boisson ? 'Boire une dose: ' : 'Manger une portion: ';
consommerData.buttonName = item.system.boisson ? "Boire" : "Manger"; consommerData.buttonName = item.system.boisson ? "Boire" : "Manger";
break; break;
case 'potion': case 'potion':
consommerData.title = `${item.name}: boire la potion`; consommerData.title = 'Boire la potion: ';
consommerData.buttonName = "Boire"; consommerData.buttonName = "Boire";
break; break;
} }
DialogConsommer.calculDoses(consommerData, consommerData.choix.doses) consommerData.title += item.name;
DialogConsommer.calculDoses(consommerData, item)
return consommerData; return consommerData;
} }
static calculDoses(consommer) { static calculDoses(consommer, item) {
const doses = consommer.choix.doses; const doses = consommer.choix.doses;
consommer.totalSust = Misc.keepDecimals(doses * (consommer.item.system.sust ?? 0), 2); switch (item.type) {
consommer.totalDesaltere = consommer.item.system.boisson case 'herbe': case 'faune':
? Misc.keepDecimals(doses * (consommer.item.system.desaltere ?? 0), 2) consommer.totalSust = doses;
: 0; consommer.totalDesaltere = 0;
} consommer.choix.sust = 1;
consommer.choix.quantite = 0;
consommer.choix.encombrement = Misc.keepDecimals(consommer.item.system.encombrement / item.system.sust, 2);
/* -------------------------------------------- */ return;
activateListeners(html) { case 'nourritureboisson':
super.activateListeners(html); consommer.choix.sust = consommer.item.system.sust;
html.find(".se-forcer").change(event => this.setSeForcer(event)); consommer.choix.quantite = doses;
html.find(".consommer-doses").change(event => this.selectDoses(event)); consommer.choix.encombrement = 0
consommer.totalSust = Misc.keepDecimals(doses * (consommer.item.system.sust ?? 0), 2);
consommer.totalDesaltere = consommer.item.system.boisson
? Misc.keepDecimals(doses * (consommer.item.system.desaltere ?? 0), 2)
: 0;
break;
case 'potion':
consommer.totalSust = 0
consommer.totalDesaltere = 0
}
} }
@@ -84,8 +105,8 @@ export class DialogConsommer extends Dialog {
selectDoses(event) { selectDoses(event) {
this.consommerData.choix.doses = Number(event.currentTarget.value); this.consommerData.choix.doses = Number(event.currentTarget.value);
DialogConsommer.calculDoses(this.consommerData); DialogConsommer.calculDoses(this.consommerData, this.item);
$(".total-sust").text(this.consommerData.totalSust); this.html.find(".total-sust").text(this.consommerData.totalSust);
$(".total-desaltere").text(this.consommerData.totalDesaltere); this.html.find(".total-desaltere").text(this.consommerData.totalDesaltere);
} }
} }

View File

@@ -1,5 +1,4 @@
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
export class DialogItemVente extends Dialog { export class DialogItemVente extends Dialog {
@@ -24,7 +23,7 @@ export class DialogItemVente extends Dialog {
} }
constructor(venteData, html, callback) { constructor(venteData, html, callback) {
let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 }; let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
let conf = { let conf = {
title: "Proposer", title: "Proposer",
@@ -38,26 +37,26 @@ export class DialogItemVente extends Dialog {
this.venteData = venteData; this.venteData = venteData;
} }
async onProposer(it) {
await $(".tailleLot").change();
await $(".quantiteNbLots").change();
await $(".quantiteIllimite").change();
await $(".prixLot").change();
this.callback(this.venteData);
}
/* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite) this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value))); this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value))); this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
} }
async onProposer(it) {
await this.html.find(".tailleLot").change();
await this.html.find(".quantiteNbLots").change();
await this.html.find(".quantiteIllimite").change();
await this.html.find(".prixLot").change();
this.callback(this.venteData);
}
/* -------------------------------------------- */
setPrixLot(prixLot) { setPrixLot(prixLot) {
this.venteData.prixLot = prixLot; this.venteData.prixLot = prixLot;
} }
@@ -66,15 +65,15 @@ export class DialogItemVente extends Dialog {
// recalculer le prix du lot // recalculer le prix du lot
if (tailleLot != this.venteData.tailleLot) { if (tailleLot != this.venteData.tailleLot) {
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2); this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
$(".prixLot").val(this.venteData.prixLot); this.html.find(".prixLot").val(this.venteData.prixLot);
} }
this.venteData.tailleLot = tailleLot; this.venteData.tailleLot = tailleLot;
if (this.venteData.isOwned) { if (this.venteData.isOwned) {
// recalculer le nombre de lots max // recalculer le nombre de lots max
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot); this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots); this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
$(".quantiteNbLots").val(this.venteData.quantiteNbLots); this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots) this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
} }
} }
@@ -83,12 +82,12 @@ export class DialogItemVente extends Dialog {
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)); nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
} }
this.venteData.quantiteNbLots = nbLots; this.venteData.quantiteNbLots = nbLots;
$(".quantiteNbLots").val(this.venteData.quantiteNbLots); this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
} }
setQuantiteIllimite(checked) { setQuantiteIllimite(checked) {
this.venteData.quantiteIllimite = checked; this.venteData.quantiteIllimite = checked;
$(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles"); this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite) HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
} }
} }

View File

@@ -3,13 +3,13 @@ import { Misc } from "./misc.js";
export class DialogRepos extends Dialog { export class DialogRepos extends Dialog {
static async create(actor) { static async create(actor) {
let actorData = actor const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actor);
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actorData); const dialog = new DialogRepos(html, actor);
new DialogRepos(html, actor).render(true); dialog.render(true);
} }
constructor(html, actor) { constructor(html, actor) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 400, 'z-index': 99999 }; let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 400, height: 'fit-content', 'z-index': 99999 };
let conf = { let conf = {
title: "Se reposer", title: "Se reposer",
content: html, content: html,
@@ -21,13 +21,18 @@ export class DialogRepos extends Dialog {
super(conf, options); super(conf, options);
this.actor = actor; this.actor = actor;
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
/* -------------------------------------------- */
async repos() { async repos() {
await $("[name='nb-heures']").change(); await this.html.find("[name='nb-heures']").change();
await $("[name='nb-jours']").change(); await this.html.find("[name='nb-jours']").change();
const selection = await $("[name='repos']:checked").val(); const selection = await this.html.find("[name='repos']:checked").val();
const nbHeures = Number.parseInt(await $("[name='nb-heures']").val()); const nbHeures = Number.parseInt(await this.html.find("[name='nb-heures']").val());
const nbJours = Number.parseInt(await $("[name='nb-jours']").val()); const nbJours = Number.parseInt(await this.html.find("[name='nb-jours']").val());
switch (selection) { switch (selection) {
case "sieste": { case "sieste": {
await this.actor.dormir(nbHeures); await this.actor.dormir(nbHeures);
@@ -35,7 +40,7 @@ export class DialogRepos extends Dialog {
} }
case "nuit": { case "nuit": {
let heuresDormies = await this.actor.dormir(nbHeures); let heuresDormies = await this.actor.dormir(nbHeures);
if (heuresDormies == nbHeures){ if (heuresDormies == nbHeures) {
await this.actor.dormirChateauDormant(); await this.actor.dormirChateauDormant();
} }
return; return;
@@ -49,8 +54,4 @@ export class DialogRepos extends Dialog {
} }
} }
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
}
} }

View File

@@ -0,0 +1,37 @@
export class DialogSelectTarget extends Dialog {
constructor(html, onSelectTarget, targets) {
const options = {
classes: ["rdd-dialog-select-target"],
width: 'fit-content',
height: 'fit-content',
'max-height': 600,
'z-index': 99999
};
const conf = {
title: "Choisir une cible",
content: html,
buttons: {}
};
super(conf, options);
this.onSelectTarget = onSelectTarget;
this.targets = targets;
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("li.select-target").click((event) => {
this.targetSelected(this.html.find(event.currentTarget)?.data("token-id"));
});
}
targetSelected(tokenId) {
const target = this.targets.find(it => it.id == tokenId);
this.close();
if (target) {
this.onSelectTarget(target);
}
}
}

View File

@@ -13,39 +13,33 @@ export class DialogSplitItem extends Dialog {
constructor(item, splitData, html, callback) { constructor(item, splitData, html, callback) {
let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 }; let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
let conf = { let conf = {
title: "Séparer en deux", title: "Séparer en deux",
content: html, content: html,
default: "separer", default: "separer",
buttons: { buttons: {
"separer": { "separer": { label: "Séparer", callback: it => this.onSplit() }
label: "Séparer", callback: it => {
this.onSplit();
}
}
} }
}; };
super(conf, options); super(conf, options);
this.callback = callback; this.callback = callback;
this.item = item; this.item = item;
this.splitData = splitData; this.splitData = splitData;
} }
async onSplit(){
await $(".choix-quantite").change();
this.callback(this.item, this.splitData.choix.quantite);
}
/* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
html.find(".choix-quantite").change(event => { this.html.find(".choix-quantite").change(event => {
this.splitData.choix.quantite = Number(event.currentTarget.value); this.splitData.choix.quantite = Number(event.currentTarget.value);
}); });
} }
/* -------------------------------------------- */
async onSplit() {
await this.html.find(".choix-quantite").change();
this.callback(this.item, this.splitData.choix.quantite);
}
} }

View File

@@ -1,4 +1,3 @@
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
export class DialogStress extends Dialog { export class DialogStress extends Dialog {
@@ -24,7 +23,7 @@ export class DialogStress extends Dialog {
constructor(dialogData, html) { constructor(dialogData, html) {
const options = { classes: ["DialogStress"], const options = { classes: ["DialogStress"],
width: 400, width: 400,
height: 205+dialogData.actors.length*25, height: 'fit-content',
'z-index': 99999 'z-index': 99999
}; };
const conf = { const conf = {
@@ -32,31 +31,30 @@ export class DialogStress extends Dialog {
content: html, content: html,
buttons: { buttons: {
stress: { label: "Stress !", callback: it => { this.onStress(); } } stress: { label: "Stress !", callback: it => { this.onStress(); } }
}, }
default: "stress"
}; };
super(conf, options); super(conf, options);
this.dialogData = dialogData; this.dialogData = dialogData;
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("input.select-actor").change((event) => this.onSelectActor(event));
}
async onStress() { async onStress() {
const motif = $("form.rdddialogstress input[name='motif']").val(); const motif = this.html.find("form.rdddialogstress input[name='motif']").val();
const stress = Number($("form.rdddialogstress input[name='stress']").val()); const stress = Number(this.html.find("form.rdddialogstress input[name='stress']").val());
const compteur = ($("form.rdddialogstress input[name='immediat']").prop("checked")) ? 'experience' : 'stress'; const compteur = (this.html.find("form.rdddialogstress input[name='immediat']").prop("checked")) ? 'experience' : 'stress';
this.dialogData.actors.filter(it => it.selected) this.dialogData.actors.filter(it => it.selected)
.map(it => game.actors.get(it.id)) .map(it => game.actors.get(it.id))
.forEach(actor => actor.distribuerStress(compteur, stress, motif)); .forEach(actor => actor.distribuerStress(compteur, stress, motif));
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find("input.select-actor").change((event) => this.onSelectActor(event));
}
async onSelectActor(event) { async onSelectActor(event) {
const actorId = $(event.currentTarget)?.data("actor-id"); const actorId = this.html.find(event.currentTarget)?.data("actor-id");
const actor = this.dialogData.actors.find(it => it.id == actorId); const actor = this.dialogData.actors.find(it => it.id == actorId);
if (actor) { if (actor) {
actor.selected = event.currentTarget.checked; actor.selected = event.currentTarget.checked;

View File

@@ -35,7 +35,7 @@ export class DialogValidationEncaissement extends Dialog {
} }
let dialogOptions = { let dialogOptions = {
classes: ["rdddialog"], classes: ["rdd-roll-dialog"],
width: 350, width: 350,
height: 290 height: 290
} }
@@ -55,11 +55,12 @@ export class DialogValidationEncaissement extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
html.find('input.encaissement-roll-result').keyup(async event => { this.html = html;
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.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
$('label.encaissement-total').text(this.encaissement.total); this.html.find('label.encaissement-total').text(this.encaissement.total);
$('label.encaissement-blessure').text(this.encaissement.blessures) this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
}); });
} }

137
module/effets-rencontres.js Normal file
View File

@@ -0,0 +1,137 @@
import { ChatUtility } from "./chat-utility.js";
import { Poetique } from "./poetique.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } from "./tmr-utility.js";
export class EffetsRencontre {
static messager = async (dialog, context) => {
dialog.setRencontreState('messager', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
}
static passeur = async (dialog, context) => {
dialog.setRencontreState('passeur', TMRUtility.getTMRPortee(context.tmr.coord, context.rencontre.system.force));
}
static teleportation_typecase = async (dialog, context) => {
dialog.setRencontreState('changeur', TMRUtility.getCasesType(context.tmr.type));
}
static rencontre_persistante = async (dialog, context) => {
dialog.setRencontreState('persistant', []);
}
static reve_plus_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, context.rencontre.system.force) }
static reve_plus_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, 1) }
static reve_moins_force = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -context.rencontre.system.force) }
static reve_moins_1 = async (dialog, context) => { await EffetsRencontre.$reve_plus(context.actor, -1) }
static $reve_plus = async (actor, valeur) => { await actor.reveActuelIncDec(valeur) }
static vie_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static vie_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
static $vie_plus = async (actor, valeur) => { await actor.santeIncDec("vie", valeur) }
static moral_plus_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, 1) }
static moral_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static $moral_plus = async (actor, valeur) => { await actor.moralIncDec(valeur) }
static end_moins_1 = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -1) }
static end_moins_force = async (dialog, context) => { await EffetsRencontre.$vie_plus(context.actor, -context.rencontre.system.force) }
static $end_plus = async (actor, valeur) => { await actor.santeIncDec("endurance", valeur) }
static fatigue_plus_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, 1) }
static fatigue_plus_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, context.rencontre.system.force) }
static fatigue_moins_1 = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -1) }
static fatigue_moins_force = async (dialog, context) => { await EffetsRencontre.$fatigue_plus(context.actor, -context.rencontre.system.force) }
static $fatigue_plus = async (actor, valeur) => { await actor.santeIncDec("fatigue", valeur) }
static perte_chance = async (dialog, context) => {
const perte = context.rolled.isETotal ? context.rencontre.system.force : 1;
await context.actor.chanceActuelleIncDec("fatigue", -perte);
}
static xp_sort_force = async (dialog, context) => {
let competence = context.competence;
if (competence) {
const xpSort = Misc.toInt(competence.system.xp_sort) + context.rencontre.system.force;
await this.updateEmbeddedDocuments("Item", [{ _id: compData._id, 'system.xp_sort': xpSort }]);
await this.updateExperienceLog("XP Sort", xpSort, `Rencontre d'un ${context.rencontre.name} en TMR`);
}
}
static stress_plus_1 = async (dialog, context) => {
await context.actor.addCompteurValue('stress', 1, `Rencontre d'un ${context.rencontre.name} en TMR`);
}
static reinsertion = async (dialog, context) => {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true)
}
static teleportation_aleatoire_typecase = async (dialog, context) => {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => it.type == context.tmr.type && it.coord != context.tmr.coord)
}
static demireve_rompu = async (dialog, context) => {
dialog.close()
}
static sort_aleatoire = async (dialog, context) => {
context.sortReserve = await RdDDice.rollOneOf(context.actor.itemTypes['sortreserve']);
if (context.sortReserve) {
context.newTMR = TMRUtility.getTMR(context.sortReserve.system.coord);
await dialog.positionnerDemiReve(context.newTMR.coord);
await dialog.processSortReserve(context.sortReserve);
dialog.close();
}
else {
await EffetsRencontre.$reinsertion(dialog, context.actor, it => true);
}
}
static deplacement_aleatoire = async (dialog, context) => {
const oldCoord = context.actor.system.reve.tmrpos.coord;
const newTmr = await TMRUtility.deplaceTMRAleatoire(context.actor, oldCoord);
await dialog.positionnerDemiReve(newTmr.coord)
}
static rdd_part_tete = async (dialog, context) => {
mergeObject(context, {
tete: context.rolled.isPart,
poesie: await Poetique.getExtrait()
})
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
});
}
static rdd_echec_queue = async (dialog, context) => {
mergeObject(context, {
queues: [await context.actor.ajouterQueue()],
poesie: await Poetique.getExtrait()
})
if (context.rolled.isETotal) {
context.queues.push(await context.actor.ajouterQueue());
}
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
});
}
static experience_particuliere = async (dialog, context) => {
await context.actor.appliquerAjoutExperience(context)
}
static regain_seuil = async (dialog, context) => {
await context.actor.regainPointDeSeuil()
}
static async $reinsertion(dialog, actor, filter) {
const newTMR = await TMRUtility.getTMRAleatoire(filter);
await actor.forcerPositionTMRInconnue(newTMR);
await dialog.positionnerDemiReve(newTMR.coord);
}
}

223
module/environnement.js Normal file
View File

@@ -0,0 +1,223 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js";
const RARETES = [
{ name: 'Commune', frequence: 54, min: 27, max: 108 },
{ name: 'Frequente', frequence: 18, min: 9, max: 36 },
{ name: 'Rare', frequence: 6, min: 3, max: 12 },
{ name: 'Rarissime', frequence: 2, min: 1, max: 4 }]
const DEFAULT_RARETE = 1;
const SETTINGS_LISTE_MILIEUX = "liste-milieux";
const MILIEUX = [
"Collines",
"Cours d'eau",
"Déserts",
"Forêts",
"Marais",
"Maritimes",
"Montagnes",
"Plaines",
"Sous-sols"
]
const ITEM_ENVIRONNEMENT_TYPES = [
'herbe', 'ingredient', 'faune'
]
export class Environnement {
static init() {
game.settings.register(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX, {
name: "Liste des milieux proposés",
hint: "Liste des milieux proposés pour la faune&flore, séparés par des virgules",
scope: "world",
config: true,
default: MILIEUX.reduce(Misc.joining(',')),
type: String
});
game.system.rdd.environnement = new Environnement();
}
constructor() {
this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
}
static getRarete(name = undefined) {
return RARETES.find(it => it.name == name) ?? RARETES[DEFAULT_RARETE];
}
static getFrequenceRarete(rarete, field = undefined) {
const selected = this.getRarete(rarete);
return selected[field];
}
async milieux() {
return Object.values(await this.mapMilieux());
}
async mapMilieux() {
const compendiumItems = await this.getElements(it => 1, it => ITEM_ENVIRONNEMENT_TYPES.includes(it.type));
return Misc.indexLowercase(this.getMilieuxSettings().concat(Environnement.listMilieux(compendiumItems)));
}
static listMilieux(items) {
return Misc.concat(items.map(it => Environnement.$itemToMilieux(it).filter(m => m)));
}
async autresMilieux(item) {
const mapMilieux = await this.mapMilieux();
const milieuxExistants = Environnement.$itemToMilieux(item).map(it => Grammar.toLowerCaseNoAccent(it));
return Object.keys(mapMilieux)
.filter(it => !milieuxExistants.includes(it))
.map(it => mapMilieux[it]);
}
static $itemToMilieux(item) {
return item.system.environnement.map(env => env.milieu);
}
getMilieuxSettings() {
return game.settings.get(SYSTEM_RDD, SETTINGS_LISTE_MILIEUX).split(',').map(it => it.trim()).filter(it => it != '');
}
async findEnvironnementsLike(search) {
const milieux = await this.mapMilieux();
const searchLower = Grammar.toLowerCaseNoAccent(search);
const keys = Object.keys(milieux).filter(it => it.includes(searchLower));
if (keys.length > 1) {
const milieuExact = milieux[searchLower];
if (milieuExact) {
return [milieuExact];
}
}
return keys.map(k => milieux[k]);
}
async searchToChatMessage(milieux, typeName) {
const table = await this.buildEnvironnementTable(milieux);
await CompendiumTableHelpers.tableToChatMessage(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, typeName);
return true
}
async getRandom(milieux, typeName) {
const table = await this.buildEnvironnementTable(milieux);
return await CompendiumTableHelpers.getRandom(table, 'Item', ITEM_ENVIRONNEMENT_TYPES, undefined, typeName);
}
async buildEnvironnementTable(milieux) {
const filterMilieux = item => item.system?.environnement.filter(env => milieux.includes(env.milieu));
const itemRareteEnMilieu = item => {
const raretes = filterMilieux(item);
const frequenceMax = Math.max(raretes.map(env => env.frequence));
return raretes.find(env => env.frequence == frequenceMax);
}
const itemFrequenceEnMilieu = item => itemRareteEnMilieu(item)?.frequence ?? 0;
const isPresentEnMilieu = item => itemFrequenceEnMilieu(item) > 0;
return await this.table.buildTable(itemFrequenceEnMilieu, isPresentEnMilieu);
}
async getElements(itemFrequence, filter) {
return await this.table.getContent(itemFrequence, filter);
}
}
export class EnvironmentSheetHelper {
static defaultOptions(defaultOptions) {
return mergeObject(defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
});
}
static setPosition(sheet, superPosition) {
const position = superPosition;
const sheetHeader = sheet.element.find(".sheet-header");
const sheetBody = sheet.element.find(".sheet-body");
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
return position;
}
/* -------------------------------------------- */
static async getData(sheet, formData) {
return mergeObject(formData, {
milieux: await game.system.rdd.environnement.autresMilieux(sheet.item)
});
}
static activateListeners(sheet) {
if (!sheet.options.editable) return;
sheet.html.find("input.input-selection-milieu").keypress(event => {
if (event.keyCode == '13') {
EnvironmentSheetHelper.onAddMilieu(sheet, event);
}
event.stopPropagation();
})
sheet.html.find("a.milieu-add").click(event => EnvironmentSheetHelper.onAddMilieu(sheet, event));
sheet.html.find("div.environnement-milieu a.milieu-delete").click(event => EnvironmentSheetHelper.onDeleteMilieu(sheet, event));
sheet.html.find("div.environnement-milieu select.environnement-rarete").change(event => EnvironmentSheetHelper.onChange(sheet, event,
updated => EnvironmentSheetHelper.$changeRarete(sheet, event, updated)));
sheet.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => EnvironmentSheetHelper.onChange(sheet, event,
updated => EnvironmentSheetHelper.$changeFrequence(sheet, event, updated)));
}
static $changeFrequence(sheet, event, updated) {
updated.frequence = Number(sheet.html.find(event.currentTarget).val());
}
static $changeRarete(sheet, event, updated) {
const name = sheet.html.find(event.currentTarget).val();
const rarete = Environnement.getRarete(name);
updated.rarete = rarete.name;
updated.frequence = rarete.frequence;
// updated.frequence = Math.min(
// Math.max(rarete.min, updated.frequence ?? rarete.frequence),
// rarete.max);
}
static async onAddMilieu(sheet, event) {
const milieu = sheet.html.find('input.input-selection-milieu').val();
if (!milieu) {
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${sheet.item.name}`);
return
}
const list = sheet.item.system.environnement;
const exists = list.find(it => it.milieu == milieu);
if (exists) {
ui.notifications.warn(`${sheet.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
return
}
const rarete = Environnement.getRarete();
const newList = [...list, { milieu, rarete: rarete.name, frequence: rarete.frequence }].sort(Misc.ascending(it => it.milieu))
await sheet.item.update({ 'system.environnement': newList })
}
static async onDeleteMilieu(sheet, event) {
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
if (milieu != undefined) {
const newList = sheet.item.system.environnement.filter(it => it.milieu != milieu)
.sort(Misc.ascending(it => it.milieu));
await sheet.item.update({ 'system.environnement': newList });
}
}
static async onChange(sheet, event, doMutation) {
const list = sheet.item.system.environnement;
const milieu = EnvironmentSheetHelper.$getEventMilieu(sheet, event);
const updated = list.find(it => it.milieu == milieu);
if (updated) {
doMutation(updated);
const newList = [...list.filter(it => it.milieu != milieu), updated]
.sort(Misc.ascending(it => it.milieu));
await sheet.item.update({ 'system.environnement': newList });
}
}
static $getEventMilieu(sheet, event) {
return sheet.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
}
}

View File

@@ -19,10 +19,14 @@ export class Grammar {
return word.match(/^[aeiouy]/i) return word.match(/^[aeiouy]/i)
} }
static equalsInsensitive(a, b) {
return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b)
}
static includesLowerCaseNoAccent(value, content) { static includesLowerCaseNoAccent(value, content) {
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content)); return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static toLowerCaseNoAccent(words) { static toLowerCaseNoAccent(words) {
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words; return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;

View File

@@ -1,10 +1,10 @@
export class HtmlUtility{ export class HtmlUtility{
static _showControlWhen(control, condition) { static _showControlWhen(jQuerySelector, condition) {
if (condition) { if (condition) {
control.show(); jQuerySelector.show();
} }
else { else {
control.hide(); jQuerySelector.hide();
} }
} }
} }

View File

@@ -28,7 +28,7 @@ export class RdDItemArme extends Item {
switch (arme ? arme.type : '') { switch (arme ? arme.type : '') {
case 'arme': return arme; case 'arme': return arme;
case 'competencecreature': case 'competencecreature':
return RdDItemCompetenceCreature.toActionArme(arme); return RdDItemCompetenceCreature.armeNaturelle(arme);
} }
return RdDItemArme.mainsNues(); return RdDItemArme.mainsNues();
} }
@@ -177,7 +177,7 @@ export class RdDItemArme extends Item {
equipe: true, equipe: true,
rapide: true, rapide: true,
force: 0, force: 0,
dommages: 0, dommages: "0",
dommagesReels: 0, dommagesReels: 0,
mortalite: 'non-mortel', mortalite: 'non-mortel',
competence: 'Corps à corps', competence: 'Corps à corps',

View File

@@ -8,18 +8,18 @@ const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20,
const niveau_max = xp_par_niveau.length - 10; const niveau_max = xp_par_niveau.length - 10;
/* -------------------------------------------- */ /* -------------------------------------------- */
const limitesArchetypes = [ const limitesArchetypes = [
{ "niveau": 0, "nombreMax": 100, "nombre": 0 }, { "niveau": 0, "nombreMax": 100, "reste": 100 },
{ "niveau": 1, "nombreMax": 10, "nombre": 0 }, { "niveau": 1, "nombreMax": 10, "reste": 10 },
{ "niveau": 2, "nombreMax": 9, "nombre": 0 }, { "niveau": 2, "nombreMax": 9, "reste": 9 },
{ "niveau": 3, "nombreMax": 8, "nombre": 0 }, { "niveau": 3, "nombreMax": 8, "reste": 8 },
{ "niveau": 4, "nombreMax": 7, "nombre": 0 }, { "niveau": 4, "nombreMax": 7, "reste": 7 },
{ "niveau": 5, "nombreMax": 6, "nombre": 0 }, { "niveau": 5, "nombreMax": 6, "reste": 6 },
{ "niveau": 6, "nombreMax": 5, "nombre": 0 }, { "niveau": 6, "nombreMax": 5, "reste": 5 },
{ "niveau": 7, "nombreMax": 4, "nombre": 0 }, { "niveau": 7, "nombreMax": 4, "reste": 4 },
{ "niveau": 8, "nombreMax": 3, "nombre": 0 }, { "niveau": 8, "nombreMax": 3, "reste": 3 },
{ "niveau": 9, "nombreMax": 2, "nombre": 0 }, { "niveau": 9, "nombreMax": 2, "reste": 2 },
{ "niveau": 10, "nombreMax": 1, "nombre": 0 }, { "niveau": 10, "nombreMax": 1, "reste": 1 },
{ "niveau": 11, "nombreMax": 1, "nombre": 0 } { "niveau": 11, "nombreMax": 1, "reste": 1 }
]; ];
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -34,13 +34,6 @@ const categorieCompetences = {
"lancer": { base: -8, label: "Lancer" } "lancer": { base: -8, label: "Lancer" }
} }
const compendiumCompetences = {
"personnage": "foundryvtt-reve-de-dragon.competences",
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
"entite": "foundryvtt-reve-de-dragon.competences-entites"
};
function _buildCumulXP() { function _buildCumulXP() {
let cumulXP = { "-11": 0 }; let cumulXP = { "-11": 0 };
let cumul = 0; let cumul = 0;
@@ -55,12 +48,6 @@ function _buildCumulXP() {
const competence_xp_cumul = _buildCumulXP(); const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item { export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static actorCompendium(actorType = undefined) {
return compendiumCompetences[actorType ?? 'personnage'];
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static getCategorieCompetences() { static getCategorieCompetences() {
return categorieCompetences; return categorieCompetences;
@@ -280,18 +267,47 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeResumeArchetype(competences) { static computeResumeArchetype(competences) {
const archetype = RdDItemCompetence.getLimitesArchetypes(); const computed = duplicate(limitesArchetypes);
competences.map(it => Math.max(0, it.system.niveau_archetype)) competences.map(it => Math.max(0, it.system.niveau_archetype))
.forEach(niveau => { .filter(n => n > 0)
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 }; .forEach(n => {
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1; computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 };
computed[n].reste = computed[n].reste - 1;
}); });
return archetype; return computed.filter(it => it.reste > 0 && it.niveau > 0);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getLimitesArchetypes() { static triVisible(competences) {
return duplicate(limitesArchetypes); return competences.filter(it => it.system.isVisible)
.sort((a, b) => RdDItemCompetence.compare(a, b))
}
static $positionTri(comp) {
if (comp.name.startsWith("Survie")) {
if (comp.name.includes("Cité")) return 0;
if (comp.name.includes("Extérieur")) return 1;
return 2;
}
if (comp.system.categorie.startsWith("melee")) {
if (comp.name.includes("Corps")) return 0;
if (comp.name.includes("Dague")) return 1;
if (comp.name.includes("Esquive")) return 2;
return 3;
}
if (comp.system.categorie.startsWith("draconic")) {
if (comp.name.includes("Oniros")) return 0;
if (comp.name.includes("Hypnos")) return 1;
if (comp.name.includes("Narcos")) return 2;
if (comp.name.includes("Thanatos")) return 3;
return 4;
}
return 0;
}
static compare(a, b) {
const diff = RdDItemCompetence.$positionTri(a) - RdDItemCompetence.$positionTri(b);
return diff ? diff : a.name.localeCompare(b.name);
} }
} }

View File

@@ -1,4 +1,4 @@
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js"; import { RdDCombatManager } from "./rdd-combat.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -12,12 +12,12 @@ export class RdDItemCompetenceCreature extends Item {
rollData.competence.system.categorie = "creature" rollData.competence.system.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.system.iscombat) { if (rollData.competence.system.iscombat) {
rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence); rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static toActionArme(competencecreature) { static armeNaturelle(competencecreature) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) { if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence // si c'est un Item compétence: cloner pour ne pas modifier lma compétence
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature; let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;

View File

@@ -0,0 +1,60 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDConteneurItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "conteneur" };
async getData() {
const formData = await super.getData();
if (this.actor) {
this.prepareConteneurData(formData);
}
return formData;
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
}
/* -------------------------------------------- */
prepareConteneurData(formData) {
RdDUtility.filterEquipementParType(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
}
async _onDragStart(event) {
console.log("_onDragStart", event);
if (event.target.classList.contains("entity-link")) return;
const itemId = event.srcElement?.attributes["data-item-id"].value;
const item = this.actor.items.get(itemId);
// Create drag data
const dragData = {
actorId: this.actor.id,
type: "Item",
data: item.system
};
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
}
async _onDropItem(event, dragData) {
if (this.actor) {
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur);
await this.actor.processDropItem(dropParams);
await this.render(true);
}
}
}

View File

@@ -0,0 +1,67 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
import { RdDUtility } from "./rdd-utility.js";
export class RdDFauneItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "faune" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
EnvironmentSheetHelper.activateListeners(this);
html.find("a.linked-actor-delete").click(event => this.onDeleteLinkedActor());
html.find("a.preparer-nourriture").click(event => this.preparerNourriture(event));
html.find("a.manger-nourriture").click(event => this.mangerNourriture(event));
}
async _onDropActor(event, dragData) {
console.log('faune:dropActor', event, dragData)
const linkedActor = fromUuidSync(dragData.uuid);
if (linkedActor?.pack) {
this.item.update({
'system.actor.pack': linkedActor.pack,
'system.actor.id': linkedActor._id,
'system.actor.name': linkedActor.name
});
}
else {
ui.notifications.warn(`${linkedActor.name} ne provient pas d'un compendium.
<br>Choisissez une créature du compendium pour représenter un élément de faune générique`)
}
}
async onDeleteLinkedActor() {
this.item.update({
'system.actor.pack': '',
'system.actor.id': '',
'system.actor.name': ''
});
}
async preparerNourriture(event) {
if (this.actor) {
await this.actor.preparerNourriture(this.item);
}
}
async mangerNourriture(event) {
if (this.actor) {
await this.actor.mangerNourriture(this.item);
}
}
}

View File

@@ -0,0 +1,25 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDHerbeItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "herbe" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
EnvironmentSheetHelper.activateListeners(this);
}
}

View File

@@ -0,0 +1,25 @@
import { EnvironmentSheetHelper } from "./environnement.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDIngredientItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "ingredient" };
static get defaultOptions() {
return EnvironmentSheetHelper.defaultOptions(super.defaultOptions);
}
setPosition(options = {}) {
return EnvironmentSheetHelper.setPosition(this, super.setPosition(options));
}
async getData() {
const formData = await super.getData();
return await EnvironmentSheetHelper.getData(this, formData);
}
activateListeners(html) {
super.activateListeners(html);
EnvironmentSheetHelper.activateListeners(this);
}
}

View File

@@ -4,22 +4,22 @@ import { LOG_HEAD } from "./constants.js";
const MONNAIE_ETAIN = { const MONNAIE_ETAIN = {
name: "Etain (1 denier)", type: 'monnaie', name: "Etain (1 denier)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
system: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" } system: { quantite: 0, cout: 0.01, encombrement: 0.001, description: "" }
}; };
const MONNAIE_BRONZE = { const MONNAIE_BRONZE = {
name: "Bronze (10 deniers)", type: 'monnaie', name: "Bronze (10 deniers)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
system: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" } system: { quantite: 0, cout: 0.10, encombrement: 0.002, description: "" }
}; };
const MONNAIE_ARGENT = { const MONNAIE_ARGENT = {
name: "Argent (1 sol)", type: 'monnaie', name: "Argent (1 sol)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
system: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" } system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" }
}; };
const MONNAIE_OR = { const MONNAIE_OR = {
name: "Or (10 sols)", type: 'monnaie', name: "Or (10 sols)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp", img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
system: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" } system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" }
}; };
const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR]; const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR];
@@ -32,7 +32,7 @@ export class Monnaie {
static monnaiesManquantes(actor) { static monnaiesManquantes(actor) {
const disponibles = actor.itemTypes['monnaie']; const disponibles = actor.itemTypes['monnaie'];
const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.valeur_deniers))); const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.cout)));
if (manquantes.length > 0) { if (manquantes.length > 0) {
console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD); console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD);
} }
@@ -40,15 +40,15 @@ export class Monnaie {
} }
static deValeur(monnaie, valeur) { static deValeur(monnaie, valeur) {
return valeur == monnaie.system.valeur_deniers return Monnaie.valEntiere(valeur) == Monnaie.valEntiere(monnaie.system.cout)
} }
static arrondiDeniers(sols) { static valEntiere(sols) {
return Number(sols).toFixed(2); return Math.max(Math.floor((sols??0)*100), 0);
} }
static triValeurDenier() { static triValeurEntiere() {
return Misc.ascending(item => item.system.valeur_deniers) return Misc.ascending(item => Monnaie.valEntiere(item.system.cout))
} }
static async creerMonnaiesStandard(actor) { static async creerMonnaiesStandard(actor) {
@@ -65,28 +65,28 @@ export class Monnaie {
return deniers; return deniers;
} }
static async optimiser(actor, fortune) { static async optimiserFortune(actor, fortune) {
let reste = fortune; let resteEnDeniers = Math.round(fortune*100);
let monnaies = actor.itemTypes['monnaie']; let monnaies = actor.itemTypes['monnaie'];
let updates = []; let updates = [];
let parValeur = Misc.classifyFirst(monnaies, it => it.system.valeur_deniers); let parValeur = Misc.classifyFirst(monnaies, it => Monnaie.valEntiere(it.system.cout));
for (let valeur of [1000, 100, 10, 1]) { for (let valeurDeniers of [1000, 100, 10, 1]) {
const itemPiece = parValeur[valeur]; const itemPiece = parValeur[valeurDeniers];
const piecesDeCetteValeur = Math.floor(reste / valeur);
if (itemPiece) { if (itemPiece) {
if (piecesDeCetteValeur != itemPiece.system.quantite) { const quantite = Math.floor(resteEnDeniers / valeurDeniers);
updates.push({ _id: parValeur[valeur].id, 'system.quantite': piecesDeCetteValeur }); if (quantite != itemPiece.system.quantite) {
updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite });
} }
reste -= piecesDeCetteValeur*valeur; resteEnDeniers -= quantite*valeurDeniers;
} }
} }
console.log('Monnaie.optimiser', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', reste); console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers);
if (updates.length > 0) { if (updates.length > 0) {
await actor.updateEmbeddedDocuments('Item', updates); await actor.updateEmbeddedDocuments('Item', updates);
} }
if (reste>0){ if (resteEnDeniers > 0){
// créer le reste en deniers fortune en deniers // créer le reste en deniers fortune en deniers
await Monnaie.creerMonnaiesDeniers(actor, reste); await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers);
} }
} }

View File

@@ -0,0 +1,85 @@
import { RdDRencontre } from "./item-rencontre.js";
import { RdDItemSheet } from "./item-sheet.js";
export class RdDRencontreItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "rencontre" };
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
return position;
}
/* -------------------------------------------- */
async getData() {
const formData = duplicate(this.item);
mergeObject(formData, {
title: formData.name,
isGM: game.user.isGM,
owner: this.actor?.isOwner,
isOwned: this.actor ? true : false,
actorId: this.actor?.id,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
effets: {
succes: {
liste: RdDRencontre.getEffetsSucces(),
select: RdDRencontre.mapEffets(this.item.system.succes.effets)
},
echec: {
liste: RdDRencontre.getEffetsEchec(),
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
}
}
});
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find("a.effet-add").click(event => this.onAddEffet(event));
this.html.find("a.effet-delete").click(event => this.onDeleteEffet(event));
}
async onAddEffet(event) {
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
const keyEffets = `system.${resultat}.effets`;
const code = this.html.find(event.currentTarget)?.data("effet-code");
const liste = RdDRencontre.getListeEffets(this.item, resultat);
liste.push(code);
await this._updateEffetsRencontre(keyEffets, liste);
}
async onDeleteEffet(event) {
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
const keyEffets = `system.${resultat}.effets`;
const pos = this.html.find(event.currentTarget)?.data("effet-pos");
const liste = RdDRencontre.getListeEffets(this.item, resultat);
liste.splice(pos, 1);
await this._updateEffetsRencontre(keyEffets, liste);
}
async _updateEffetsRencontre(key, liste) {
const updates = {};
updates[key] = liste;
this.item.update(updates);
}
}

71
module/item-rencontre.js Normal file
View File

@@ -0,0 +1,71 @@
import { EffetsRencontre } from "./effets-rencontres.js";
const tableEffets = [
{ code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager },
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
{ code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve", method: EffetsRencontre.reve_moins_force },
{ code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie", method: EffetsRencontre.vie_moins_1 },
{ code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire", method: EffetsRencontre.reinsertion },
{ code: "persistant", resultat: "echec", description: "Bloque le demi-rêve", method: EffetsRencontre.rencontre_persistante },
{ code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type)", method: EffetsRencontre.teleportation_aleatoire_typecase },
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },
{ code: "moral+1", resultat: "succes", description: "Gain de 1 point de moral", method: EffetsRencontre.moral_plus_1 },
{ code: "moral-1", resultat: "echec", description: "Perte de 1 point de moral", method: EffetsRencontre.moral_moins_1 },
{ code: "xpsort+f", resultat: "succes", description: "Gain de (force) xp sort", method: EffetsRencontre.xp_sort_force },
{ code: "endurance-1", resultat: "echec", description: "Perte de 1 point d'endurance", method: EffetsRencontre.end_moins_1 },
{ code: "endurance-f", resultat: "echec", description: "Perte de (force) points d'endurance", method: EffetsRencontre.end_moins_force },
{ code: "fatigue+1", resultat: "echec", description: "Coup de fatigue de 1 point", method: EffetsRencontre.fatigue_plus_1},
{ code: "fatigue+f", resultat: "echec", description: "Coup de fatigue de 1 (force) points", method: EffetsRencontre.fatigue_plus_force },
{ code: "fatigue-1", resultat: "succes", description: "Récupération de 1 point de fatigue", method: EffetsRencontre.fatigue_moins_1},
{ code: "fatigue-f", resultat: "succes", description: "Récupération de 1 (force) points de fatigue", method: EffetsRencontre.fatigue_moins_force },
{ code: "perte-chance", resultat: "echec", description: "Perte de chance actuelle", method: EffetsRencontre.perte_chance },
{ code: "stress+1", resultat: "succes", description: "Gain de 1 point de stress", method: EffetsRencontre.stress_plus_1 },
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
];
export class RdDRencontre {
static getEffetsSucces() { return RdDRencontre.getEffets("succes"); }
static getEffetsEchec() { return RdDRencontre.getEffets("echec"); }
static getEffets(resultat) {
return tableEffets.filter(e => resultat == e.resultat);
}
static mapEffets(liste) {
return liste.map(it => RdDRencontre.getEffet(it));
}
static getListeEffets(item, reussite) {
if (reussite == 'echec') {
return [...item.system.echec.effets];
}
if (reussite == 'succes') {
return [...item.system.succes.effets];
}
return [];
}
static getEffet(code) {
return tableEffets.find(it => code == it.code)
}
static async appliquer(codes, tmrDialog, rencData) {
for(const effet of RdDRencontre.mapEffets(codes)){
await effet.method(tmrDialog, rencData);
}
}
}

View File

@@ -4,35 +4,59 @@ import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
import { RdDGemme } from "./rdd-gemme.js"; import { RdDGemme } from "./rdd-gemme.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { SYSTEM_RDD } from "./constants.js"; import { SYSTEM_RDD } from "./constants.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js"; import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
/** /**
* Extend the basic ItemSheet with some very simple modifications * Extend the basic ItemSheet for RdD specific items
* @extends {ItemSheet}
*/ */
export class RdDItemSheet extends ItemSheet { export class RdDItemSheet extends ItemSheet {
static get ITEM_TYPE() {
return undefined
}
static defaultTemplate(type) {
return type ?
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
}
static register(sheetClass) {
Items.registerSheet(SYSTEM_RDD, sheetClass, {
label: Misc.typeName('Item', sheetClass.ITEM_TYPE),
types: [sheetClass.ITEM_TYPE],
makeDefault: true
})
}
/** @override */ /** @override */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
classes: [SYSTEM_RDD, "sheet", "item"], classes: [SYSTEM_RDD, "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html", template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
width: 550, width: 550,
height: 550 height: 550
}); });
} }
/* -------------------------------------------- */
get template() {
return RdDItemSheet.defaultTemplate(this.item.type);
}
get title() {
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
_getHeaderButtons() { _getHeaderButtons() {
let buttons = super._getHeaderButtons(); let buttons = super._getHeaderButtons();
// Add "Post to chat" button if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) {
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
if ("cout" in this.item.system && this.item.isVideOuNonConteneur()) {
buttons.unshift({ buttons.unshift({
class: "vendre", class: "vendre",
icon: "fas fa-comments-dollar", icon: "fas fa-comments-dollar",
@@ -67,43 +91,44 @@ export class RdDItemSheet extends ItemSheet {
img: this.item.img, img: this.item.img,
name: this.item.name, name: this.item.name,
system: this.item.system, system: this.item.system,
// TODO: v10 remove
data: this.item.system,
isGM: game.user.isGM, isGM: game.user.isGM,
actorId: this.actor?.id, actorId: this.actor?.id,
isOwned: this.actor ? true : false,
owner: this.item.isOwner, owner: this.item.isOwner,
editable: this.isEditable, editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked", cssClass: this.isEditable ? "editable" : "locked",
isSoins: false, isSoins: false,
description: await TextEditor.enrichHTML(this.object.system.description, {async: true}), description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
descriptionmj: await TextEditor.enrichHTML(this.object.system.descriptionmj, {async: true}) descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
isComestible: this.item.isComestible()
}
if (this.actor) {
formData.isOwned = true;
if (this.item.type == 'conteneur') {
this.prepareConteneurData(formData);
}
} }
const competences = await SystemCompendiums.getCompetences(this.actor?.type);
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences() formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
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 = duplicate(game.system.model.Actor.personnage.carac) formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve) formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
formData.competences = await RdDUtility.loadItems(it => it.isCompetencePersonnage(), RdDItemCompetence.actorCompendium(this.actor?.type)) formData.competences = competences;
} }
if (this.item.type == 'arme') { if (this.item.type == 'arme') {
formData.competences = await RdDUtility.loadItems(it => RdDItemCompetence.isCompetenceArme(it), RdDItemCompetence.actorCompendium(this.actor?.type)) formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it));
}
if (['sort', 'sortreserve'].includes(this.item.type)) {
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
} }
if (this.item.type == 'recettecuisine') { if (this.item.type == 'recettecuisine') {
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, {async: true}) formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
}
if (this.item.type == 'extraitpoetique') {
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
} }
if (this.item.type == 'recettealchimique') { if (this.item.type == 'recettealchimique') {
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id); RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, {async: true}) formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, {async: true}) formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, {async: true}) formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, {async: true}) formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
} }
if (this.item.type == 'gemme') { if (this.item.type == 'gemme') {
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList(); formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
@@ -128,106 +153,66 @@ export class RdDItemSheet extends ItemSheet {
return formData; return formData;
} }
/* -------------------------------------------- */
prepareConteneurData(formData) {
RdDUtility.filterEquipementParType(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
if (this.item.type == 'conteneur') {
this.form.ondragstart = (event) => this._onDragStart(event);
this.form.ondrop = (event) => this._onDrop(event);
}
let itemSheetDialog = this; let itemSheetDialog = this;
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned); HtmlUtility._showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned);
HtmlUtility._showControlWhen($(".item-magique"), this.item.isMagique()); HtmlUtility._showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
// Everything below here is only needed if the sheet is editable // Everything below here is only needed if the sheet is editable
if (!this.options.editable) return; if (!this.options.editable) return;
// Select competence categorie this.form.ondragstart = (event) => this._onDragStart(event);
html.find(".categorie").change(event => this._onSelectCategorie(event)); this.form.ondrop = (event) => this._onDrop(event);
html.find('.sheet-competence-xp').change((event) => { // Select competence categorie
this.html.find(".categorie").change(event => this._onSelectCategorie(event));
this.html.find('.sheet-competence-xp').change((event) => {
if (this.item.isCompetencePersonnage()) { if (this.item.isCompetencePersonnage()) {
RdDUtility.checkThanatosXP(this.item.name); RdDUtility.checkThanatosXP(this.item.name);
} }
}); });
html.find('.enchanteDate').change((event) => { this.html.find('.enchanteDate').change((event) => {
let jour = Number($('#jourMois').val()); let jour = Number(this.html.find('[name="splitDate.day"]').val());
let mois = $('#nomMois').val(); let mois = this.html.find('[name="splitDate.month"]').val();
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois); this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
}); });
html.find('.creer-tache-livre').click((event) => { this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
let actorId = event.currentTarget.attributes['data-actor-id'].value; this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item));
let actor = game.actors.get(actorId); this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
actor.creerTacheDepuisLivre(this.item);
});
html.find('.consommer-potion').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.consommerPotion(this.item);
});
html.find('.creer-potion-base').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.dialogFabriquerPotion(this.item);
});
html.find('.alchimie-tache a').click((event) => { this.html.find('.alchimie-tache a').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value; let actor = this._getEventActor(event);
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
let actor = game.actors.get(actorId);
if (actor) { if (actor) {
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData); actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else { } else {
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique."); ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
} }
}); });
html.find('.item-split').click(async event => { this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => itemSheetDialog.render(true)));
const item = RdDSheetUtility.getItem(event, this.actor); this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
await RdDSheetUtility.splitItem(item, this.actor, async () => itemSheetDialog.render(true)); this.html.find('.item-delete').click(async event => RdDUtility.confirmerSuppressionItem(this, RdDSheetUtility.getItem(event, this.actor)));
}); this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
html.find('.item-edit').click(async event => { this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItem());
const item = RdDSheetUtility.getItem(event, this.actor); this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => itemSheetDialog.render(true)));
item.sheet.render(true); }
});
html.find('.item-delete').click(async event => { _getEventActor(event) {
const li = RdDSheetUtility.getEventElement(event); let actorId = event.currentTarget.attributes['data-actor-id'].value;
const item = this.actor.getObjet(li.data("item-id")); let actor = game.actors.get(actorId);
RdDUtility.confirmerSuppressionItem(this, item, li); return actor;
});
html.find('.item-vendre').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.proposerVente();
});
html.find('.item-montrer').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.postItem();
});
html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
this.actor.actionItem(item, async () => itemSheetDialog.render(true));
});
html.find('.conteneur-name a').click(async event => {
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
this.render(true);
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -237,70 +222,56 @@ export class RdDItemSheet extends ItemSheet {
if (this.item.isCompetence()) { if (this.item.isCompetence()) {
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value); let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
this.item.system.base = level; this.item.system.base = level;
$("#base").val(level); this.html.find('[name="system.base"]').val(level);
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
get template() {
let type = this.item.type
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
}
/* -------------------------------------------- */
/** @override */ /** @override */
_updateObject(event, formData) { _updateObject(event, formData) {
// Données de bonus de cases ? if (this.item.type == 'sort') {
formData['system.bonuscase'] = RdDItemSort.buildBonusCaseStringFromFormData(formData.bonusValue, formData.caseValue); // Données de bonus de cases ?
formData['system.bonuscase'] = RdDItemSort.buildBonusCaseStringFromFormData(formData.bonusValue, formData.caseValue);
}
return this.item.update(formData); return this.item.update(formData);
} }
/* -------------------------------------------- */
async _onDragStart(event) { async _onDragStart(event) {
console.log("_onDragStart", event);
if (event.target.classList.contains("entity-link")) return;
const itemId = event.srcElement?.attributes["data-item-id"].value;
const item = this.actor.items.get(itemId);
// Create drag data
const dragData = {
actorId: this.actor.id,
type: "Item",
data: item.system
};
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
} }
async _onDrop(event) { async _onDrop(event) {
// Try to extract the dragData // Try to extract the dragData
let dragData; let dragData = RdDItemSheet.$extractDragData(event);
try { if (!dragData) return false;
dragData = JSON.parse(event.dataTransfer.getData('text/plain'));
} catch (err) {
return false;
}
const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData); const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData);
if (allowed === false) return; if (allowed === false) return false;
// Handle different dragData types // Handle different dragData types
switch (dragData.type) { switch (dragData.type) {
case "Item": case "Item":
return this._onDropItem(event, dragData); return this._onDropItem(event, dragData);
case "Actor":
return this._onDropActor(event, dragData);
} }
return super._onDrop(event); return super._onDrop(event);
} }
/* -------------------------------------------- */ static $extractDragData(event) {
async _onDropItem(event, dragData) { try {
if (this.actor) { const eventData = event?.dataTransfer?.getData('text/plain');
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor.id, dragData, this.objetVersConteneur); if (eventData) {
await this.actor.processDropItem(dropParams); return JSON.parse(eventData);
await this.render(true); }
} } catch (err) { }
return undefined;
} }
async _onDropItem(event, dragData) {
}
async _onDropActor(event, dragData) {
}
} }

View File

@@ -1,30 +1,14 @@
import { SYSTEM_RDD } from "./constants.js"; import { RdDItemSheet } from "./item-sheet.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js"; import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js"; import { TMRUtility } from "./tmr-utility.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
/** /**
* Item sheet pour signes draconiques * Item sheet pour signes draconiques
* @extends {ItemSheet} * @extends {RdDItemSheet}
*/ */
export class RdDSigneDraconiqueItemSheet extends ItemSheet { export class RdDSigneDraconiqueItemSheet extends RdDItemSheet {
/** @override */ static get ITEM_TYPE() { return "signedraconique" }
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: [SYSTEM_RDD, "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
width: 550,
height: 550
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
return buttons;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/** @override */ /** @override */
@@ -62,12 +46,13 @@ export class RdDSigneDraconiqueItemSheet extends ItemSheet {
if (!this.options.editable) return; if (!this.options.editable) return;
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire()); html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("input.select-tmr").change((event) => this.onSelectTmr(event)); html.find("input.select-tmr").change(event => this.onSelectTmr(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value))); html.find(".signe-xp-sort").change(event => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
} }
async setSigneAleatoire() { async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique(); const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
newSigne.name = this.item.name;
this.item.update(newSigne); this.item.update(newSigne);
} }
@@ -89,12 +74,4 @@ export class RdDSigneDraconiqueItemSheet extends ItemSheet {
await this.item.update({ 'system.valeur': newValeur }); await this.item.update({ 'system.valeur': newValeur });
} }
/* -------------------------------------------- */
get template() {
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
}
get title() {
return `Signe draconique: ${this.object.name}`;
}
} }

View File

@@ -1,15 +1,17 @@
import { DialogItemVente } from "./dialog-item-vente.js"; import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDHerbes } from "./rdd-herbes.js"; import { RdDHerbes } from "./rdd-herbes.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
const typesObjetsEquipement = [ const typesObjetsInventaire = [
"arme", "arme",
"armure", "armure",
"conteneur", "conteneur",
"gemme", "gemme",
"herbe", "herbe",
"ingredient", "ingredient",
"faune",
"livre", "livre",
"monnaie", "monnaie",
"munition", "munition",
@@ -18,7 +20,7 @@ const typesObjetsEquipement = [
"potion", "potion",
] ]
const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"] const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"]
const typesObjetsDraconiques = ["queue", "ombre", "souffle", "tete", "signedraconique", "sortreserve"] const typesObjetsDraconiques = ["queue", "ombre", "souffle", "tete", "signedraconique", "sortreserve", "rencontre"]
const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"] const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"]
const typesObjetsEffet = ["possession", "poison", "maladie"] const typesObjetsEffet = ["possession", "poison", "maladie"]
const typesObjetsCompetence = ["competence", "competencecreature"] const typesObjetsCompetence = ["competence", "competencecreature"]
@@ -35,9 +37,11 @@ export const defaultItemImg = {
conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp", conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp",
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp", herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.webp",
faune: "systems/foundryvtt-reve-de-dragon/icons/faune/rongeur.webp",
ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp", ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp",
livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp", livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp",
potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp", potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp",
rencontre: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp", ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp", souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
@@ -57,20 +61,61 @@ export const defaultItemImg = {
gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp", gemme: "systems/foundryvtt-reve-de-dragon/icons/gemmes/almaze.webp",
possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp", possession: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp", sortreserve: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
extraitpoetique: "systems/foundryvtt-reve-de-dragon/icons/competence_ecriture.webp",
tarot: "systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp",
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDItem extends Item { export class RdDItem extends Item {
static getDefaultImg(itemType) {
return defaultItemImg[itemType];
}
static isItemInventaire(newLocal) {
return typesObjetsInventaire.includes(newLocal.type);
}
static isFieldInventaireModifiable(type, field) {
switch (field) {
case 'quantite':
if (['conteneur'].includes(type)) {
return false;
}
break;
case 'cout':
if (['monnaie'].includes(type)) {
return game.user.isGM;
}
break;
}
return true;
}
getUniteQuantite() {
switch (this.type) {
case "monnaie": return "(Pièces)"
case "herbe":
switch (this.system.categorie) {
case 'Alchimie': case 'Repos': case 'Soin':
return "(Brins)"
case 'Cuisine': return '';
}
return '';
case "ingredient": return "(Pépins ou Brins)"
}
return '';
}
constructor(itemData, context) { constructor(itemData, context) {
if (!itemData.img) { if (!itemData.img) {
itemData.img = defaultItemImg[itemData.type]; itemData.img = RdDItem.getDefaultImg(itemData.type);
} }
super(itemData, context); super(itemData, context);
} }
static getTypesObjetsEquipement() { static getItemTypesInventaire() {
return typesObjetsEquipement return typesObjetsInventaire
} }
static getTypesOeuvres() { static getTypesOeuvres() {
@@ -80,11 +125,14 @@ export class RdDItem extends Item {
isCompetencePersonnage() { isCompetencePersonnage() {
return this.type == 'competence' return this.type == 'competence'
} }
isCompetenceCreature() {
return this.type == 'competencecreature'
}
isCompetence() { isCompetence() {
return typesObjetsCompetence.includes(this.type) return typesObjetsCompetence.includes(this.type)
} }
isEquipement() { isInventaire() {
return typesObjetsEquipement.includes(this.type) return RdDItem.isItemInventaire(this)
} }
isOeuvre() { isOeuvre() {
return typesObjetsOeuvres.includes(this.type) return typesObjetsOeuvres.includes(this.type)
@@ -103,7 +151,7 @@ export class RdDItem extends Item {
} }
getItemGroup() { getItemGroup() {
if (this.isEquipement()) return "equipement"; if (this.isInventaire()) return "equipement";
if (this.isOeuvre()) return "oeuvre"; if (this.isOeuvre()) return "oeuvre";
if (this.isDraconique()) return "draconique"; if (this.isDraconique()) return "draconique";
if (this.isConnaissance()) return "connaissance"; if (this.isConnaissance()) return "connaissance";
@@ -124,9 +172,25 @@ export class RdDItem extends Item {
return !this.isConteneur() || (this.system.contenu?.length ?? 0) == 0; return !this.isConteneur() || (this.system.contenu?.length ?? 0) == 0;
} }
isAlcool() { isNourritureBoisson() {
return this.type == 'nourritureboisson' && this.system.boisson && this.system.alcoolise; return this.type == 'nourritureboisson';
} }
isComestible() {
switch (this.type) {
case 'nourritureboisson': return 'pret';
case 'herbe':
return this.system.categorie == 'Cuisine' && this.system.sust > 0 ? 'brut' : '';
case 'faune':
return this.system.sust > 0 ? 'brut' : '';
}
return '';
}
isAlcool() {
return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise;
}
isHerbeAPotion() { isHerbeAPotion() {
return this.type == 'herbe' && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); return this.type == 'herbe' && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos');
} }
@@ -147,29 +211,38 @@ export class RdDItem extends Item {
getEncTotal() { getEncTotal() {
return this.getEnc() * this.getQuantite(); return this.getEnc() * this.getQuantite();
} }
getEnc() { getEnc() {
switch (this.type) { switch (this.type) {
case 'herbe': case 'herbe':
return encBrin; return this.getEncHerbe();
case 'gemme': case '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);
} }
prixTotalDeniers() { getEncHerbe() {
return this.getQuantite() * this.valeurDeniers() switch (this.system.categorie) {
case 'Repos': case 'Soin': case 'Alchimie':
return encBrin;
}
return this.system.encombrement;
} }
valeurDeniers() { valeurTotale() {
return Math.max(Math.round(this.system.cout ? (this.system.cout * 100) : (this.system.valeur_deniers ?? 0)), 0) return this.getQuantite() * this.valeur()
}
valeur() {
return this.system.cout ?? 0
} }
prepareDerivedData() { prepareDerivedData() {
super.prepareDerivedData(); super.prepareDerivedData();
if (this.isEquipement()) { if (this.isInventaire()) {
this.system.encTotal = this.getEncTotal(); this.system.encTotal = this.getEncTotal();
if (this.isPotion()) { if (this.isPotion()) {
this.prepareDataPotion() this.prepareDataPotion()
@@ -190,19 +263,43 @@ export class RdDItem extends Item {
} }
getActionPrincipale(options = { warnIfNot: true }) { getActionPrincipale(options = { warnIfNot: true }) {
const warn = options.warnIfNot;
switch (this.type) { switch (this.type) {
case 'nourritureboisson': return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
case 'potion': return this._actionOrWarnQuantiteZero('Boire', warn);
case 'livre': return this._actionOrWarnQuantiteZero('Lire', warn);
case 'conteneur': return 'Ouvrir'; case 'conteneur': return 'Ouvrir';
case 'herbe': return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined; }
case 'queue': case 'ombre': return this.system.refoulement>0 ? 'Refouler' : undefined; if (this.actor?.isPersonnage()) {
const warn = options.warnIfNot;
if (this.isComestible() == 'brut') {
return 'Utiliser';
}
switch (this.type) {
case 'nourritureboisson': return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
case 'potion': return this._actionOrWarnQuantiteZero('Boire', warn);
case 'livre': return this._actionOrWarnQuantiteZero('Lire', warn);
case 'herbe': return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
case 'queue': case 'ombre': return this.system.refoulement > 0 ? 'Refouler' : undefined;
}
} }
return undefined; return undefined;
} }
/* -------------------------------------------- */
async actionPrincipale(actor, onActionItem = async () => { }) {
if (!this.getActionPrincipale()) {
return;
}
if (await actor.actionNourritureboisson(this, onActionItem)) {
return;
}
switch (this.type) {
case 'potion': return await actor.consommerPotion(this, onActionItem);
case 'livre': return await actor.actionLire(this);
case 'conteneur': return await this.sheet.render(true);
case 'herbe': return await actor.actionHerbe(this);
case 'queue': case 'ombre': return await actor.actionRefoulement(this);
}
}
_actionOrWarnQuantiteZero(actionName, warn){ _actionOrWarnQuantiteZero(actionName, warn) {
if ((this.system.quantite ?? 0) <= 0) { if ((this.system.quantite ?? 0) <= 0) {
if (warn) { if (warn) {
ui.notifications.warn(`Vous n'avez plus de ${this.name}.`); ui.notifications.warn(`Vous n'avez plus de ${this.name}.`);
@@ -219,6 +316,42 @@ export class RdDItem extends Item {
await this.quantiteIncDec(-nombre, options); await this.quantiteIncDec(-nombre, options);
} }
async onCreateDecoupeComestible(actor) {
if (actor && this.isComestible() == 'brut' && this.system.sust != 1) {
if (this.system.sust < 1) {
await actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
'system.sust': 0
}])
}
else {
const sust = Math.floor(this.system.sust);
await actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
'system.quantite': this.system.quantite * sust,
'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2),
'system.cout': Misc.keepDecimals(this.system.cout / sust, 2),
'system.sust': 1
}])
}
}
}
async empiler(item) {
if (this.isComestible() == 'brut') {
const sust = this.system.sust + item.system.sust;
const encombrement = this.system.encombrement + item.system.encombrement;
await this.update({
"system.sust": sust,
"system.encombrement": encombrement
});
}
else {
await this.quantiteIncDec(item.system.quantite);
}
await item.delete();
}
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) { async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
const quantite = Number(this.system.quantite ?? -1); const quantite = Number(this.system.quantite ?? -1);
if (quantite >= 0) { if (quantite >= 0) {
@@ -242,14 +375,13 @@ export class RdDItem extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
// détermine si deux équipements sont similaires: de même type, et avec les même champs hormis la quantité // détermine si deux équipements sont similaires: de même type, et avec les même champs hormis la quantité
isEquipementEmpilable(other) { isInventaireEmpilable(other) {
if (!other || !this.isEquipement()) { if (!other || !this.isInventaire()) {
return [false, undefined]; return [false, undefined];
} }
if (this.system.quantite == undefined) { if (this.system.quantite == undefined) {
return [false, `Impossible de regrouper des ${this.type}, ils ne sont pas empilables`]; return [false, `Impossible de regrouper des ${this.type}, ils ne sont pas empilables`];
} }
else if (this.type != other.type) { else if (this.type != other.type) {
return [false, `Impossible de regrouper des ${this.type} avec des ${other.type}`]; return [false, `Impossible de regrouper des ${this.type} avec des ${other.type}`];
} }
@@ -257,8 +389,13 @@ export class RdDItem extends Item {
return [false, `Impossible de regrouper ${this.name} avec ${other.name}`]; return [false, `Impossible de regrouper ${this.name} avec ${other.name}`];
} }
else { else {
const differences = Object.entries(this.system) const excludedProperties = ['quantite', 'cout', 'encTotal'];
.filter(([key, value]) => !['quantite', 'cout', 'encTotal'].includes(key) && value != other.system[key]); if (this.isComestible()) {
excludedProperties.push('sust', 'encombrement');
}
let differences = Object.entries(this.system)
.filter(([key, value]) => !excludedProperties.includes(key))
.filter(([key, value]) => value != other.system[key])
if (differences.length > 0) { if (differences.length > 0) {
let message = `Impossible de regrouper les ${this.type} ${this.name}: `; let message = `Impossible de regrouper les ${this.type} ${this.name}: `;
for (const [key, value] of differences) { for (const [key, value] of differences) {
@@ -276,7 +413,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(this, async (vente) => { await DialogItemVente.display(this, async (vente) => {
vente["properties"] = this.getProprietes(); vente["properties"] = this.getProprietes();
if (vente.isOwned) { if (vente.isOwned) {
if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) { if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) {
@@ -285,7 +422,7 @@ export class RdDItem extends Item {
} }
} }
vente.jsondata = JSON.stringify(vente.item); vente.jsondata = JSON.stringify(vente.item);
console.log(vente); console.log(vente);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
ChatMessage.create(RdDUtility.chatDataSetup(html)); ChatMessage.create(RdDUtility.chatDataSetup(html));
@@ -294,15 +431,14 @@ export class RdDItem extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
getProprietes() { getProprietes() {
return this[`_${this.type}ChatData`](); return this[`_${this.type}ChatData`]().filter(it => it != undefined);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async postItem(modeOverride) { async postItem(modeOverride) {
console.log(this); console.log(this);
let chatData = duplicate(this); let chatData = duplicate(this);
const properties = this.getProprietes(); chatData["properties"] = this.getProprietes();
chatData["properties"] = properties
if (this.actor) { if (this.actor) {
chatData.actor = { id: this.actor.id }; chatData.actor = { id: this.actor.id };
} }
@@ -319,262 +455,237 @@ export class RdDItem extends Item {
}); });
} }
static propertyIfDefined(name, val, condition = (it) => true) { static propertyIfDefined(name, val, condition = true) {
return condition ? [`<b>${name}</b>: ${val}`] : []; return condition ? `<b>${name}</b>: ${val}` : undefined;
} }
_inventaireTemplateChatData() {
return [
RdDItem.propertyIfDefined('Qualité', this.system.qualite, this.system.qualite != 0),
RdDItem.propertyIfDefined('Encombrement', this.system.encombrement)
// cout et quantité masqués
]
}
/* -------------------------------------------- */ /* -------------------------------------------- */
_objetChatData() { _objetChatData() {
const tplData = this.system return this._inventaireTemplateChatData()
let properties = [].concat(
RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance),
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_nourritureboissonChatData() { _nourritureboissonChatData() {
const tplData = this.system return [
let properties = [].concat( RdDItem.propertyIfDefined('Sustentation', this.system.sust, this.system.sust > 0),
RdDItem.propertyIfDefined('Sustentation', tplData.sust, tplData.sust > 0), RdDItem.propertyIfDefined('Désaltère', this.system.desaltere, this.system.boisson),
RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson), RdDItem.propertyIfDefined('Force alcool', this.system.force, this.system.boisson && this.system.alcoolise),
RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise), RdDItem.propertyIfDefined('Exotisme', this.system.exotisme, this.system.exotisme < 0),
RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0), ...this._inventaireTemplateChatData()
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite), ]
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_armeChatData() { _armeChatData() {
const tplData = this.system return [
let properties = [ `<b>Compétence</b>: ${this.system.competence}`,
`<b>Compétence</b>: ${tplData.competence}`, `<b>Dommages</b>: ${this.system.dommages}`,
`<b>Dommages</b>: ${tplData.dommages}`, `<b>Force minimum</b>: ${this.system.force}`,
`<b>Force minimum</b>: ${tplData.force}`, `<b>Resistance</b>: ${this.system.resistance}`,
`<b>Resistance</b>: ${tplData.resistance}`, ...this._inventaireTemplateChatData()
`<b>Encombrement</b>: ${tplData.encombrement}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_conteneurChatData() { _conteneurChatData() {
const tplData = this.system return [
let properties = [ `<b>Capacité</b>: ${this.system.capacite} Enc.`,
`<b>Capacité</b>: ${tplData.capacite} Enc.`, ...this._inventaireTemplateChatData()
`<b>Encombrement</b>: ${tplData.encombrement}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_munitionChatData() { _munitionChatData() {
const tplData = this.system return this._inventaireTemplateChatData()
let properties = [
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_armureChatData() { _armureChatData() {
const tplData = this.system return [
let properties = [ `<b>Protection</b>: ${this.system.protection}`,
`<b>Protection</b>: ${tplData.protection}`, `<b>Détérioration</b>: ${this.system.deterioration}`,
`<b>Détérioration</b>: ${tplData.deterioration}`, `<b>Malus armure</b>: ${this.system.malus}`,
`<b>Malus armure</b>: ${tplData.malus}`, ...this._inventaireTemplateChatData()
`<b>Encombrement</b>: ${tplData.encombrement}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_competenceChatData() { _competenceChatData() {
const tplData = this.system return [
let properties = [ `<b>Catégorie</b>: ${this.system.categorie}`,
`<b>Catégorie</b>: ${tplData.categorie}`, `<b>Niveau</b>: ${this.system.niveau}`,
`<b>Niveau</b>: ${tplData.niveau}`, `<b>Caractéristique par défaut</b>: ${this.system.carac_defaut}`,
`<b>Caractéristique par défaut</b>: ${tplData.carac_defaut}`, `<b>XP</b>: ${this.system.xp}`
`<b>XP</b>: ${tplData.xp}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_competencecreatureChatData() { _competencecreatureChatData() {
const tplData = this.system return [
let properties = [ `<b>Catégorie</b>: ${this.system.categorie}`,
`<b>Catégorie</b>: ${tplData.categorie}`, `<b>Niveau</b>: ${this.system.niveau}`,
`<b>Niveau</b>: ${tplData.niveau}`, `<b>Caractéristique</b>: ${this.system.carac_value}`,
`<b>Caractéristique</b>: ${tplData.carac_value}`, `<b>XP</b>: ${this.system.xp}`
`<b>XP</b>: ${tplData.xp}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_sortChatData() { _sortChatData() {
const tplData = this.system return [
let properties = [ `<b>Draconic</b>: ${this.system.draconic}`,
`<b>Draconic</b>: ${tplData.draconic}`, `<b>Difficulté</b>: ${this.system.difficulte}`,
`<b>Difficulté</b>: ${tplData.difficulte}`, `<b>Case TMR</b>: ${this.system.caseTMR}`,
`<b>Case TMR</b>: ${tplData.caseTMR}`, `<b>Points de Rêve</b>: ${this.system.ptreve}`
`<b>Points de Rêve</b>: ${tplData.ptreve}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_herbeChatData() { _herbeChatData() {
const tplData = this.system return [
let properties = [ `<b>Milieu</b>: ${this.system.milieu}`,
`<b>Milieu</b>: ${tplData.milieu}`, `<b>Catégorie</b>: ${this.system.categorie}`,
`<b>Rareté</b>: ${tplData.rarete}`, ...this._inventaireTemplateChatData()
`<b>Catégorie</b>: ${tplData.categorie}`,
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_ingredientChatData() { _ingredientChatData() {
const tplData = this.system return [
let properties = [ `<b>Milieu</b>: ${this.system.milieu}`,
`<b>Milieu</b>: ${tplData.milieu}`, `<b>Catégorie</b>: ${this.system.categorie}`,
`<b>Rareté</b>: ${tplData.rarete}`, ...this._inventaireTemplateChatData()
`<b>Catégorie</b>: ${tplData.categorie}`, ]
}
/* -------------------------------------------- */
_fauneChatData() {
return [
`<b>Sustentation</b>: ${this.system.sust}`,
`<b>Milieu</b>: ${this.system.milieu}`,
...this._inventaireTemplateChatData()
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_tacheChatData() { _tacheChatData() {
const tplData = this.system return [
let properties = [ `<b>Caractéristique</b>: ${this.system.carac}`,
`<b>Caractéristique</b>: ${tplData.carac}`, `<b>Compétence</b>: ${this.system.competence}`,
`<b>Compétence</b>: ${tplData.competence}`, `<b>Périodicité</b>: ${this.system.periodicite}`,
`<b>Périodicité</b>: ${tplData.periodicite}`, `<b>Fatigue</b>: ${this.system.fatigue}`,
`<b>Fatigue</b>: ${tplData.fatigue}`, `<b>Difficulté</b>: ${this.system.difficulte}`,
`<b>Difficulté</b>: ${tplData.difficulte}` RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
].concat([ `<b>Points de Tâche atteints</b>: ${this.system.points_de_tache_courant}`]
tplData.cacher_points_de_tache ? [] :`<b>Points de Tâche</b>: ${tplData.points_de_tache}`
]).concat([
`<b>Points de Tâche atteints</b>: ${tplData.points_de_tache_courant}`]
);
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_livreChatData() { _livreChatData() {
const tplData = this.system return [
let properties = [ `<b>Compétence</b>: ${this.system.competence}`,
`<b>Compétence</b>: ${tplData.competence}`, `<b>Auteur</b>: ${this.system.auteur}`,
`<b>Auteur</b>: ${tplData.auteur}`, `<b>Difficulté</b>: ${this.system.difficulte}`,
`<b>Difficulté</b>: ${tplData.difficulte}`, RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
`<b>Points de Tâche</b>: ${tplData.points_de_tache}`, ...this._inventaireTemplateChatData()
`<b>Encombrement</b>: ${tplData.encombrement}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_potionChatData() { _potionChatData() {
const tplData = this.system return [
let properties = [ `<b>Rareté</b>: ${this.system.rarete}`,
`<b>Rareté</b>: ${tplData.rarete}`, `<b>Catégorie</b>: ${this.system.categorie}`,
`<b>Catégorie</b>: ${tplData.categorie}`, ...this._inventaireTemplateChatData()
`<b>Encombrement</b>: ${tplData.encombrement}`,
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_queueChatData() { _queueChatData() {
const tplData = this.system function label(categorie) {
let properties = [ switch (categorie) {
`<b>Refoulement</b>: ${tplData.refoulement}` case 'ideefixe': return 'Idée fixe';
case 'lancinant': return 'Désir lancinant';
}
return ''
}
return [
`<b>Refoulement</b>: ${this.system.refoulement}`,
`<b>Catégorie</b>: ${label(this.system.categorie)}`,
`<b>Affecte</b>: ${this.system.hautrevant ? 'les haut-rêvants' : 'tout le monde'}`,
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_ombreChatData() { _ombreChatData() {
const tplData = this.system return this._queueChatData()
let properties = [
`<b>Refoulement</b>: ${tplData.refoulement}`
]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_souffleChatData() { _souffleChatData() {
const tplData = this.system return [
let properties = []; `<b>Affecte</b>: ${this.system.hautrevant ? 'les haut-rêvants' : 'tout le monde'}`,
return properties; ];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_teteChatData() { _teteChatData() {
const tplData = this.system return [
let properties = []; `<b>Affecte</b>: ${this.system.hautrevant ? 'les haut-rêvants' : 'tout le monde'}`,
return properties; ];
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_tarotChatData() { _tarotChatData() {
const tplData = this.system return [
let properties = [ RdDItem.propertyIfDefined('Carte', RdDUtility.linkCompendium(this.pack, this.id, this.name), this.pack),
`<b>Concept</b>: ${tplData.concept}`, `<b>Concept</b>: ${this.system.concept}`,
`<b>Aspect</b>: ${tplData.aspect}`, `<b>Aspect</b>: ${this.system.aspect}`,
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_nombreastralChatData() { _nombreastralChatData() {
const tplData = this.system return [
let properties = [ `<b>Valeur</b>: ${this.system.value}`,
`<b>Valeur</b>: ${tplData.value}`, `<b>Jour</b>: ${this.system.jourlabel}`,
`<b>Jour</b>: ${tplData.jourlabel}`,
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_monnaieChatData() { _monnaieChatData() {
const tplData = this.system return this._inventaireTemplateChatData()
let properties = [
`<b>Valeur en Deniers</b>: ${tplData.valeur_deniers}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_meditationChatData() { _meditationChatData() {
const tplData = this.system return [
let properties = [ `<b>Thème</b>: ${this.system.theme}`,
`<b>Thème</b>: ${tplData.theme}`, `<b>Compétence</b>: ${this.system.competence}`,
`<b>Compétence</b>: ${tplData.competence}`, `<b>Support</b>: ${this.system.support}`,
`<b>Support</b>: ${tplData.support}`, `<b>Heure</b>: ${this.system.heure}`,
`<b>Heure</b>: ${tplData.heure}`, `<b>Purification</b>: ${this.system.purification}`,
`<b>Purification</b>: ${tplData.purification}`, `<b>Vêture</b>: ${this.system.veture}`,
`<b>Vêture</b>: ${tplData.veture}`, `<b>Comportement</b>: ${this.system.comportement}`,
`<b>Comportement</b>: ${tplData.comportement}`, `<b>Case TMR</b>: ${this.system.tmr}`
`<b>Case TMR</b>: ${tplData.tmr}` ]
}
/* -------------------------------------------- */
_rencontreChatData() {
if (this.system.coord) {
return [
`<b>Force</b>: ${this.system.force}`,
`<b>Coordonnées</b>: ${this.system.coord}`,
]
}
return [
`<b>Force</b>: ${this.system.formule}`,
`<b>Refoulement</b>: ${this.system.refoulement}`,
RdDItem.propertyIfDefined('<b>Présent de cités</b>', '', this.system.presentCite),
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_casetmrChatData() { _casetmrChatData() {
const tplData = this.system return [
let properties = [ `<b>Coordonnée</b>: ${this.system.coord}`,
`<b>Coordonnée</b>: ${tplData.coord}`, `<b>Spécificité</b>: ${this.system.specific}`
`<b>Spécificité</b>: ${tplData.specific}`
] ]
return properties;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_maladieChatData() { _maladieChatData() {
const tplData = this.system if (!this.system.identifie) {
let properties return [`<b>Inconnue</b>`]
if (tplData.identifie) {
properties = [
`<b>Malignité</b>: ${tplData.malignite}`,
`<b>Périodicité</b>: ${tplData.periodicite}`,
`<b>Dommages</b>: ${tplData.dommages}`
]
if (tplData.remedesconnus) {
properties.push(`<b>Remedes</b>: ${tplData.remedes}`)
}
} else {
properties = [
`<b>Inconnue</b>`]
} }
return properties; return [
`<b>Malignité</b>: ${this.system.malignite}`,
`<b>Périodicité</b>: ${this.system.periodicite}`,
`<b>Dommages</b>: ${this.system.dommages}`,
RdDItem.propertyIfDefined('<b>Remedes</b>', this.system.remedes, this.system.remedesconnus),
]
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -584,16 +695,13 @@ export class RdDItem extends Item {
/* -------------------------------------------- */ /* -------------------------------------------- */
_gemmeChatData() { _gemmeChatData() {
const tplData = this.system return [
let properties = [ `<b>Pureté</b>: ${this.system.purete}`,
`<b>Pureté</b>: ${tplData.purete}`, `<b>Taille</b>: ${this.system.taille}`,
`<b>Taille</b>: ${tplData.taille}`, `<b>Inertie</b>: ${this.system.inertie}`,
`<b>Inertie</b>: ${tplData.inertie}`, `<b>Enchantabilité</b>: ${this.system.enchantabilite}`,
`<b>Enchantabilité</b>: ${tplData.enchantabilite}`, ...this._inventaireTemplateChatData()
`<b>Prix</b>: ${tplData.cout}`,
] ]
return properties;
} }
} }

View File

@@ -1,4 +1,5 @@
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js"; import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
import { Environnement } from "./environnement.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
class Migration { class Migration {
@@ -42,7 +43,7 @@ class _10_0_16_MigrationSortsReserve extends Migration {
await actor.createEmbeddedDocuments("Item", sortsReserve, { await actor.createEmbeddedDocuments("Item", sortsReserve, {
renderSheet: false, renderSheet: false,
}); });
await actor.update({ 'system.reve.reserve.list': [] }) await actor.update({ 'system.reve.reserve': undefined })
}); });
} }
@@ -98,12 +99,177 @@ class _10_0_21_VehiculeStructureResistanceMax extends Migration {
} }
} }
class _10_0_33_MigrationNomsDraconic extends Migration {
get code() { return "competences-creature-parade"; }
get version() { return "10.0.33"; }
migrationNomDraconic(ancien) {
if (typeof ancien == 'string') {
switch (ancien) {
case 'oniros': case "Voie d'Oniros": return "Voie d'Oniros";
case 'hypnos': case "Voie d'Hypnos": return "Voie d'Hypnos";
case 'narcos': case "Voie de Narcos": return "Voie de Narcos";
case 'thanatos': case "Voie de Thanatos": return "Voie de Thanatos";
}
return ancien;
}
else if (typeof ancien.name == 'string') {
return this.migrationNomDraconic(ancien.name)
}
return ancien;
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => ["sort", "sortreserve"].includes(it.type)
&& (typeof it.system.draconic == 'string') || (typeof it.system.draconic?.name == 'string'))
.map(it => { return { _id: it.id, "system.draconic": this.migrationNomDraconic(it.system.draconic) } }));
}
}
class _10_2_5_ArmesTirLancer extends Migration {
constructor() {
super();
this.dagues = { "system.competence": 'Dague', "system.lancer": 'Dague de jet', "system.portee_courte": 3, "system.portee_moyenne": 8, "system.portee_extreme": 15 }
this.javelot = { "system.competence": 'Lance', "system.lancer": 'Javelot', "system.portee_courte": 6, "system.portee_moyenne": 12, "system.portee_extreme": 20 }
this.fouet = { "system.competence": '', "system.lancer": 'Fouet', "system.portee_courte": 2, "system.portee_moyenne": 2, "system.portee_extreme": 3, "system.penetration": -1 }
this.arc = { "system.competence": '', "system.tir": 'Arc' }
this.arbalete = { "system.competence": '', "system.tir": 'Arbalète' }
this.fronde = { "system.competence": '', "system.tir": 'Fronde' }
this.mappings = {
'dague': { filter: it => true, updates: this.dagues },
'dague de jet': { filter: it => true, updates: this.dagues },
'javelot': { filter: it => true, updates: this.javelot },
'lance': { filter: it => it.name == 'Javeline', updates: this.javelot },
'fouet': { filter: it => true, updates: this.fouet },
'arc': { filter: it => true, updates: this.arc },
'arbalete': { filter: it => true, updates: this.arbalete },
'fronde': { filter: it => true, updates: this.fronde },
}
}
get code() { return "separation-competences-tir-lancer"; }
get version() { return "10.2.5"; }
migrateArmeTirLancer(it) {
let updates = mergeObject({ _id: it.id }, this.getMapping(it).updates);
console.log(it.name, updates);
return updates;
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => "arme" == it.type)
.filter(it => this.isTirLancer(it))
.filter(it => this.getMapping(it).filter(it))
.map(it => this.migrateArmeTirLancer(it)));
}
isTirLancer(it) {
return Object.keys(this.mappings).includes(this.getCompKey(it));
}
getMapping(it) {
return this.mappings[this.getCompKey(it)];
}
getCompKey(it) {
return Grammar.toLowerCaseNoAccent(it.system.competence);
}
}
class _10_2_10_DesirLancinant_IdeeFixe extends Migration {
get code() { return "desir-lancinat-idee-fixe"; }
get version() { return "10.2.10"; }
migrateQueue(it) {
let categorie = undefined
let name = it.name
if (Grammar.toLowerCaseNoAccent(name).includes('desir')) {
categorie = 'lancinant';
name = it.name.replace('Désir lancinant : ', '');
}
if (Grammar.toLowerCaseNoAccent(name).includes('idee fixe')) {
categorie = 'ideefixe';
name = it.name.replace('Idée fixe : ', '')
}
return {
_id: it.id, name: name,
'system.ideefixe': undefined,
'system.lancinant': undefined,
'system.categorie': categorie
}
}
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => ['queue', 'ombre'].includes(it.type))
.map(it => this.migrateQueue(it))
);
}
}
class _10_3_0_Inventaire extends Migration {
get code() { return "migration-equipement-inventaire"; }
get version() { return "10.3.0"; }
async migrate() {
await this.applyItemsUpdates(items => {
return this._updatesMonnaies(items)
.concat(this._updatesNonEquipe(items))
.concat(this._updatesObjets(items))
});
}
_updatesNonEquipe(items) {
return items
.filter(it => ['munition'].includes(it.type))
.map(it => { return { _id: it.id, 'system.equipe': undefined } });
}
_updatesObjets(items) {
return items
.filter(it => ['objet'].includes(it.type))
.map(it => { return { _id: it.id, 'system.resistance': undefined, 'system.equipe': undefined } });
}
_updatesMonnaies(items) {
return items
.filter(it => ['monnaie'].includes(it.type) && it.system.cout == undefined)
.map(it => { return { _id: it.id, 'system.cout': it.system.valeur_deniers / 100, 'system.valeur_deniers': undefined } });
}
}
class _10_3_0_FrequenceEnvironnement extends Migration {
get code() { return "migration-frequence-resources"; }
get version() { return "10.3.0"; }
async migrate() {
await this.applyItemsUpdates(items => items.filter(it => ['herbe', 'ingredient'].includes(it.type))
.map(it => this._updatesFrequences(it)));
}
_updatesFrequences(it) {
return {
_id: it.id,
'system.rarete': undefined,
'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }]
}
}
}
export class Migrations { export class Migrations {
static getMigrations() { static getMigrations() {
return [ return [
new _10_0_16_MigrationSortsReserve(), new _10_0_16_MigrationSortsReserve(),
new _10_0_17_MigrationCompetenceCreature(), new _10_0_17_MigrationCompetenceCreature(),
new _10_0_21_VehiculeStructureResistanceMax(), new _10_0_21_VehiculeStructureResistanceMax(),
new _10_0_33_MigrationNomsDraconic(),
new _10_2_5_ArmesTirLancer(),
new _10_2_10_DesirLancinant_IdeeFixe(),
new _10_3_0_Inventaire(),
new _10_3_0_FrequenceEnvironnement()
]; ];
} }
@@ -118,11 +284,9 @@ export class Migrations {
} }
migrate() { migrate() {
const currentVersion = game.settings.get( const currentVersion = game.settings.get(SYSTEM_RDD,"systemMigrationVersion");
SYSTEM_RDD, //if (isNewerVersion(game.system.version, currentVersion)) {
"systemMigrationVersion" if (true) { /* comment previous and uncomment here to test before upgrade */
);
if (isNewerVersion(game.system.version, currentVersion)) {
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion)); const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
if (migrations.length > 0) { if (migrations.length > 0) {
migrations.sort((a, b) => migrations.sort((a, b) =>

View File

@@ -24,7 +24,7 @@ export class Misc {
} }
static sum() { static sum() {
return (a, b) => a + b; return (a, b) => Number(a) + Number(b);
} }
static ascending(orderFunction = x => x) { static ascending(orderFunction = x => x) {
@@ -41,6 +41,11 @@ export class Misc {
return 0; return 0;
} }
static typeName(type, subType) {
return subType ? game.i18n.localize(`${type.toUpperCase()}.Type${Misc.upperFirst(subType)}`)
: '';
}
/** /**
* Converts the value to an integer, or to 0 if undefined/null/not representing integer * Converts the value to an integer, or to 0 if undefined/null/not representing integer
* @param {*} value value to convert to an integer using parseInt * @param {*} value value to convert to an integer using parseInt
@@ -68,6 +73,19 @@ export class Misc {
} }
} }
static indexLowercase(list) {
const obj = {};
const addToObj = (map, val) => {
const key = Grammar.toLowerCaseNoAccent(val);
if (key && !map[key]) map[key] = val
}
list.forEach(it => addToObj(obj, it))
return obj;
}
static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []);
}
static classify(items, classifier = it => it.type) { static classify(items, classifier = it => it.type) {
let itemsBy = {} let itemsBy = {}
Misc.classifyInto(itemsBy, items, classifier) Misc.classifyInto(itemsBy, items, classifier)
@@ -102,7 +120,11 @@ export class Misc {
} }
static join(params, separator = '') { static join(params, separator = '') {
return params.reduce((a, b) => a + separator + b); return params?.reduce(Misc.joining(separator)) ?? '';
}
static joining(separator = '') {
return (a, b) => a + separator + b;
} }
static connectedGMOrUser(ownerId = undefined) { static connectedGMOrUser(ownerId = undefined) {
@@ -112,13 +134,20 @@ export class Misc {
return Misc.firstConnectedGM()?.id ?? game.user.id; return Misc.firstConnectedGM()?.id ?? game.user.id;
} }
static isRollModeHiddenToPlayer() {
switch (game.settings.get("core", "rollMode")) {
case CONST.DICE_ROLL_MODES.BLIND:
case CONST.DICE_ROLL_MODES.SELF: return true;
}
return false
}
static getActiveUser(id) { static getActiveUser(id) {
return game.users.find(u => u.id == id && u.active); return game.users.find(u => u.id == id && u.active);
} }
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); return game.users.filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active);
} }
static isOwnerPlayer(actor, user=undefined) { static isOwnerPlayer(actor, user=undefined) {
@@ -133,7 +162,11 @@ export class Misc {
* @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 isUniqueConnectedGM() {
return game.user.id == Misc.firstConnectedGM()?.id; return game.user.id == Misc.firstConnectedGMId();
}
static firstConnectedGMId() {
return Misc.firstConnectedGM()?.id;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -191,4 +224,4 @@ export class Misc {
} }
return subset; return subset;
} }
} }

View File

@@ -1,72 +1,13 @@
import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
const poesieHautReve = [
{
reference: 'Le Ratier Bretonien',
extrait: `Le courant du Fleuve
<br>Te domine et te Porte
<br>Avant que tu te moeuves
<br>Combat le, ou il t'emporte`
},
{
reference: 'Incompatibilité, Charles Beaudelaire',
extrait: `Et lorsque par hasard une nuée errante
<br>Assombrit dans son vol le lac silencieux,
<br>On croirait voir la robe ou l'ombre transparente
<br>D'un esprit qui voyage et passe dans les cieux.`
},
{
reference: 'Au fleuve de Loire, Joachim du Bellay',
extrait: `Ô de qui la vive course
<br>Prend sa bienheureuse source,
<br>Dune argentine fontaine,
<br>Qui dune fuite lointaine,
<br>Te rends au sein fluctueux
<br>De lOcéan monstrueux`
},
{
reference: 'Denis Gerfaud',
extrait: `Et l'on peut savoir qui est le maître d'Oniros, c'est le Fleuve de l'Oubli.
Et l'on sait qui est le créateur du Fleuve de l'Oubli, c'est Hypnos et Narcos.
Mais l'on ne sait pas qui est le maître du Fleuve de l'Oubli,
sinon peut-être lui-même, ou peut-être Thanatos` },
{
reference: 'Denis Gerfaud',
extrait: `Narcos est la source du Fleuve de l'Oubli et Hypnos l'embouchure
Remonter le Fleuve est la Voie de la Nuit, la Voie du Souvenir.
Descendre le Fleuve est la Voie du Jour, la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Narcos engendre le fils dont il est la mère à l'heure du Vaisseau,
car Oniros s'embarque pour redescendre le Fleuve
vers son père Hypnos sur la Voie de l'Oubli`
},
{
reference: 'Denis Gerfaud',
extrait: `Hypnos engendre le fils dont il est la mère à l'heure du Serpent, car
tel les serpents, Oniros commence à remonter le Fleuve
sur le Voie du Souvenir vers son père Narcos`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi se succèdent les Jours et les Ages.
<br>Les jours des Dragons sont les Ages des Hommes.`
},
{
reference: 'Denis Gerfaud',
extrait: `Ainsi parlent les sages:
&laquo;Les Dragons sont créateurs de leurs rêves, mais ils ne sont pas créateurs d'Oniros
Les Dragons ne sont pas les maîtres de leurs rêvezs, car ils ne sont pas maîtres d'Oniros.
Nul ne sait qui est le créateur des Dragons, ni qui est leur maître.
Mais l'on peut supposer qui est le maître du Rêve des Dragons, c'est Oniros&raquo;`
},
]
export class Poetique { export class Poetique {
static async getExtrait(){ static async getExtrait() {
return await RdDDice.rollOneOf(poesieHautReve); const items = await SystemCompendiums.getItems('extrait-poetique', 'extraitpoetique')
const selected = await RdDDice.rollOneOf(items);
return {
reference: selected?.name,
extrait: selected?.system.extrait
}
} }
}
}

View File

@@ -1,44 +0,0 @@
Le courant du Fleuve
Te domine et te Porte
Avant que tu te moeuves
Combat le, ou il t'emporte
A vous qui faites ripaille
sourds aux damnés de la faim
à vous qui livrez
une inégale bataille
à ceux qui vous tendent la main
Ils sont tout près ! - Tenons fermée
<br>Cette salle, où nous les narguons.
<br>Quel bruit dehors ! Hideuse armée
<br>De vampires et de dragons !
<br>La poutre du toit descellée
<br>Ploie ainsi qu'une herbe mouillée,
<br>Et la vieille porte rouillée
<br>Tremble, à déraciner ses gonds !`),
https://www.poetica.fr/poeme-1423/guy-de-maupassant-le-sommeil-du-mandarin/
Le monde est un rêve de Dragons. Nous
ne savons pas qui sont les Dragons ni à quoi
ils ressemblent, en dépit de lantique iconographie qui les dépeint comme de gigantesques créatures ailées capables de cracher
feu et flammes.
Car parmi les humains, autre nom lui est donné,
Nom sinistre parmi tous, nom funèbre, c'est la mort!
Un ami disparu... Thanatos est passé...
Messieurs, ne crachez pas de jurons ni d'ordure
Au visage fardé de cette pauvre impure
Que déesse Famine a par un soir d'hiver,
Contrainte à relever ses jupons en plein air.

View File

@@ -15,13 +15,19 @@
// Common conf // Common conf
let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" }; let dialogConf = { content: html, title: "Editeur d'Astrologie", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 } let dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 300, 'z-index': 99999 }
super(dialogConf, dialogOptions) super(dialogConf, dialogOptions)
this.calendrier = calendrier; this.calendrier = calendrier;
this.updateData( calendrierData ); this.updateData( calendrierData );
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async resetNombreAstraux() { async resetNombreAstraux() {
game.system.rdd.calendrier.resetNombreAstral(); game.system.rdd.calendrier.resetNombreAstral();
@@ -39,15 +45,4 @@
this.calendrierData = duplicate(calendrierData); this.calendrierData = duplicate(calendrierData);
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
let astrologieData = this.astrologieData;
$(function () {
});
}
} }

View File

@@ -20,7 +20,7 @@ export class RdDAstrologieJoueur extends Dialog {
astrologie: RdDItemCompetence.findCompetence(actor.items, 'Astrologie') astrologie: RdDItemCompetence.findCompetence(actor.items, 'Astrologie')
} }
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', dialogData); const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', dialogData);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 }; let options = { classes: ["rdd-roll-dialog"], width: 600, height: 500, 'z-index': 99999 };
if (dialogConfig.options) { if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true }); mergeObject(options, dialogConfig.options, { overwrite: true });
} }
@@ -29,21 +29,35 @@ export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, actor, dialogData) { constructor(html, actor, dialogData) {
const dialogConf = {
let myButtons = { title: "Nombres Astraux",
saveButton: { label: "Fermer", callback: html => this.quitDialog() } content: html,
default: "saveButton",
buttons: {
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
},
}; };
const dialogOptions = { classes: ["rdd-roll-dialog"], width: 600, height: 300, 'z-index': 99999 };
// Get all n
// Common conf
let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 };
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
this.actor = actor; this.actor = actor;
this.dataNombreAstral = duplicate(dialogData); this.dataNombreAstral = duplicate(dialogData);
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find(function () {
this.html.find("[name='diffConditions']").val(0);
});
this.html.find('[name="jet-astrologie"]').click((event) => {
this.requestJetAstrologie();
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static organizeNombres(actor) { static organizeNombres(actor) {
let itemNombres = actor.listItemsData('nombreastral'); let itemNombres = actor.listItemsData('nombreastral');
@@ -68,8 +82,8 @@ export class RdDAstrologieJoueur extends Dialog {
carac_vue: this.actor.system.carac['vue'].value, carac_vue: this.actor.system.carac['vue'].value,
etat: this.dataNombreAstral.etat, etat: this.dataNombreAstral.etat,
astrologie: this.dataNombreAstral.astrologie, astrologie: this.dataNombreAstral.astrologie,
conditions: $("#diffConditions").val(), conditions: this.html.find('[name="diffConditions"]').val(),
date: $("#joursAstrologie").val(), date: this.html.find('[name="joursAstrologie"]').val(),
userId: game.user.id userId: game.user.id
} }
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
@@ -87,17 +101,4 @@ export class RdDAstrologieJoueur extends Dialog {
quitDialog() { quitDialog() {
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
$(function () {
$("#diffConditions").val(0);
});
html.find('#jet-astrologie').click((event) => {
this.requestJetAstrologie();
});
}
} }

View File

@@ -8,50 +8,45 @@ export class RdDCalendrierEditeur extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, calendrier, calendrierData) { constructor(html, calendrier, calendrierData) {
let dialogConf = {
let myButtons = { content: html,
saveButton: { label: "Enregistrer", callback: html => this.fillData() } title: "Editeur de date/heure",
}; buttons: {
save: { label: "Enregistrer", callback: html => this.fillData() }
// Common conf },
let dialogConf = { content: html, title: "Editeur de date/heure", buttons: myButtons, default: "saveButton" }; default: "save"
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 300, 'z-index': 99999 } };
let dialogOptions = { classes: ["rdd-dialog-calendar-editor"], width: 400, height: 'fit-content', 'z-index': 99999 }
super(dialogConf, dialogOptions) super(dialogConf, dialogOptions)
this.calendrier = calendrier; this.calendrier = calendrier;
this.calendrierData = calendrierData; //duplicate(calendrierData); this.calendrierData = calendrierData;
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find("input[name='nomMois']").val(this.calendrierData.moisKey);
this.html.find("select[name='nomHeure']").val(this.calendrierData.heureKey);
this.html.find("select[name='jourMois']").val(this.calendrierData.jourMois);
this.html.find("select[name='minutesRelative']").val(calendrierData.minutesRelative);
this.html.find("select[name='annee']").val(this.calendrierData.annee);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
fillData( ) { fillData() {
this.calendrierData.moisKey = $("#nomMois").val(); this.calendrierData.annee = this.html.find("input[name='annee']").val();
this.calendrierData.heureKey = $("#nomHeure").val(); this.calendrierData.moisKey = this.html.find("select[name='nomMois']").val();
this.calendrierData.jourMois = $("#jourMois").val(); this.calendrierData.heureKey = this.html.find("select[name='nomHeure']").val();
this.calendrierData.minutesRelative = $("#minutesRelative").val(); this.calendrierData.jourMois = this.html.find("select[name='jourMois']").val();
this.calendrierData.minutesRelative = this.html.find("select[name='minutesRelative']").val();
console.log("UPDATE ", this.calendrierData);
this.calendrier.saveEditeur( this.calendrierData ) this.calendrier.saveEditeur(this.calendrierData)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
updateData( calendrierData ) { updateData(calendrierData) {
this.calendrierData = duplicate(calendrierData); this.calendrierData = duplicate(calendrierData);
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
let calendrierData = this.calendrierData;
$(function () {
console.log(calendrierData);
$("#nomMois").val(calendrierData.moisKey);
$("#nomHeure").val(calendrierData.heureKey);
$("#jourMois").val(calendrierData.jourMois);
$("#minutesRelative").val(calendrierData.minutesRelative);
});
}
} }

View File

@@ -8,23 +8,24 @@ import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { HIDE_DICE, SHOW_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { DialogChronologie } from "./dialog-chronologie.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/' const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"]; const heuresList = ["vaisseau", "sirene", "faucon", "couronne", "dragon", "epees", "lyre", "serpent", "poissonacrobate", "araignee", "roseau", "chateaudormant"];
const heuresDef = { const heuresDef = {
"vaisseau": { label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' }, "vaisseau": {key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "printemps", heure: 0, icon: 'hd01.svg' },
"sirene": { label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' }, "sirene": { key: "sirene", label: "Sirène", lettreFont: 'i', saison: "printemps", heure: 1, icon: 'hd02.svg' },
"faucon": { label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' }, "faucon": { key: "faucon", label: "Faucon", lettreFont: 'f', saison: "printemps", heure: 2, icon: 'hd03.svg' },
"couronne": { label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' }, "couronne": { key: "couronne", label: "Couronne", lettreFont: '', saison: "ete", heure: 3, icon: 'hd04.svg' },
"dragon": { label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' }, "dragon": { key: "dragon", label: "Dragon", lettreFont: 'd', saison: "ete", heure: 4, icon: 'hd05.svg' },
"epees": { label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' }, "epees": { key: "epees", label: "Epées", lettreFont: 'e', saison: "ete", heure: 5, icon: 'hd06.svg' },
"lyre": { label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' }, "lyre": { key: "lyre", label: "Lyre", lettreFont: 'l', saison: "automne", heure: 6, icon: 'hd07.svg' },
"serpent": { label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' }, "serpent": { key: "serpent", label: "Serpent", lettreFont: 's', saison: "automne", heure: 7, icon: 'hd08.svg' },
"poissonacrobate": { label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' }, "poissonacrobate": { key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "automne", heure: 8, icon: 'hd09.svg' },
"araignee": { label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' }, "araignee": { key: "araignee", label: "Araignée", lettreFont: 'a', saison: "hiver", heure: 9, icon: 'hd10.svg' },
"roseau": { label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' }, "roseau": { key: "roseau", label: "Roseau", lettreFont: 'r', saison: "hiver", heure: 10, icon: 'hd11.svg' },
"chateaudormant": { label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' } "chateaudormant": { key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "hiver", heure: 11, icon: 'hd12.svg' }
}; };
const saisonsDef = { const saisonsDef = {
"printemps": { label: "Printemps" }, "printemps": { label: "Printemps" },
@@ -42,6 +43,14 @@ const MAX_NOMBRE_ASTRAL = 12;
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDCalendrier extends Application { export class RdDCalendrier extends Application {
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html",
popOut: false,
resizable: false
});
}
static createCalendrierPos() { static createCalendrierPos() {
return { top: 200, left: 200 }; return { top: 200, left: 200 };
} }
@@ -51,21 +60,50 @@ export class RdDCalendrier extends Application {
return Object.values(heuresDef).find(h => h.heure == chiffre); return Object.values(heuresDef).find(h => h.heure == chiffre);
} }
static getSigneAs(key, value) {
const heure = (typeof value == 'string' || typeof value == 'number') && Number.isInteger(Number(value))
? Number(value)
: (typeof value == 'string') ? RdDCalendrier.getChiffreFromSigne(value)
: undefined
if (heure != undefined && ['key', 'label', 'lettreFont', 'saison', 'heure', 'icon'].includes(key)) {
return RdDCalendrier.getDefSigne(heure)[key]
}
if (heure != undefined && ['webp'].includes(key)) {
return RdDCalendrier.getDefSigne(heure)['icon'].replace('svg', 'webp');
}
console.error(`Appel à getSigneAs('${key}', ${value}) avec une clé/heure incorrects`);
return value;
}
static getChiffreFromSigne(signe) { static getChiffreFromSigne(signe) {
return heuresList.indexOf(signe); return heuresList.indexOf(signe);
} }
static getCalendrier(index) { static createCalendrierInitial() {
let calendrier = { return {
heureRdD: 0,
minutesRelative: 0,
indexJour: 0,
annee: 0,
moisRdD: 0,
moisLabel: heuresDef["vaisseau"].label,
jour: 0
}
}
getCalendrier(index) {
index = index ?? this.getCurrentDayIndex();
const mois = Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN;
return {
heureRdD: 0, // Index dans heuresList / heuresDef[x].heure heureRdD: 0, // Index dans heuresList / heuresDef[x].heure
minutesRelative: 0, minutesRelative: 0,
indexJour: index, indexJour: index,
annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)), annee: Math.floor(index / (RDD_JOUR_PAR_MOIS * RDD_MOIS_PAR_AN)),
moisRdD: Math.floor(index / RDD_JOUR_PAR_MOIS) % RDD_MOIS_PAR_AN, moisRdD: RdDCalendrier.getDefSigne(mois).heure,
moisLabel: RdDCalendrier.getDefSigne(mois).label,
jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage jour: (index % RDD_JOUR_PAR_MOIS) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage
} }
calendrier.moisLabel = RdDCalendrier.getDefSigne(calendrier.moisRdD).label;
return calendrier;
} }
constructor() { constructor() {
@@ -78,7 +116,7 @@ export class RdDCalendrier extends Application {
} }
// Calendrier // Calendrier
this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.getCalendrier(0)); this.calendrier = duplicate(game.settings.get(SYSTEM_RDD, "calendrier") ?? RdDCalendrier.createCalendrierInitial());
this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN); this.calendrier.annee = this.calendrier.annee ?? Math.floor((this.calendrier.moisRdD ?? 0) / RDD_MOIS_PAR_AN);
this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN; this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % RDD_MOIS_PAR_AN;
@@ -86,34 +124,117 @@ export class RdDCalendrier extends Application {
game.settings.set(SYSTEM_RDD, "calendrier", this.calendrier); game.settings.set(SYSTEM_RDD, "calendrier", this.calendrier);
this.listeNombreAstral = this.getListeNombreAstral(); this.listeNombreAstral = this.getListeNombreAstral();
this.rebuildListeNombreAstral(false); // Ensure always up-to-date this.rebuildListeNombreAstral(HIDE_DICE); // Ensure always up-to-date
} }
console.log(this.calendrier, this.calendrierPos, this.listeNombreAstral); console.log('RdDCalendrier.constructor()', this.calendrier, this.calendrierPos, this.listeNombreAstral);
} }
/* -------------------------------------------- */
/** @override */
async activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.updateDisplay();
this.html.find('.ajout-chronologie').click(ev => DialogChronologie.create());
this.html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
this.html.find('.calendar-btn-edit').click(ev => {
ev.preventDefault();
this.showCalendarEditor();
});
this.html.find('.astrologie-btn-edit').click(ev => {
ev.preventDefault();
this.showAstrologieEditor();
});
this.html.find('#calendar-move-handle').mousedown(ev => {
ev.preventDefault();
ev = ev || window.event;
let isRightMB = false;
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
isRightMB = ev.which == 3;
} else if ("button" in ev) { // IE, Opera
isRightMB = ev.button == 2;
}
if (!isRightMB) {
dragElement(document.getElementById("calendar-time-container"));
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
function dragElement(elmnt) {
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.bottom = undefined
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
elmnt.onmousedown = undefined;
document.onmouseup = undefined;
document.onmousemove = undefined;
let xPos = (elmnt.offsetLeft - pos1) > window.innerWidth ? window.innerWidth - 200 : (elmnt.offsetLeft - pos1);
let yPos = (elmnt.offsetTop - pos2) > window.innerHeight - 20 ? window.innerHeight - 100 : (elmnt.offsetTop - pos2)
xPos = xPos < 0 ? 0 : xPos;
yPos = yPos < 0 ? 0 : yPos;
if (xPos != (elmnt.offsetLeft - pos1) || yPos != (elmnt.offsetTop - pos2)) {
elmnt.style.top = (yPos) + "px";
elmnt.style.left = (xPos) + "px";
}
game.system.rdd.calendrier.calendrierPos.top = yPos;
game.system.rdd.calendrier.calendrierPos.left = xPos;
if (game.user.isGM) {
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
}
}
}
} else if (isRightMB) {
game.system.rdd.calendrier.calendrierPos.top = 200;
game.system.rdd.calendrier.calendrierPos.left = 200;
if (game.user.isGM) {
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
}
this.setPos(game.system.rdd.calendrier.calendrierPos);
}
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getListeNombreAstral() { getListeNombreAstral() {
return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? []; return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? [];
} }
/* -------------------------------------------- */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html",
popOut: false,
resizable: false
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getDateFromIndex(index) { getDateFromIndex(index) {
const date = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex()); const dateRdD = this.getCalendrier(index);
return (date.jour + 1) + ' ' + RdDCalendrier.getDefSigne(date.moisRdD).label; return (dateRdD.jour + 1) + ' ' + dateRdD.moisLabel;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
getNumericDateFromIndex(index = undefined) { getDayMonthFromIndex(index = undefined) {
const dateRdD = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex()); const dateRdD = this.getCalendrier(index);
return { return {
day: dateRdD.jour + 1, day: dateRdD.jour + 1,
month: heuresList[dateRdD.moisRdD] month: heuresList[dateRdD.moisRdD]
@@ -180,14 +301,14 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
getNombreAstral(indexDate) { getNombreAstral(indexDate) {
let astralData = this.getListeNombreAstral().find((nombreAstral, i) => nombreAstral.index == indexDate); const listNombreAstral = this.getListeNombreAstral();
let astralData = listNombreAstral.find((nombreAstral, i) => nombreAstral.index == indexDate);
return astralData?.nombreAstral; return astralData?.nombreAstral;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rebuildListeNombreAstral(showDice = SHOW_DICE) { async rebuildListeNombreAstral(showDice = HIDE_DICE) {
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
console.log("rebuildListeNombreAstral", showDice);
let jourCourant = this.getCurrentDayIndex(); let jourCourant = this.getCurrentDayIndex();
let newList = []; let newList = [];
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) { for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
@@ -199,9 +320,8 @@ export class RdDCalendrier extends Application {
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice); newList[i] = await this.ajouterNombreAstral(dayIndex, showDice);
} }
} }
//console.log("SAVE list", newList, jourCourant); game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
this.listeNombreAstral = newList; this.listeNombreAstral = newList;
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.listeNombreAstral);
} }
} }
@@ -264,7 +384,7 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
async incrementerJour() { async incrementerJour() {
const index = this.getCurrentDayIndex() + 1; const index = this.getCurrentDayIndex() + 1;
this.calendrier = RdDCalendrier.getCalendrier(index); this.calendrier = this.getCalendrier(index);
await this.rebuildListeNombreAstral(); await this.rebuildListeNombreAstral();
} }
@@ -286,18 +406,15 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */ /* -------------------------------------------- */
fillCalendrierData(formData = {}) { fillCalendrierData(formData = {}) {
console.log(this.calendrier); const mois = RdDCalendrier.getDefSigne(this.calendrier.moisRdD);
let moisKey = heuresList[this.calendrier.moisRdD]; const heure = RdDCalendrier.getDefSigne(this.calendrier.heureRdD);
let heureKey = heuresList[this.calendrier.heureRdD]; console.log('fillCalendrierData', this.calendrier, mois, heure);
console.log(moisKey, heureKey);
const mois = heuresDef[moisKey]; formData.heureKey = heure.key;
const heure = heuresDef[heureKey]; formData.moisKey = mois.key;
formData.heureKey = heureKey;
formData.moisKey = moisKey;
formData.jourMois = this.calendrier.jour + 1; formData.jourMois = this.calendrier.jour + 1;
formData.nomMois = mois.label; // heures et mois nommés identiques formData.nomMois = mois.label; // heures et mois nommés identiques
formData.annee = this.calendrier.annee;
formData.iconMois = dossierIconesHeures + mois.icon; formData.iconMois = dossierIconesHeures + mois.icon;
formData.nomHeure = heure.label; formData.nomHeure = heure.label;
formData.iconHeure = dossierIconesHeures + heure.icon; formData.iconHeure = dossierIconesHeures + heure.icon;
@@ -428,7 +545,7 @@ export class RdDCalendrier extends Application {
function check() { function check() {
let elmnt = document.getElementById("calendar-time-container"); let elmnt = document.getElementById("calendar-time-container");
if (elmnt) { if (elmnt) {
elmnt.style.bottom = null; elmnt.style.bottom = undefined;
let xPos = (pos.left) > window.innerWidth ? window.innerWidth - 200 : pos.left; let xPos = (pos.left) > window.innerWidth ? window.innerWidth - 200 : pos.left;
let yPos = (pos.top) > window.innerHeight - 20 ? window.innerHeight - 100 : pos.top; let yPos = (pos.top) > window.innerHeight - 20 ? window.innerHeight - 100 : pos.top;
elmnt.style.top = (yPos) + "px"; elmnt.style.top = (yPos) + "px";
@@ -446,7 +563,7 @@ export class RdDCalendrier extends Application {
updateDisplay() { updateDisplay() {
let calendrier = this.fillCalendrierData(); let calendrier = this.fillCalendrierData();
// Rebuild text du calendrier // Rebuild text du calendrier
let dateHTML = `Jour ${calendrier.jourMois} de ${calendrier.nomMois} (${calendrier.nomSaison})` let dateHTML = `${calendrier.jourMois} ${calendrier.nomMois} ${calendrier.annee} (${calendrier.nomSaison})`
if (game.user.isGM) { if (game.user.isGM) {
dateHTML = dateHTML + " - NA: " + (this.getCurrentNombreAstral() ?? "indéterminé"); dateHTML = dateHTML + " - NA: " + (this.getCurrentNombreAstral() ?? "indéterminé");
} }
@@ -469,6 +586,7 @@ export class RdDCalendrier extends Application {
this.calendrier.minutesRelative = Number(calendrierData.minutesRelative); this.calendrier.minutesRelative = Number(calendrierData.minutesRelative);
this.calendrier.jour = Number(calendrierData.jourMois) - 1; this.calendrier.jour = Number(calendrierData.jourMois) - 1;
this.calendrier.moisRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.moisKey); this.calendrier.moisRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.moisKey);
this.calendrier.annee = Number(calendrierData.annee);
this.calendrier.heureRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.heureKey); this.calendrier.heureRdD = RdDCalendrier.getChiffreFromSigne(calendrierData.heureKey);
game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier)); game.settings.set(SYSTEM_RDD, "calendrier", duplicate(this.calendrier));
@@ -528,95 +646,4 @@ export class RdDCalendrier extends Application {
astrologieEditeur.updateData(calendrierData); astrologieEditeur.updateData(calendrierData);
astrologieEditeur.render(true); astrologieEditeur.render(true);
} }
/* -------------------------------------------- */
/** @override */
async activateListeners(html) {
super.activateListeners(html);
this.updateDisplay();
html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));
html.find('.calendar-btn-edit').click(ev => {
ev.preventDefault();
this.showCalendarEditor();
});
html.find('.astrologie-btn-edit').click(ev => {
ev.preventDefault();
this.showAstrologieEditor();
});
html.find('#calendar-move-handle').mousedown(ev => {
ev.preventDefault();
ev = ev || window.event;
let isRightMB = false;
if ("which" in ev) { // Gecko (Firefox), WebKit (Safari/Chrome) & Opera
isRightMB = ev.which == 3;
} else if ("button" in ev) { // IE, Opera
isRightMB = ev.button == 2;
}
if (!isRightMB) {
dragElement(document.getElementById("calendar-time-container"));
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
function dragElement(elmnt) {
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.bottom = null
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
elmnt.onmousedown = null;
document.onmouseup = null;
document.onmousemove = null;
let xPos = (elmnt.offsetLeft - pos1) > window.innerWidth ? window.innerWidth - 200 : (elmnt.offsetLeft - pos1);
let yPos = (elmnt.offsetTop - pos2) > window.innerHeight - 20 ? window.innerHeight - 100 : (elmnt.offsetTop - pos2)
xPos = xPos < 0 ? 0 : xPos;
yPos = yPos < 0 ? 0 : yPos;
if (xPos != (elmnt.offsetLeft - pos1) || yPos != (elmnt.offsetTop - pos2)) {
elmnt.style.top = (yPos) + "px";
elmnt.style.left = (xPos) + "px";
}
game.system.rdd.calendrier.calendrierPos.top = yPos;
game.system.rdd.calendrier.calendrierPos.left = xPos;
if (game.user.isGM) {
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
}
}
}
} else if (isRightMB) {
game.system.rdd.calendrier.calendrierPos.top = 200;
game.system.rdd.calendrier.calendrierPos.left = 200;
if (game.user.isGM) {
game.settings.set(SYSTEM_RDD, "calendrier-pos", duplicate(game.system.rdd.calendrier.calendrierPos));
}
this.setPos(game.system.rdd.calendrier.calendrierPos);
}
});
}
} }

View File

@@ -52,6 +52,11 @@ export class RdDCarac {
return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/); return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/);
} }
static isActionPhysique(selectedCarac) {
return !selectedCarac ||
selectedCarac?.label.match(/(Apparence|Force|Agilité|Dextérité|Vue|Ouïe|Odorat-Goût|Empathie|Dérobée|Mêlée|Tir|Lancer)/);
}
static isIgnoreEtatGeneral(rollData) { static isIgnoreEtatGeneral(rollData) {
const selectedCarac = rollData.selectedCarac; const selectedCarac = rollData.selectedCarac;
return !selectedCarac || return !selectedCarac ||

View File

@@ -1,5 +1,6 @@
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js"; import { ENTITE_BLURETTE, ENTITE_INCARNE, ENTITE_NONINCARNE, HIDE_DICE, SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { DialogSelectTarget } from "./dialog-select-target.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDItemArme } from "./item-arme.js"; import { RdDItemArme } from "./item-arme.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
@@ -9,8 +10,9 @@ import { RdDBonus } from "./rdd-bonus.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRoll } from "./rdd-roll.js"; import { RdDRoll } from "./rdd-roll.js";
import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { STATUSES } from "./status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { Targets } from "./targets.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
const premierRoundInit = [ const premierRoundInit = [
@@ -82,7 +84,6 @@ export class RdDCombatManager extends Combat {
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions); console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
ids = typeof ids === "string" ? [ids] : ids; ids = typeof ids === "string" ? [ids] : ids;
const currentId = this.combatant._id;
// calculate initiative // calculate initiative
for (let cId = 0; cId < ids.length; cId++) { for (let cId = 0; cId < ids.length; cId++) {
const combatant = this.combatants.get(ids[cId]); const combatant = this.combatants.get(ids[cId]);
@@ -101,14 +102,14 @@ export class RdDCombatManager extends Combat {
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value; const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
const niveau = competence.system.niveau; const niveau = competence.system.niveau;
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0; const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille); rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
} }
} }
} }
//console.log("Combatat", c); //console.log("Combatat", c);
const roll = combatant.getInitiativeRoll(rollFormula); const roll = combatant.getInitiativeRoll(rollFormula);
if ( !roll.total) { if (!roll.total) {
roll.evaluate( {async: false}); roll.evaluate({ async: false });
} }
if (roll.total <= 0) roll.total = 0.00; if (roll.total <= 0) roll.total = 0.00;
console.log("Compute init for", rollFormula, roll.total, combatant); console.log("Compute init for", rollFormula, roll.total, combatant);
@@ -121,7 +122,7 @@ export class RdDCombatManager extends Combat {
{ {
speaker: { speaker: {
scene: canvas.scene._id, scene: canvas.scene._id,
actor: combatant.actor ? combatant.actor._id : null, actor: combatant.actor?._id,
token: combatant.token._id, token: combatant.token._id,
alias: combatant.token.name, alias: combatant.token.name,
sound: CONFIG.sounds.dice, sound: CONFIG.sounds.dice,
@@ -151,79 +152,101 @@ export class RdDCombatManager extends Combat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main */ /** Retourne une liste triée d'actions d'armes avec le split arme1 main / arme 2 main / lancer */
static listActionsArmes(armes, competences, carac) { static listActionsArmes(armes, competences, carac) {
// Gestion des armes 1/2 mains let actions = [];
let actionsArme = [];
for (const arme of armes) { for (const arme of armes) {
let action = duplicate(arme) if (arme.system.equipe) {
if (action.system.equipe) { const dommages = arme.system.dommages.toString();
let compData = competences.find(c => c.name == action.system.competence) const tableauDommages = dommages.includes("/") ? dommages.split("/") : [dommages, dommages];
if (arme.system.unemain && arme.system.deuxmains && !dommages.includes("/")) {
actionsArme.push(action); ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
action.action = 'attaque'; }
action.system.dommagesReels = Number(action.system.dommages); console.log(">>>>", arme)
action.system.niveau = compData.system.niveau; if ((arme.system.unemain && arme.system.competence) ||
action.system.initiative = RdDCombatManager.calculInitiative(compData.system.niveau, carac[compData.system.defaut_carac].value); (arme.system.competence.toLowerCase().includes("corps à corps"))) {
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence actions.push(RdDCombatManager.$prepareAttaqueArme({
if (action.system.unemain && !action.system.deuxmains) { arme: arme,
action.system.mainInfo = "(1m)"; infoMain: "(1 main)",
} else if (!action.system.unemain && action.system.deuxmains) { dommagesReel: Number(tableauDommages[0]),
action.system.mainInfo = "(2m)"; competence: arme.system.competence,
} else if (action.system.unemain && action.system.deuxmains) { carac: carac,
action.system.mainInfo = "(1m)"; competences: competences
}));
const comp2m = action.system.competence.replace(" 1 main", " 2 mains"); // Replace ! }
const comp = competences.find(c => c.name == comp2m) if (arme.system.deuxmains && arme.system.competence) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
const arme2main = duplicate(action); arme: arme,
arme2main.system.mainInfo = "(2m)"; infoMain: "(2 mains)",
arme2main.system.niveau = comp.system.niveau; dommagesReel: Number(tableauDommages[1]),
arme2main.system.competence = comp2m; competence: arme.system.competence.replace(" 1 main", " 2 mains"),
arme2main.system.initiative = RdDCombatManager.calculInitiative(arme2main.system.niveau, carac[comp.system.defaut_carac].value); carac: carac,
actionsArme.push(arme2main); competences: competences
const containsSlash = action.system.dommages.includes("/"); }));
if (containsSlash) { }
const tableauDegats = action.system.dommages.split("/"); if (arme.system.lancer) {
action.system.dommagesReels = Number(tableauDegats[0]); actions.push(RdDCombatManager.$prepareAttaqueArme({
arme2main.system.dommagesReels = Number(tableauDegats[1]); arme: arme,
} infoMain: "(lancer)",
else{ dommagesReel: Number(tableauDommages[0]),
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + action.name + " ne sont pas corrects (ie sous la forme X/Y)"); competence: arme.system.lancer,
} carac: carac,
competences: competences
}));
}
if (arme.system.tir) {
actions.push(RdDCombatManager.$prepareAttaqueArme({
arme: arme,
infoMain: "(tir)",
dommagesReel: Number(tableauDommages[0]),
competence: arme.system.tir,
carac: carac,
competences: competences
}));
} }
} }
} }
return actionsArme.sort(Misc.ascending(armeData => armeData.name + (armeData.system.mainInfo ?? ''))); return actions.sort(Misc.ascending(action => action.name + (action.system.infoMain ?? '')));
}
static $prepareAttaqueArme(infoAttaque) {
const comp = infoAttaque.competences.find(c => c.name == infoAttaque.competence);
const attaque = duplicate(infoAttaque.arme);
attaque.action = 'attaque';
attaque.system.competence = infoAttaque.competence;
attaque.system.dommagesReels = infoAttaque.dommagesReel;
attaque.system.infoMain = infoAttaque.infoMain;
attaque.system.niveau = comp.system.niveau;
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value);
return attaque;
} }
static listActionsCreature(competences) { static listActionsCreature(competences) {
return competences.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it)) return competences.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
.map(it => RdDItemCompetenceCreature.toActionArme(it)); .map(it => RdDItemCompetenceCreature.armeNaturelle(it));
} }
static listActionsPossessions(actor) { static listActionsPossessions(actor) {
return RdDCombatManager._indexActions(actor.getPossessions().map(p => return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
{ return {
return { name: p.name,
name: p.name, action: 'conjurer',
action: 'conjurer', system: {
system: { competence: p.name,
competence: p.name, possessionid: p.system.possessionid,
possessionid: p.system.possessionid,
}
} }
})); }
}));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static listActionsCombat(combatant) { static listActionsCombat(combatant) {
const actor = combatant.actor; const actor = combatant.actor;
let actions = RdDCombatManager.listActionsPossessions(actor); let actions = RdDCombatManager.listActionsPossessions(actor);
if (actions.length>0) { if (actions.length > 0) {
return actions; return actions;
} }
if (actor.isCreature()) { if (actor.isCreatureEntite()) {
actions = actions.concat(RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature'])); actions = actions.concat(RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']));
} else { } else {
// Recupération des items 'arme' // Recupération des items 'arme'
@@ -334,7 +357,7 @@ export class RdDCombatManager extends Combat {
compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence); compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence);
compNiveau = compData.system.niveau; compNiveau = compData.system.niveau;
initInfo = action.name + " / " + action.system.competence; initInfo = action.name + " / " + action.system.competence;
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') { if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
caracForInit = compData.system.carac_value; caracForInit = compData.system.carac_value;
} else { } else {
@@ -362,7 +385,7 @@ export class RdDCombatManager extends Combat {
switch (arme.system.cac) { switch (arme.system.cac) {
case "empoignade": case "empoignade":
return 3; return 3;
case "pugilat": case "pugilat":
case "naturelle": case "naturelle":
return 4; return 4;
} }
@@ -373,7 +396,7 @@ export class RdDCombatManager extends Combat {
static displayInitiativeMenu(html, combatantId) { static displayInitiativeMenu(html, combatantId) {
console.log("Combatant ; ", combatantId); console.log("Combatant ; ", combatantId);
const combatant = game.combat.combatants.get(combatantId); const combatant = game.combat.combatants.get(combatantId);
if (! (combatant?.actor) ) { if (!(combatant?.actor)) {
ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`) ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
return; return;
} }
@@ -448,49 +471,30 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static createUsingTarget(attacker) { static rddCombatTarget(target, attacker) {
const target = RdDCombat.getTarget() const defender = target?.actor;
if (target == undefined) { const defenderTokenId = target?.id;
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
? "Vous devez choisir <strong>une seule</strong> cible à attaquer!"
: "Vous devez choisir une cible à attaquer!");
}
else {
const defender = target?.actor;
const defenderTokenId = target?.id;
if ( defender.type == 'entite' && defender.system.definition.typeentite == ENTITE_NONINCARNE) {
ui.notifications.warn("Vous ne pouvez pas cibler une entité non incarnée !!!!");
} else {
return this.create(attacker, defender, defenderTokenId, target)
}
}
}
/* -------------------------------------------- */
static getTarget() {
if (game.user.targets && game.user.targets.size == 1) {
for (let target of game.user.targets) {
return target;
}
}
return undefined;
}
/* -------------------------------------------- */
static create(attacker, defender, defenderTokenId, target = undefined) {
return new RdDCombat(attacker, defender, defenderTokenId, target) return new RdDCombat(attacker, defender, defenderTokenId, target)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static createForAttackerAndDefender(attackerId, defenderTokenId) { static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) {
const attacker = game.actors.get(attackerId); const attacker = game.actors.get(attackerId);
if (defenderTokenId) { let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
const defenderToken = canvas.tokens.get(defenderTokenId); let target = undefined
const defender = defenderToken.actor; if (!defenderTokenId || !defender) {
console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`);
return RdDCombat.create(attacker, defender, defenderTokenId); target = Targets.getTarget()
if (!target) {
return;
}
defenderTokenId = target.id;
defender = target.actor;
if (!defenderTokenId || !defender) {
return;
}
} }
return RdDCombat.createUsingTarget(attacker) return new RdDCombat(attacker, defender, defenderTokenId, target)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -498,10 +502,10 @@ export class RdDCombat {
let defender = canvas.tokens.get(msg.defenderTokenId).actor; 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) : null; let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
defender.encaisserDommages(attackerRoll, attacker); defender.encaisserDommages(attackerRoll, attacker);
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme); rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
} }
} }
@@ -510,7 +514,7 @@ export class RdDCombat {
static onMsgDefense(msg) { static onMsgDefense(msg) {
let defenderToken = canvas.tokens.get(msg.defenderTokenId); let defenderToken = canvas.tokens.get(msg.defenderTokenId);
if (defenderToken && Misc.isUniqueConnectedGM()) { if (defenderToken && Misc.isUniqueConnectedGM()) {
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId); const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme); rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll); rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
} }
@@ -537,11 +541,10 @@ export class RdDCombat {
'#echec-total-attaque', '#echec-total-attaque',
]) { ]) {
html.on("click", button, event => { html.on("click", button, event => {
const rddCombat = RdDCombat.createForAttackerAndDefender( const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
event.currentTarget.attributes['data-attackerId']?.value, event.currentTarget.attributes['data-attackerId']?.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);
event.preventDefault(); event.preventDefault();
} }
@@ -568,7 +571,7 @@ export class RdDCombat {
async onEvent(button, event) { async onEvent(button, event) {
const chatMessage = ChatUtility.getChatMessage(event); const chatMessage = ChatUtility.getChatMessage(event);
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll'); const defenderRoll = ChatUtility.getMessageData(chatMessage, '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 defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value;
@@ -688,12 +691,13 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async proposerAjustementTirLancer( rollData ) { async proposerAjustementTirLancer(rollData) {
if (['tir', 'lancer'].includes(rollData.competence.system.categorie)) { if (['tir', 'lancer'].includes(rollData.competence.system.categorie)) {
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: ChatMessage.getWhisperRecipients("GM")
})
} }
else { else {
const defenderToken = canvas.tokens.get(this.defenderTokenId); const defenderToken = canvas.tokens.get(this.defenderTokenId);
@@ -702,7 +706,7 @@ export class RdDCombat {
const portee = this._ajustementPortee(dist, rollData.arme) const portee = this._ajustementPortee(dist, rollData.arme)
const taille = this._ajustementTaille(this.defender) const taille = this._ajustementTaille(this.defender)
const activite = this._ajustementMouvement(this.defender) const activite = this._ajustementMouvement(this.defender)
const total = [portee, taille, activite].map(it=>it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0) const total = [portee, taille, activite].map(it => it.diff).filter(d => !Number.isNaN(d)).reduce(Misc.sum(), 0)
ChatMessage.create({ ChatMessage.create({
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', { content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-info-distance.html', {
rollData: rollData, rollData: rollData,
@@ -724,32 +728,32 @@ export class RdDCombat {
isVisible(token, defenderToken) { isVisible(token, defenderToken) {
return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token }) return canvas.effects.visibility.testVisibility(defenderToken.center, { object: token })
} }
distance(token, defenderToken) { distance(token, defenderToken) {
return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1); return Number(canvas.grid.measureDistances([{ ray: new Ray(token.center, defenderToken.center) }], { gridSpaces: false })).toFixed(1);
} }
_ajustementPortee(dist, arme) { _ajustementPortee(dist, arme) {
if (dist <= arme.system.portee_courte) return {msg:"courte", diff:0}; if (dist <= arme.system.portee_courte) return { msg: "courte", diff: 0 };
if (dist <= arme.system.portee_moyenne) return {msg: "moyenne" , diff: -3}; if (dist <= arme.system.portee_moyenne) return { msg: "moyenne", diff: -3 };
if (dist <= arme.system.portee_extreme) return {msg: "extrême", diff:-5}; if (dist <= arme.system.portee_extreme) return { msg: "extrême", diff: -5 };
return {msg: "inatteignable", diff: -10}; return { msg: "inatteignable", diff: -10 };
} }
_ajustementTaille(actor) { _ajustementTaille(actor) {
if (actor.isVehicule()) return {msg: "véhicule", diff: 0} if (actor.isVehicule()) return { msg: "véhicule", diff: 0 }
const taille = actor.getCaracByName('TAILLE')?.value ?? 1; const taille = actor.getCaracByName('TAILLE')?.value ?? 1;
if (taille <= 1) return {msg: "souris", diff: -8}; if (taille <= 1) return { msg: "souris", diff: -8 };
if (taille <= 3) return {msg: "chat", diff: -4}; if (taille <= 3) return { msg: "chat", diff: -4 };
if (taille <= 5) return {msg: "chien", diff: -2}; if (taille <= 5) return { msg: "chien", diff: -2 };
if (taille <= 15) return {msg: "humanoïde", diff: 0}; if (taille <= 15) return { msg: "humanoïde", diff: 0 };
if (taille <= 20) return {msg: "ogre", diff: 2}; if (taille <= 20) return { msg: "ogre", diff: 2 };
return {msg: "gigantesque", diff: 4}; return { msg: "gigantesque", diff: 4 };
} }
_ajustementMouvement(defender) { _ajustementMouvement(defender) {
if (defender.getSurprise(true)) return {msg: "immobile (surprise)", diff: 0}; if (defender.getSurprise(true)) return { msg: "immobile (surprise)", diff: 0 };
if (game.combat?.combatants.find(it => it.actorId == defender.id)) return {msg: "en mouvement (combat)", diff: -4}; if (game.combat?.combatants.find(it => it.actorId == defender.id)) return { msg: "en mouvement (combat)", diff: -4 };
return {msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3}; return { msg: "à déterminer (0 immobile, -3 actif, -4 en mouvement, -5 en zig-zag)", diff: -3 };
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -763,7 +767,7 @@ export class RdDCombat {
// whisper: ChatMessage.getWhisperRecipients("GM")}) // whisper: ChatMessage.getWhisperRecipients("GM")})
// } // }
if (!await this.accorderEntite('avant-attaque')) { if (!await this.attacker.accorder(this.defender, 'avant-attaque')) {
return; return;
} }
if (arme.system.cac == 'empoignade' && this.attacker.isCombatTouche()) { if (arme.system.cac == 'empoignade' && this.attacker.isCombatTouche()) {
@@ -786,23 +790,21 @@ export class RdDCombat {
await this.proposerAjustementTirLancer(rollData) await this.proposerAjustementTirLancer(rollData)
const dialog = await RdDRoll.create(this.attacker, rollData, const dialog = await RdDRoll.create(this.attacker, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', name: 'jet-attaque',
options: { height: 540 } label: 'Attaque: ' + (arme?.name ?? competence.name),
}, { callbacks: [
name: 'jet-attaque', this.attacker.createCallbackExperience(),
label: 'Attaque: ' + (arme?.name ?? competence.name), this.attacker.createCallbackAppelAuMoral(),
callbacks: [ { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
this.attacker.createCallbackExperience(), { condition: r => arme && !RdDCombat.isParticuliere(r), action: r => this.attacker.incDecItemUse(arme._id) },
this.attacker.createCallbackAppelAuMoral(), { condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) },
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, { condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) },
{ condition: r => arme && !RdDCombat.isParticuliere(r), action: r => this.attacker.incDecItemUse(arme._id) }, { condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) },
{ condition: r => (RdDCombat.isReussite(r) && !RdDCombat.isParticuliere(r)), action: r => this._onAttaqueNormale(r) }, { condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
{ condition: RdDCombat.isParticuliere, action: r => this._onAttaqueParticuliere(r) }, ]
{ condition: RdDCombat.isEchec, action: r => this._onAttaqueEchec(r) }, });
{ condition: RdDCombat.isEchecTotal, action: r => this._onAttaqueEchecTotal(r) },
]
});
dialog.render(true); dialog.render(true);
} }
@@ -815,10 +817,11 @@ export class RdDCombat {
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),
essais: {} essais: {}
}; };
if (this.attacker.isCreature()) { if (this.attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
} }
else if (arme) { else if (arme) {
@@ -836,7 +839,7 @@ export class RdDCombat {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _onAttaqueParticuliere(rollData) { async _onAttaqueParticuliere(rollData) {
const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0; const isMeleeDiffNegative = (rollData.competence.type == 'competencecreature' || rollData.selectedCarac.label == "Mêlée") && rollData.diffLibre < 0;
// force toujours, sauf empoignade // force toujours, sauf empoignade
// finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum // finesse seulement en mélée, pour l'empoignade, ou si la difficulté libre est de -1 minimum
@@ -854,7 +857,7 @@ export class RdDCombat {
else if (!isForce && !isFinesse && isRapide) { else if (!isForce && !isFinesse && isRapide) {
return await this.choixParticuliere(rollData, "rapidite"); return await this.choixParticuliere(rollData, "rapidite");
} }
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.getWhisperRecipientsAndGMs(this.attacker.name),
@@ -883,7 +886,7 @@ export class RdDCombat {
} }
await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html'); await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html');
if (!await this.accorderEntite('avant-defense')) { if (!await this.attacker.accorder(this.defender, 'avant-defense')) {
return; return;
} }
@@ -893,7 +896,7 @@ export class RdDCombat {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
isPossession( attackerRoll) { isPossession(attackerRoll) {
return attackerRoll.selectedCarac.label.toLowerCase() == 'possession'; return attackerRoll.selectedCarac.label.toLowerCase() == 'possession';
} }
@@ -1036,31 +1039,28 @@ export class RdDCombat {
const arme = this.defender.getArmeParade(armeParadeId); const arme = this.defender.getArmeParade(armeParadeId);
console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme); console.log("RdDCombat.parade >>>", attackerRoll, armeParadeId, arme);
const competence = arme?.system?.competence; const competence = arme?.system?.competence;
if (competence == undefined) if (competence == undefined) {
{ console.error("Pas de compétence de parade associée à ", arme?.name, armeParadeId);
console.error("Pas de compétence de parade associée à ", arme?.name, armeParadeId) ;
return; return;
} }
let rollData = this._prepareParade(attackerRoll, arme, competence); let rollData = this._prepareParade(attackerRoll, arme, competence);
const dialog = await RdDRoll.create(this.defender, rollData, const dialog = await RdDRoll.create(this.defender, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', name: 'jet-parade',
options: { height: 540 } label: 'Parade: ' + (arme ? arme.name : rollData.competence.name),
}, { callbacks: [
name: 'jet-parade', this.defender.createCallbackExperience(),
label: 'Parade: ' + (arme ? arme.name : rollData.competence.name), this.defender.createCallbackAppelAuMoral(),
callbacks: [ { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
this.defender.createCallbackExperience(), { condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(armeParadeId) },
this.defender.createCallbackAppelAuMoral(), { condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) },
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, { condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) },
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(armeParadeId) }, { condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) },
{ condition: RdDCombat.isReussite, action: r => this._onParadeNormale(r) }, ]
{ condition: RdDCombat.isParticuliere, action: r => this._onParadeParticuliere(r) }, });
{ condition: RdDCombat.isEchec, action: r => this._onParadeEchec(r) },
]
});
dialog.render(true); dialog.render(true);
} }
@@ -1079,7 +1079,7 @@ export class RdDCombat {
show: {} show: {}
}; };
if (this.defender.isCreature()) { if (this.defender.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(defenderRoll); RdDItemCompetenceCreature.setRollDataCreature(defenderRoll);
} }
@@ -1128,19 +1128,20 @@ export class RdDCombat {
let rollData = this._prepareEsquive(attackerRoll, esquive); let rollData = this._prepareEsquive(attackerRoll, esquive);
const dialog = await RdDRoll.create(this.defender, rollData, const dialog = await RdDRoll.create(this.defender, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' }, { { html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
name: 'jet-esquive', {
label: 'Esquiver', name: 'jet-esquive',
callbacks: [ label: 'Esquiver',
this.defender.createCallbackExperience(), callbacks: [
this.defender.createCallbackAppelAuMoral(), this.defender.createCallbackExperience(),
{ condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(esquive._id) }, this.defender.createCallbackAppelAuMoral(),
{ action: r => this.removeChatMessageActionsPasseArme(r.passeArme) }, { condition: r => !RdDCombat.isParticuliere(r), action: r => this.defender.incDecItemUse(esquive._id) },
{ condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) }, { action: r => this.removeChatMessageActionsPasseArme(r.passeArme) },
{ condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) }, { condition: RdDCombat.isReussite, action: r => this._onEsquiveNormale(r) },
{ condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) }, { condition: RdDCombat.isParticuliere, action: r => this._onEsquiveParticuliere(r) },
] { condition: RdDCombat.isEchec, action: r => this._onEsquiveEchec(r) },
}); ]
});
dialog.render(true); dialog.render(true);
} }
@@ -1157,7 +1158,7 @@ export class RdDCombat {
show: {} show: {}
}; };
if (this.defender.isCreature()) { if (this.defender.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData); RdDItemCompetenceCreature.setRollDataCreature(rollData);
} }
return rollData; return rollData;
@@ -1318,35 +1319,6 @@ export class RdDCombat {
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme); this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
} }
/* -------------------------------------------- */
/* retourne true si on peut continuer, false si on ne peut pas continuer */
async accorderEntite(when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| this.defender == undefined
|| !this.defender.isEntite([ENTITE_INCARNE])
|| this.defender.isEntiteAccordee(this.attacker)) {
return true;
}
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(this.defender.system.carac.niveau.value));
let message = {
content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>",
whisper: ChatMessage.getWhisperRecipients(this.attacker.name)
};
if (rolled.isSuccess) {
await this.defender.setEntiteReveAccordee(this.attacker);
message.content += this.attacker.name + " s'est accordé avec " + this.defender.name;
}
else {
message.content += this.attacker.name + " n'est pas accordé avec " + this.defender.name;
}
ChatMessage.create(message);
return rolled.isSuccess;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async displayActorCombatStatus(combat, actor) { static async displayActorCombatStatus(combat, actor) {
let formData = { let formData = {

View File

@@ -1,8 +1,8 @@
/* -------------------------------------------- */ /* -------------------------------------------- */
import { DialogChronologie } from "./dialog-chronologie.js";
import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js"; import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
import { DialogStress } from "./dialog-stress.js"; import { DialogStress } from "./dialog-stress.js";
import { Grammar } from "./grammar.js";
import { RdDItemCompetence } from "./item-competence.js"; import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
@@ -13,7 +13,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js"; import { RdDRollResolutionTable } from "./rdd-roll-resolution-table.js";
import { RdDRollTables } from "./rdd-rolltables.js"; import { RdDRollTables } from "./rdd-rolltables.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { TMRRencontres } from "./tmr-rencontres.js"; import { CompendiumTableHelpers } from "./settings/system-compendiums.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/; const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
@@ -22,55 +22,100 @@ const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
export class RdDCommands { export class RdDCommands {
static init() { static init() {
if (!game.system.rdd.commands) { const rddCommands = new RdDCommands();
const rddCommands = new RdDCommands();
rddCommands.registerCommand({ path: ["/aide"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
rddCommands.registerCommand({ path: ["/help"], func: (content, msg, params) => rddCommands.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
rddCommands.registerCommand({ path: ["/table", "queues"], func: (content, msg, params) => RdDRollTables.getQueue(true), descr: "Tire une Queue de Dragon" });
rddCommands.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe(true), descr: "Tire une Idée fixe" });
rddCommands.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant(true), descr: "Tire un Désir Lancinant" });
rddCommands.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre(true), descr: "Tire une Ombre de Dragon" });
rddCommands.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR(true), descr: "Tire une Tête de Dragon pour Hauts Revants" });
rddCommands.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete(true), descr: "Tire une Tête de Dragon" });
rddCommands.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle(true), descr: " Tire un Souffle de Dragon" });
rddCommands.registerCommand({ path: ["/table", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence(true), descr: "Tire une compétence au hasard" });
rddCommands.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot(true), descr: "Tire une carte du Tarot Draconique" });
rddCommands.registerCommand({ path: ["/meteo"], func: (content, msg, params) => rddCommands.getMeteo(msg, params), descr: "Propose une météo marine" });
rddCommands.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" });
rddCommands.registerCommand({ Hooks.on("chatMessage", (html, content, msg) => {
path: ["/tmra"], func: (content, msg, params) => rddCommands.getTMRAleatoire(msg, params), if (content[0] == '/') {
descr: `Tire une case aléatoire des Terres médianes let regExp = /(\S+)/g;
let commands = content.match(regExp);
if (rddCommands.processChatCommand(commands, content, msg)) {
return false;
}
}
return true;
});
game.system.rdd.commands = rddCommands;
}
constructor() {
this.commandsTable = undefined;
}
_registerCommands() {
this.commandsTable = {}
this.registerCommand({ path: ["/aide"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
this.registerCommand({ path: ["/help"], func: (content, msg, params) => this.help(msg), descr: "Affiche l'aide pour toutes les commandes" });
this.registerCommand({ path: ["/liste", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('liste'), descr: "Affiche la liste des compétences" });
this.registerCommand({ path: ["/table", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('liste'), descr: "Affiche la table des Queues de Dragon" });
this.registerCommand({ path: ["/table", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('liste'), descr: "Affiche la table des Ombres de Thanatos" });
this.registerCommand({ path: ["/table", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('liste'), descr: "Affiche la table des Têtes de Dragon pour Hauts Revants" });
this.registerCommand({ path: ["/table", "tete"], func: (content, msg, params) => RdDRollTables.getTete('liste'), descr: "Affiche la table des Tête de Dragon pour tous" });
this.registerCommand({ path: ["/table", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('liste'), descr: "Affiche la table des Souffles de Dragon" });
this.registerCommand({ path: ["/table", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('liste'), descr: "Affiche la table les cartes du Tarot Draconique" });
this.registerCommand({ path: ["/table", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('liste'), descr: "Affiche la table des Idées fixes" });
this.registerCommand({ path: ["/table", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('liste'), descr: "Affiche la table des Désirs Lancinants" });
this.registerCommand({
path: ["/table", "rencontre"], func: (content, msg, params) => this.tableRencontres(msg, params),
descr: `Affiche la table des Rencontres
<br><strong>/table rencontre deso</strong> affiche la table des rencontres en Désolation
<br><strong>/table rencontre mauvaise</strong> affiche la table des mauvaises rencontres`
});
this.registerCommand({ path: ["/table", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'liste'), descr: "Affiche la table des ressource naturelles pour un milieu donné" });
this.registerCommand({ path: ["/tirer", "comp"], func: (content, msg, params) => RdDRollTables.getCompetence('chat'), descr: "Tire une compétence au hasard" });
this.registerCommand({ path: ["/tirer", "queue"], func: (content, msg, params) => RdDRollTables.getQueue('chat'), descr: "Tire une Queue de Dragon" });
this.registerCommand({ path: ["/tirer", "ombre"], func: (content, msg, params) => RdDRollTables.getOmbre('chat'), descr: "Tire une Ombre de Thanatos" });
this.registerCommand({ path: ["/tirer", "tetehr"], func: (content, msg, params) => RdDRollTables.getTeteHR('chat'), descr: "Tire une Tête de Dragon pour Hauts Revants" });
this.registerCommand({ path: ["/tirer", "tete"], func: (content, msg, params) => RdDRollTables.getTete('chat'), descr: "Tire une Tête de Dragon" });
this.registerCommand({ path: ["/tirer", "souffle"], func: (content, msg, params) => RdDRollTables.getSouffle('chat'), descr: "Tire un Souffle de Dragon" });
this.registerCommand({ path: ["/tirer", "tarot"], func: (content, msg, params) => RdDRollTables.getTarot('chat'), descr: "Tire une carte du Tarot Draconique" });
this.registerCommand({ path: ["/tirer", "ideefixe"], func: (content, msg, params) => RdDRollTables.getIdeeFixe('chat'), descr: "Tire une Idée fixe" });
this.registerCommand({ path: ["/tirer", "desir"], func: (content, msg, params) => RdDRollTables.getDesirLancinant('chat'), descr: "Tire un Désir Lancinant" });
this.registerCommand({ path: ["/tirer", "rencontre"], func: (content, msg, params) => this.getRencontreTMR(params), descr: `Détermine une rencontre dans les TMR (synonyme de "/tmrr")` });
this.registerCommand({ path: ["/tirer", "milieu"], func: (content, msg, params) => this.tableMilieu(msg, params, 'chat'), descr: "Effectue un tirage dans la table desressource naturelles pour un milieu donné" });
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: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params),
descr: `Cherche où se trouve une case des Terres médianes
<br><strong>/tmr sord</strong> indique que la cité Sordide est en D13
<br><strong>/tmr foret</strong> donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)`
});
this.registerCommand({
path: ["/tmra"], func: (content, msg, params) => this.getTMRAleatoire(msg, params),
descr: `Tire une case aléatoire des Terres médianes
<br><strong>/tmra forêt</strong> détermine une 'forêt' aléatoire <br><strong>/tmra forêt</strong> détermine une 'forêt' aléatoire
<br><strong>/tmra</strong> détermine une case aléatoire dans toutes les TMR` }); <br><strong>/tmra</strong> détermine une case aléatoire dans toutes les TMR`
rddCommands.registerCommand({ });
path: ["/tmr"], func: (content, msg, params) => rddCommands.findTMR(msg, params), this.registerCommand({
descr: `Cherche où se trouve une case des Terres médianes path: ["/tmrr"], func: (content, msg, params) => this.getRencontreTMR(params),
<br><strong>/tmr? sordide</strong> indique que la cité Sordide est en D13 descr: `Détermine une rencontre dans les TMR
<br><strong>/tmr? foret</strong> donne la liste des TMR dont le nom contient "foret" (donc, toutes les forêts)` }); <br><strong>/tmrr forêt</strong> détermine une rencontre aléatoire en 'forêt'
rddCommands.registerCommand({ <br><strong>/tmrr mauvaise</strong> détermine une mauvaise rencontre aléatoire
path: ["/tmrr"], func: (content, msg, params) => rddCommands.getRencontreTMR(params), <br><strong>/tmrr for 47</strong> détermine la rencontre en 'forêt' pour un jet de dé de 47`
descr: `Détermine une rencontre dans un type de case });
<br><strong>/tmrr foret</strong> lance un d100 et détermine la rencontre correspondante en 'forêt'
<br><strong>/tmrr forêt 47</strong> détermine la rencontre en 'forêt' pour un jet de dé de 47`
});
rddCommands.registerCommand({ this.registerCommand({
path: ["/xp", "comp"], func: (content, msg, params) => rddCommands.getCoutXpComp(msg, params), path: ["/xp", "comp"], func: (content, msg, params) => this.getCoutXpComp(msg, params),
descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples: descr: `Détermine le coût d'expérience pour augmenter une compétence. Exemples:
<br>/xp comp -6 1: pour passer de -6 à +1 <br>/xp comp -6 1: pour passer de -6 à +1
<br>/xp comp +4: pour atteindre le niveau 4 (depuis +3)` <br>/xp comp +4: pour atteindre le niveau 4 (depuis +3)`
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/xp", "carac"], func: (content, msg, params) => rddCommands.getCoutXpCarac(msg, params), path: ["/xp", "carac"], func: (content, msg, params) => this.getCoutXpCarac(msg, params),
descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples: descr: `Détermine le coût d'expérience pour augmenter une caractéristique. Exemples:
<br>/xp carac 15: coût pour atteindre 15 (depuis 14)` <br>/xp carac 15: coût pour atteindre 15 (depuis 14)`
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/rdd"], func: (content, msg, params) => rddCommands.rollRdd(msg, params), path: ["/rdd"], func: (content, msg, params) => this.rollRdd(msg, params),
descr: `Effectue un jet de dés dans la table de résolution. Exemples: descr: `Effectue un jet de dés dans la table de résolution. Exemples:
<br><strong>/rdd</strong> ouvre la table de résolution <br><strong>/rdd</strong> ouvre la table de résolution
<br><strong>/rdd 10 3</strong> effectue un jet 10 à +3 <br><strong>/rdd 10 3</strong> effectue un jet 10 à +3
<br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2 <br><strong>/rdd 15 -2</strong> effectue un jet 15 à -2
@@ -78,47 +123,46 @@ export class RdDCommands {
<br><strong>/rdd Vue Vigilance -2</strong> effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés <br><strong>/rdd Vue Vigilance -2</strong> effectue un jet de Vue/Vigilance à -2 pour les tokens sélectionnés
<br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés <br><strong>/rdd vol déser +2</strong> effectue un jet de Volonté/Survie en désert à +2 pour les tokens sélectionnés
` `
}); });
rddCommands.registerCommand({ path: ["/ddr"], func: (content, msg, params) => rddCommands.rollDeDraconique(msg), descr: "Lance un Dé Draconique" }); this.registerCommand({ path: ["/ddr"], func: (content, msg, params) => this.rollDeDraconique(msg), descr: "Lance un Dé Draconique" });
rddCommands.registerCommand({ this.registerCommand({
path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]), path: ["/payer"], func: (content, msg, params) => RdDUtility.afficherDemandePayer(params[0], params[1]),
descr: `Permet de payer un montant. Exemples: descr: `Demande aux joueurs de payer un montant. Exemples:
<br><strong>/payer 5s 10d</strong> permet d'envoyer un message pour payer 5 sols et 10 deniers <br><strong>/payer 5s 10d</strong> permet d'envoyer un message pour payer 5 sols et 10 deniers
<br><strong>/payer 10d</strong> permet d'envoyer un message pour payer 10 deniers` <br><strong>/payer 10d</strong> permet d'envoyer un message pour payer 10 deniers`
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')), path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(Misc.join(params, ' ')),
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre: descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
<br><strong>/astro 7</strong> <br><strong>/astro 7</strong>
<br><strong>/astro Lyre</strong> <br><strong>/astro Lyre</strong>
<br><strong>/astro Lyr</strong>` <br><strong>/astro Lyr</strong>`
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(), path: ["/signe", "+"], func: (content, msg, params) => this.creerSignesDraconiques(),
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis." descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(), path: ["/signe", "-"], func: (content, msg, params) => this.supprimerSignesDraconiquesEphemeres(),
descr: "Supprime les signes draconiques éphémères" descr: "Supprime les signes draconiques éphémères"
}); });
rddCommands.registerCommand({ this.registerCommand({
path: ["/stress"], func: (content, msg, params) => rddCommands.distribuerStress(params), path: ["/stress"], func: (content, msg, params) => this.distribuerStress(params),
descr: `Distribue du stress aux personnages. Exemples: descr: `Distribue du stress aux personnages. Exemples:
<br><strong>/stress</strong> : Ouvre une fenêtre pour donner du stress ou de l'expérience à un ensemble de personnages <br><strong>/stress</strong> : Ouvre une fenêtre pour donner du stress ou de l'expérience à un ensemble de personnages
<br><strong>/stress 6</strong> : Distribue 6 points des Stress à tout les personnages joueurs, sans raison renseignée <br><strong>/stress 6</strong> : Distribue 6 points des Stress à tout les personnages joueurs, sans raison renseignée
<br><strong>/stress 6 Tigre</strong> : Distribue 6 points des Stress à tout les personnages joueurs, à cause d'un Tigre (Vert) <br><strong>/stress 6 Tigre</strong> : Distribue 6 points des Stress à tout les personnages joueurs, à cause d'un Tigre (Vert)
<br><strong>/stress 6 Glou Paulo</strong> : Distribue 6 points de Stress au personnage Paulon ou au personnage joueur Paulo, à cause d'un Glou` <br><strong>/stress 6 Glou Paulo</strong> : Distribue 6 points de Stress au personnage Paulon ou au personnage joueur Paulo, à cause d'un Glou`
}); });
game.system.rdd.commands = rddCommands; this.registerCommand({
} path: ["/chrono"], func: (content, msg, params) => DialogChronologie.create(),
} descr: `Enregistre une entrée de chronologie dans un article de journal`
constructor() { });
this.commandsTable = {};
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -160,37 +204,50 @@ export class RdDCommands {
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"); let rollMode = game.settings.get("core", "rollMode");
if (["gmroll", "blindroll"].includes(rollMode)) msg["whisper"] = ChatMessage.getWhisperRecipients("GM"); if (["gmroll", "blindroll"].includes(rollMode)) {
if (rollMode === "blindroll") msg["blind"] = true; msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
}
if (rollMode === "blindroll"){
msg["blind"] = true;
}
msg["type"] = 0; msg["type"] = 0;
if (!this.commandsTable) {
this._registerCommands();
}
let command = commandLine[0].toLowerCase(); let command = commandLine[0].toLowerCase();
let params = commandLine.slice(1); if (this._isCommandHandled(command)) {
let params = commandLine.slice(1);
return this.process(command, params, content, msg); this._processCommand(this.commandsTable, command, params, content, msg);
return true;
}
return false;
} }
process(command, params, content, msg) { _isCommandHandled(command){
return this._processCommand(this.commandsTable, command, params, content, msg); return this.commandsTable[command] != undefined;
} }
_processCommand(commandsTable, name, params, content = '', msg = {}, path = "") { async _processCommand(commandsTable, name, params, content = '', msg = {}, path = "") {
let command = commandsTable[name]; let command = commandsTable[name];
path = path + name + " "; path = path + name + " ";
if (command && command.subTable) { if (command && command.subTable) {
if (params[0]) { if (params[0]) {
return this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path) this._processCommand(command.subTable, params[0], params.slice(1), content, msg, path)
} }
else { else {
this.help(msg, command.subTable); this.help(msg, command.subTable);
return true;
} }
return true;
} }
if (command && command.func) { if (command && command.func) {
const result = command.func(content, msg, params); new Promise(async () => {
if (result == false) { const result = await command.func(content, msg, params);
RdDCommands._chatAnswer(msg, command.descr); if (result == false) {
} RdDCommands._chatAnswer(msg, command.descr);
}
});
return true; return true;
} }
return false; return false;
@@ -201,10 +258,10 @@ export class RdDCommands {
this.help(msg, undefined); this.help(msg, undefined);
} }
async help(msg, table) { async help(msg, table) {
let list = [] let commands = []
this._buildSubTableHelp(list, table || this.commandsTable); this._buildSubTableHelp(commands, table ?? this.commandsTable);
let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: list }); let html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/settings/dialog-aide-commands.html", { commands: commands });
let d = new Dialog( let d = new Dialog(
{ {
title: "Commandes disponibles dans le tchat", title: "Commandes disponibles dans le tchat",
@@ -212,7 +269,7 @@ export class RdDCommands {
buttons: {}, buttons: {},
}, },
{ {
width: 600, height: 500, width: 600, height: 600,
}); });
d.render(true); d.render(true);
@@ -242,11 +299,9 @@ export class RdDCommands {
/* -------------------------------------------- */ /* -------------------------------------------- */
async getRencontreTMR(params) { async getRencontreTMR(params) {
if (params.length == 1 || params.length == 2) { if (params.length == 1 || params.length == 2) {
return TMRRencontres.rollRencontre(params[0], params[1]) return game.system.rdd.rencontresTMR.rollRencontre(params[0], params[1])
}
else {
return false;
} }
return false;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -299,20 +354,20 @@ export class RdDCommands {
show: { title: "Table de résolution" } show: { title: "Table de résolution" }
}; };
await RdDResolutionTable.rollData(rollData); await RdDResolutionTable.rollData(rollData);
RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData)); return RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async rollDeDraconique(msg) { async rollDeDraconique(msg) {
let ddr = await RdDDice.rollTotal("1dr + 7"); let ddr = await RdDDice.rollTotal("1dr + 7");
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`); return RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
} }
async getTMRAleatoire(msg, params) { async getTMRAleatoire(msg, params) {
if (params.length < 2) { if (params.length < 2) {
let type = params[0]; let type = params[0];
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true)); const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`); return RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
} }
else { else {
return false; return false;
@@ -320,20 +375,61 @@ export class RdDCommands {
} }
async findTMR(msg, params) { async findTMR(msg, params) {
const search = Misc.join(params, ' '); if (params && params.length > 0) {
const found = TMRUtility.findTMR(search); const search = Misc.join(params, ' ');
if (found?.length > 0) { const found = TMRUtility.findTMR(search);
return RdDCommands._chatAnswer(msg, `Les TMRs correspondant à '${search}' sont:` + Misc.join(found.map(it => `<br>${it.coord}: ${it.label}`))); if (found?.length > 0) {
return RdDCommands._chatAnswer(msg, `Les TMRs correspondant à '${search}' sont:` + Misc.join(found.map(it => `<br>${it.coord}: ${it.label}`)));
}
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
} }
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search); return false;
} }
async tableRencontres(msg, params) {
if (params && params.length > 0) {
const search = Misc.join(params, ' ');
const solvedTerrain = TMRUtility.findTMRLike(search);
if (solvedTerrain == undefined) {
return RdDCommands._chatAnswer(msg, 'Aucune TMR correspondant à ' + search);
}
return await game.system.rdd.rencontresTMR.chatTable(solvedTerrain);
}
return false;
}
async tableMilieu(msg, params, toChat) {
if (params && params.length > 0) {
const search = Misc.join(params, ' ');
const milieux = await game.system.rdd.environnement.findEnvironnementsLike(search);
if (milieux.length == 0) {
const tous = Object.values(await game.system.rdd.environnement.milieux());
return RdDCommands._chatAnswer(msg, `<strong>Aucun milieu correspondant à '${search}'.</strong>
<br>Milieux disponibles:
<br><ul class="chat-list"><li>${tous.reduce(Misc.joining('</li><li>'))}</li></ul>`);
}
if (milieux.length > 1) {
ui.notifications.warn(`<strong>Plusieurs milieux correspondent à '${search}'</strong>:
<br><ul class="chat-list"><li>${milieux.reduce(Misc.joining('</li><li>'))}</li></ul>`);
}
const tableName = `ressources en ${milieux.reduce(Misc.joining(', '))}`;
if (toChat == 'liste') {
return await game.system.rdd.environnement.searchToChatMessage(milieux, tableName);
}
else {
const row = await game.system.rdd.environnement.getRandom(milieux, tableName);
await CompendiumTableHelpers.tableRowToChatMessage(row, 'Item');
return true;
}
}
return false;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
getCoutXpComp(msg, params) { getCoutXpComp(msg, params) {
if (params && (params.length == 1 || params.length == 2)) { if (params && (params.length == 1 || params.length == 2)) {
let to = params.length == 1 ? Number(params[0]) : Number(params[1]); let to = params.length == 1 ? Number(params[0]) : Number(params[1]);
let from = params.length == 1 ? to - 1 : Number(params[0]); let from = params.length == 1 ? to - 1 : Number(params[0]);
RdDCommands._chatAnswer(msg, `Coût pour passer une compétence de ${from} à ${to}: ${RdDItemCompetence.getDeltaXp(from, to)}`); return RdDCommands._chatAnswer(msg, `Coût pour passer une compétence de ${from} à ${to}: ${RdDItemCompetence.getDeltaXp(from, to)}`);
} }
else { else {
return false; return false;
@@ -344,7 +440,7 @@ export class RdDCommands {
getCoutXpCarac(msg, params) { getCoutXpCarac(msg, params) {
if (params && params.length == 1) { if (params && params.length == 1) {
let to = Number(params[0]); let to = Number(params[0]);
RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`); return RdDCommands._chatAnswer(msg, `Coût pour passer une caractéristique de ${to - 1} à ${to}: ${RdDCarac.getCaracXp(to)}`);
} }
else { else {
return false; return false;
@@ -404,5 +500,6 @@ export class RdDCommands {
async getMeteo(msg, params) { async getMeteo(msg, params) {
return await RdDMeteo.getMeteo(); return await RdDMeteo.getMeteo();
} }
} }

View File

@@ -29,13 +29,14 @@ export class RddCompendiumOrganiser {
static getEntityTypeLabel(entity) { static getEntityTypeLabel(entity) {
const documentName = entity?.documentName const documentName = entity?.documentName
const type = entity?.type const type = entity?.type
if (documentName === 'Actor' || documentName === 'Item') { if (documentName === 'Actor' || documentName === 'Item') {
const label = CONFIG[documentName]?.typeLabels?.[type] ?? type; const label = CONFIG[documentName]?.typeLabels?.[type] ?? type;
return game.i18n.has(label) ? game.i18n.localize(label) : t; if (game.i18n.has(label)) {
return game.i18n.localize(label);
}
} }
return type; return type;
} }
} }

View File

@@ -1,5 +1,5 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
export class RdDConfirm { export class RdDConfirm {
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -45,7 +45,7 @@ export class RdDConfirm {
return { return {
"actionSave": { "actionSave": {
icon: '<i class="fas fa-user-check"></i>', icon: '<i class="fas fa-user-check"></i>',
label: "Toujours "+ options.buttonLabel.toLowerCase(), label: options.buttonLabel + "<br>et ne plus demander",
callback: () => { callback: () => {
ReglesOptionelles.set(options.settingConfirmer, false); ReglesOptionelles.set(options.settingConfirmer, false);
options.onAction(); options.onAction();

View File

@@ -144,6 +144,9 @@ export class RdDDice {
} }
static async rollOneOf(array) { static async rollOneOf(array) {
if (array == undefined || array.length == 0) {
return undefined;
}
const roll = await RdDDice.rollTotal(`1d${array.length}`); const roll = await RdDDice.rollTotal(`1d${array.length}`);
return array[roll - 1]; return array[roll - 1];
} }
@@ -241,7 +244,7 @@ export class RdDDice {
} }
static _getWhisperBlind(options) { static _getWhisperBlind(options) {
let whisper = null; let whisper = undefined;
let blind = false; let blind = false;
let rollMode = options.rollMode ?? game.settings.get("core", "rollMode"); let rollMode = options.rollMode ?? game.settings.get("core", "rollMode");
switch (rollMode) { switch (rollMode) {

View File

@@ -1,6 +1,7 @@
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { RdDCalendrier } from "./rdd-calendrier.js"; import { RdDCalendrier } from "./rdd-calendrier.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDHerbes extends Item { export class RdDHerbes extends Item {
@@ -12,9 +13,8 @@ export class RdDHerbes extends Item {
} }
static async listCategorieHerbes(categorie) { static async listCategorieHerbes(categorie) {
return await RdDUtility.loadItems( const herbes = await SystemCompendiums.getWorldOrCompendiumItems('herbe', 'faune-flore-mineraux');
it => it.type == 'herbe' && it.system.categorie.toLowerCase() == categorie.toLowerCase(), return herbes.filter(it => Grammar.equalsInsensitive(it.system.categorie, categorie));
'foundryvtt-reve-de-dragon.botanique');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -42,7 +42,7 @@ export class RdDHerbes extends Item {
formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7); formData.herbesRepos = RdDHerbes.buildHerbesList(this.herbesRepos, 7);
formData.jourMoisOptions = RdDCalendrier.buildJoursMois(); formData.jourMoisOptions = RdDCalendrier.buildJoursMois();
formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex(); formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex();
formData.splitDate = game.system.rdd.calendrier.getNumericDateFromIndex(formData.system.prdate); formData.splitDate = game.system.rdd.calendrier.getDayMonthFromIndex(formData.system.prdate);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@@ -23,10 +23,9 @@ 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 "./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 { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { TMRRencontres } from "./tmr-rencontres.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";
@@ -36,6 +35,15 @@ import { RdDPossession } from "./rdd-possession.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js"; import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Migrations } from './migrations.js'; import { Migrations } from './migrations.js';
import { DialogChronologie } from "./dialog-chronologie.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRencontreItemSheet } from "./item-rencontre-sheet.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { RdDHerbeItemSheet } from "./item-herbe-sheet.js";
import { Environnement } from "./environnement.js";
import { RdDIngredientItemSheet } from "./item-ingredient-sheet.js";
import { RdDFauneItemSheet } from "./item-faune-sheet.js";
import { RdDConteneurItemSheet } from "./item-conteneur-sheet.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Foundry VTT Initialization */ /* Foundry VTT Initialization */
@@ -77,7 +85,7 @@ Hooks.once("init", async function () {
name: "calendrier", name: "calendrier",
scope: "world", scope: "world",
config: false, config: false,
default: RdDCalendrier.getCalendrier(0), default: RdDCalendrier.createCalendrierInitial(),
type: Object type: Object
}); });
@@ -107,6 +115,8 @@ Hooks.once("init", async function () {
default: RdDCalendrier.createCalendrierPos(), default: RdDCalendrier.createCalendrierPos(),
type: Object type: Object
}); });
/* -------------------------------------------- */ /* -------------------------------------------- */
game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", { game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
name: "Supprimer les dialogues de combat", name: "Supprimer les dialogues de combat",
@@ -155,8 +165,8 @@ Hooks.once("init", async function () {
RdDCombat.onSocketMessage(sockmsg); RdDCombat.onSocketMessage(sockmsg);
ChatUtility.onSocketMessage(sockmsg); ChatUtility.onSocketMessage(sockmsg);
RdDActor.onSocketMessage(sockmsg); RdDActor.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)
} }
}); });
@@ -179,19 +189,30 @@ Hooks.once("init", async function () {
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);
Items.registerSheet(SYSTEM_RDD, RdDSigneDraconiqueItemSheet, {
label: "Signe draconique", RdDItemSheet.register(RdDSigneDraconiqueItemSheet);
types: ["signedraconique"], RdDItemSheet.register(RdDRencontreItemSheet);
makeDefault: true RdDItemSheet.register(RdDConteneurItemSheet);
}); RdDItemSheet.register(RdDHerbeItemSheet);
RdDItemSheet.register(RdDFauneItemSheet);
RdDItemSheet.register(RdDIngredientItemSheet);
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, { Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
types: ["arme", "armure", "objet", "arme", "armure", "conteneur", "competence", "sort", "herbe", "ingredient", "livre", "potion", "munition", "rencontresTMR", "queue", "ombre", "souffle", types: [
"tete", "competencecreature", "tarot", "monnaie", "nombreastral", "tache", "meditation", "casetmr", "recettealchimique", "gemme", "competence", "competencecreature",
"musique", "chant", "danse", "jeu", "recettecuisine", "maladie", "poison", "oeuvre", "nourritureboisson", "possession", "sortreserve"], makeDefault: true "recettealchimique", "musique", "chant", "danse", "jeu", "recettecuisine", "oeuvre",
"objet", "arme", "armure", "livre", "potion", "munition",
"monnaie", "nourritureboisson", "gemme",
"meditation", "queue", "ombre", "souffle", "tete", "casetmr", "sort", "sortreserve",
"nombreastral", "tache", "maladie", "poison", "possession",
"tarot", "extraitpoetique"
], makeDefault: true
}); });
CONFIG.Combat.documentClass = RdDCombatManager; CONFIG.Combat.documentClass = RdDCombatManager;
// préparation des différents modules // préparation des différents modules
SystemCompendiums.init();
DialogChronologie.init();
ReglesOptionelles.init(); ReglesOptionelles.init();
RdDUtility.init(); RdDUtility.init();
RdDDice.init(); RdDDice.init();
@@ -203,9 +224,10 @@ Hooks.once("init", async function () {
RddCompendiumOrganiser.init(); RddCompendiumOrganiser.init();
EffetsDraconiques.init() EffetsDraconiques.init()
TMRUtility.init(); TMRUtility.init();
TMRRencontres.init();
RdDHotbar.initDropbar(); RdDHotbar.initDropbar();
RdDPossession.init(); RdDPossession.init();
TMRRencontres.init();
Environnement.init();
}); });
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -223,8 +245,8 @@ function messageDeBienvenue() {
/* -------------------------------------------- */ /* -------------------------------------------- */
// Register world usage statistics // Register world usage statistics
function registerUsageCount( registerKey ) { function registerUsageCount(registerKey) {
if ( game.user.isGM ) { if (game.user.isGM) {
game.settings.register("world", "world-key", { game.settings.register("world", "world-key", {
name: "Unique world key", name: "Unique world key",
scope: "world", scope: "world",
@@ -234,9 +256,9 @@ function registerUsageCount( registerKey ) {
}); });
let worldKey = game.settings.get("world", "world-key") let worldKey = game.settings.get("world", "world-key")
if ( worldKey == undefined || worldKey == "" ) { if (worldKey == undefined || worldKey == "") {
worldKey = randomID(32) worldKey = randomID(32)
game.settings.set("world", "world-key", worldKey ) game.settings.set("world", "world-key", worldKey)
} }
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"` let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
$.ajax(regURL) $.ajax(regURL)
@@ -276,7 +298,7 @@ Hooks.once("ready", async function () {
} }
if (Misc.isUniqueConnectedGM()) { if (Misc.isUniqueConnectedGM()) {
messageDeBienvenue(); messageDeBienvenue();
registerUsageCount( SYSTEM_RDD ); registerUsageCount(SYSTEM_RDD);
} }
}); });
@@ -321,17 +343,3 @@ async function migrationPngWebp_1_5_34() {
/* -------------------------------------------- */ /* -------------------------------------------- */
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d)); Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d));
/* -------------------------------------------- */
/* Foundry VTT chat message */
/* -------------------------------------------- */
Hooks.on("chatMessage", (html, content, msg) => {
if (content[0] == '/') {
let regExp = /(\S+)/g;
let commands = content.match(regExp);
if (game.system.rdd.commands.processChatCommand(commands, content, msg)) {
return false;
}
}
return true;
});

View File

@@ -3,6 +3,7 @@ import { RdDCombat } from "./rdd-combat.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; 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";
/* -------------------------------------------- */ /* -------------------------------------------- */
/* On part du principe qu'une entité démarre tjs /* On part du principe qu'une entité démarre tjs
@@ -27,7 +28,139 @@ export class RdDPossession {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static updateEtatPossession(possession) { static async onAttaquePossession(target, attacker, competence, suitePossession = undefined) {
const defender = target.actor;
const fromEntite = RdDPossession.searchPossessionFromEntite(attacker, defender);
const isNouvelle = !suitePossession && ! fromEntite;
const possession = (suitePossession ?? fromEntite ?? (await RdDPossession.createPossession(attacker, defender)));
RdDPossession.$updateEtatPossession(possession)
let rollData = {
mode: "possession",
isECNIDefender: false,
competence: competence,
possession: possession,
attacker: attacker,
defender: defender,
targetToken: Targets.extractTokenData(target)
};
if (attacker.isCreatureEntite()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
await RdDPossession.$rollAttaquePossession(attacker, rollData, isNouvelle);
}
/* -------------------------------------------- */
static async onConjurerPossession(attacker, competence, possession) {
possession = duplicate(possession);
RdDPossession.$updateEtatPossession(possession)
let rollData = {
mode: "possession",
isECNIDefender: true,
competence: competence,
possession: possession,
attacker: attacker,
defender: game.actors.get(possession.system.possesseurid)
};
await RdDPossession.$rollAttaquePossession(attacker, rollData);
}
/* -------------------------------------------- */
static async onDefensePossession(attackerId, defenderId, possessionId) {
let attacker = game.actors.get(attackerId)
let possession = attacker?.getPossession(possessionId)
defenderId = defenderId ?? possession?.system.possesseurid ?? undefined
let defender = game.actors.get(defenderId)
possession = possession ?? defender?.getPossession(possessionId) ?? undefined;
if (!possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
possession = duplicate(possession)
// Update for draconic roll
let rollData = {
mode: "conjuration",
isECNIDefender: defender.type == "entite",
possession: possession,
attacker: attacker,
defender: defender,
competence: defender.getDraconicOuPossession(),
selectedCarac: defender.system.carac.reve,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
}
rollData.competence.system.defaut_carac = 'reve-actuel'
await RdDPossession.$rollDefensePossession(defender, rollData);
}
/* -------------------------------------------- */
static async $rollAttaquePossession(attacker, rollData, isNouvelle = false) {
const dialog = await RdDRoll.create(attacker, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html' },
{
name: 'jet-possession',
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async (r) => await RdDPossession.$onRollPossession(r, true, isNouvelle) },
{ condition: r => (r.rolled.isEchec), action: async (r) => await RdDPossession.$onRollPossession(r, false, isNouvelle) },
]
});
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollPossession(rollData, isSuccess, isNouvelle = false) {
rollData.possession.isSuccess = isSuccess;
RdDPossession.$updateEtatPossession(rollData.possession);
if (isNouvelle) {
// Creer la possession sur le defenseur
rollData.defender.createEmbeddedDocuments('Item', [rollData.possession.toObject()])
}
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async $rollDefensePossession(defender, rollData) {
const dialog = await RdDRoll.create(defender, rollData,
{ html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html' },
{
name: 'conjurer',
label: 'Conjurer une Possession',
callbacks: [
{ action: async (r) => await RdDPossession.$onRollConjuration(r) }
]
}
);
dialog.render(true);
}
/* -------------------------------------------- */
static async $onRollConjuration(rollData) {
let actor = game.actors.get(rollData.possession.system.possedeid)
if (!rollData.rolled.isSuccess) {
if (rollData.isECNIDefender) {
rollData.possession.system.compteur--
} else {
rollData.possession.system.compteur++
}
let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
await actor.updateEmbeddedDocuments('Item', [update])
}
RdDPossession.$updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData,rollData.defender, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}
/* -------------------------------------------- */
static $updateEtatPossession(possession) {
possession.ptsConjuration = 0 possession.ptsConjuration = 0
possession.ptsPossession = 0 possession.ptsPossession = 0
console.log("Possession", possession) console.log("Possession", possession)
@@ -48,122 +181,15 @@ export class RdDPossession {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async resultConjuration(rollData) { static async createPossession(attacker, defender) {
let actor = game.actors.get(rollData.possession.system.possedeid) return await Item.create({
if (!rollData.rolled.isSuccess) { name: "Possession en cours de " + attacker.name, type: 'possession',
if (rollData.isECNIDefender) { img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
rollData.possession.system.compteur-- system: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.id, possedeid: defender.id, date: 0, compteur: 0 }
} else {
rollData.possession.system.compteur++
}
let update = { _id: rollData.possession._id, "system.compteur": rollData.possession.system.compteur }
await actor.updateEmbeddedDocuments('Item', [update])
}
this.updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
actor.deleteEmbeddedDocuments("Item", [rollData.possession._id])
}
}
/* -------------------------------------------- */
static async onDefensePossession(attackerId, defenderId, possessionId) {
let attacker = game.actors.get(attackerId)
let defender = game.actors.get(defenderId)
let possession = attacker.getPossession(possessionId) ?? defender.getPossession(possessionId) ;
if (!possession) {
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
return
}
// Update for draconic roll
let rollData = {
mode: "conjuration",
isECNIDefender: defender.type == "entite",
possession: duplicate(possession),
attacker: attacker,
defender: defender,
competence: defender.getDraconicOuPossession(),
selectedCarac: defender.system.carac.reve,
forceCarac: { 'reve-actuel': { label: "Rêve Actuel", value: defender.getReveActuel() } }
}
rollData.competence.system.defaut_carac = 'reve-actuel'
const dialog = await RdDRoll.create(defender, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-defense-possession.html',
options: { height: 450 }
}, },
{ {
name: 'conjurer', temporary: true
label: 'Conjurer une Possession', })
callbacks: [
{ action: async r => await this.resultConjuration(r) }
]
}
);
dialog.render(true)
}
/* -------------------------------------------- */
static async onAttaquePossession(attacker, competence, possession = undefined) {
const target = RdDCombat.getTarget()
if (target == undefined) {
ui.notifications.warn((game.user.targets?.size ?? 0) > 1
? "Vous devez choisir <strong>une seule</strong> cible à posséder!"
: "Vous devez choisir une cible à posséder!");
return;
}
const defender = target.actor;
possession = duplicate(possession ?? this.searchPossessionFromEntite(attacker, defender) ??(await this.createPossession(attacker, defender)));
this.updateEtatPossession(possession)
let rollData = {
mode: "possession",
isECNIDefender: defender.type == "entite",
competence: competence,
possession: possession,
attacker: attacker,
defender: defender
};
if (attacker.isCreature()) {
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
const dialog = await RdDRoll.create(attacker, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
options: { height: 540 }
}, {
name: 'jet-possession',
label: rollData.isECNIDefender ? 'Conjurer la possession' : 'Possession',
callbacks: [
{ condition: r => (r.rolled.isSuccess), action: async r => await this._onRollPossession(r, true) },
{ condition: r => (r.rolled.isEchec), action: async r => await this._onRollPossession(r, false) },
]
});
dialog.render(true)
}
/* -------------------------------------------- */
static async _onRollPossession(rollData, isSuccess) {
rollData.possession.isSuccess = isSuccess;
this.updateEtatPossession(rollData.possession);
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-possession.html');
}
/* -------------------------------------------- */
static async createPossession(attacker, defender) {
let possessionData = {
name: "Possession en cours de " + attacker.name, type: 'possession',
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
system: { description: "", typepossession: attacker.name, possede: false, possessionid: randomID(16), possesseurid: attacker.id, possedeid: defender.id, date: 0, compteur: 0 }
}
// Creates only the possession on the personnage side
let poss = await defender.createEmbeddedDocuments('Item', [possessionData])
return duplicate(poss[0])
} }
} }

View File

@@ -1,7 +1,7 @@
import { ChatUtility } from "./chat-utility.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";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
/** /**
* difficultés au delà de -10 * difficultés au delà de -10
@@ -14,7 +14,7 @@ const levelDown = [
{ level: -15, score: 1, norm: 1, sign: 0, part: 0, epart: 2, etotal: 10 }, { level: -15, score: 1, norm: 1, sign: 0, part: 0, epart: 2, etotal: 10 },
{ level: -16, score: 1, norm: 1, sign: 0, part: 0, epart: 0, etotal: 2 } { level: -16, score: 1, norm: 1, sign: 0, part: 0, epart: 0, etotal: 2 }
]; ];
const levelImpossible = { score: 0, norm:0, sign: 0, part: 0, epart: 0, etotal: 1 }; const levelImpossible = { score: 0, norm: 0, sign: 0, part: 0, epart: 0, etotal: 1 };
const reussites = [ const reussites = [
{ code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 }, { code: "etotal", isPart: false, isSign: false, isSuccess: false, isEchec: true, isEPart: true, isETotal: true, ptTache: -4, ptQualite: -6, quality: "Echec total", condition: (target, roll) => roll >= target.etotal && roll <= 100 },
@@ -42,6 +42,44 @@ export class RdDResolutionTable {
return table; return table;
} }
/* -------------------------------------------- */
static computeChances(carac, level) {
if (level < -16) {
return levelImpossible;
}
if (level < -10) {
return levelDown.find(it => it.level == level);
}
const percentage = RdDResolutionTable.computePercentage(carac, level);
return this._computeCell(level, percentage);
}
/* -------------------------------------------- */
static _computeRow(caracValue) {
let dataRow = [
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
]
for (var diff = -8; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeCell(diff, RdDResolutionTable.computePercentage(caracValue, diff));
}
return dataRow;
}
/* -------------------------------------------- */
static _computeCell(niveau, percentage) {
return {
niveau: niveau,
score: percentage,
norm: Math.min(99, percentage),
sign: this._reussiteSignificative(percentage),
part: this._reussitePart(percentage),
epart: this._echecParticulier(percentage),
etotal: this._echecTotal(percentage)
};
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static getResultat(code) { static getResultat(code) {
let resultat = reussites.find(r => code == r.code); let resultat = reussites.find(r => code == r.code);
@@ -51,17 +89,6 @@ export class RdDResolutionTable {
return resultat; return resultat;
} }
/* -------------------------------------------- */
static explain(rolled) {
let message = "<br>Jet : <strong>" + rolled.roll + "</strong> sur " + rolled.score + "% ";
if (rolled.caracValue != null && rolled.finalLevel != null) {
message += (rolled.diviseurSignificative > 1 ? `(1/${rolled.diviseurSignificative} de ` : "(")
+ rolled.caracValue + " à " + Misc.toSignedString(rolled.finalLevel) + ") ";
}
message += '<strong>' + rolled.quality + '</strong>'
return message;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
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(actor?.userName ?? game.user.name, { return await ChatUtility.createChatWithRollMode(actor?.userName ?? game.user.name, {
@@ -82,8 +109,8 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async roll(caracValue, finalLevel, rollData = {}){ static async roll(caracValue, finalLevel, rollData = {}) {
let chances = this.computeChances(caracValue, finalLevel); let chances = duplicate(this.computeChances(caracValue, finalLevel));
this._updateChancesWithBonus(chances, rollData.bonus, finalLevel); this._updateChancesWithBonus(chances, rollData.bonus, finalLevel);
this._updateChancesFactor(chances, rollData.diviseurSignificative); this._updateChancesFactor(chances, rollData.diviseurSignificative);
chances.showDice = rollData.showDice; chances.showDice = rollData.showDice;
@@ -95,7 +122,7 @@ export class RdDResolutionTable {
rolled.bonus = rollData.bonus; rolled.bonus = rollData.bonus;
rolled.factorHtml = Misc.getFractionHtml(rollData.diviseurSignificative); rolled.factorHtml = Misc.getFractionHtml(rollData.diviseurSignificative);
if (ReglesOptionelles.isUsing("afficher-colonnes-reussite")){ if (ReglesOptionelles.isUsing("afficher-colonnes-reussite")) {
rolled.niveauNecessaire = this.findNiveauNecessaire(caracValue, rolled.roll); rolled.niveauNecessaire = this.findNiveauNecessaire(caracValue, rolled.roll);
rolled.ajustementNecessaire = rolled.niveauNecessaire - finalLevel; rolled.ajustementNecessaire = rolled.niveauNecessaire - finalLevel;
} }
@@ -103,28 +130,39 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static findNiveauNecessaire(caracValue, rollValue) { static findNiveauNecessaire(carac, rolled) {
for (let cell of this.resolutionTable[caracValue]) { if (carac == 0) {
if ( rollValue <= cell.norm) { return NaN;
return cell.niveau;
}
} }
return 16; // Dummy default if (rolled >= carac){
const upper = Math.ceil(rolled/carac);
return 2*upper -10
}
if (rolled > Math.floor(carac/2)) {
return -8
}
if (rolled > Math.floor(carac/4)) {
return -9
}
if (rolled > 1) {
return -10
}
return -11;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _updateChancesFactor(chances, diviseur) { static _updateChancesFactor(chances, diviseur) {
if (chances.level > -11 && diviseur && diviseur > 1) { if (chances.level > -11 && diviseur && diviseur > 1) {
let newScore = Math.floor(chances.score / diviseur); let newScore = Math.floor(chances.score / diviseur);
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true }); mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _updateChancesWithBonus(chances, bonus, finalLevel) { static _updateChancesWithBonus(chances, bonus, finalLevel) {
if (bonus && finalLevel>-11) { if (bonus && finalLevel > -11) {
let newScore = Number(chances.score) + bonus; let newScore = Number(chances.score) + bonus;
mergeObject(chances, this._computeCell(null, newScore), { overwrite: true }); mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
} }
} }
@@ -142,21 +180,19 @@ export class RdDResolutionTable {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async rollChances(chances, diviseur, forceDiceResult = -1) { static async rollChances(chances, diviseur, forceDiceResult = -1) {
chances.forceDiceResult = forceDiceResult <= 0 || forceDiceResult > 100 ? undefined : {total: forceDiceResult}; chances.forceDiceResult = forceDiceResult <= 0 || forceDiceResult > 100 ? undefined : { total: forceDiceResult };
chances.roll = await RdDDice.rollTotal( "1d100", chances); chances.roll = await RdDDice.rollTotal("1d100", chances);
mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true }); mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
return chances; return chances;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static computeChances(caracValue, difficulte) { static computePercentage(carac, diff) {
if (difficulte < -16) { if (diff < -16) return 0
return duplicate(levelImpossible); if (diff < -10) return 1
} if (diff == -10) return Math.max(Math.floor(carac / 4), 1)
if (difficulte < -10) { if (diff == -9) return Math.max(Math.floor(carac / 2), 1)
return duplicate(levelDown.find(levelData => levelData.level == difficulte)); return Math.max(Math.floor(carac * (diff + 10) / 2), 1);
}
return duplicate(RdDResolutionTable.resolutionTable[caracValue][difficulte + 10]);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -213,31 +249,6 @@ export class RdDResolutionTable {
return reussite; return reussite;
} }
/* -------------------------------------------- */
static _computeRow(caracValue) {
let dataRow = [
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
]
for (var diff = -8; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(caracValue * (diff + 10) / 2), 1));
}
return dataRow;
}
/* -------------------------------------------- */
static _computeCell(niveau, percentage) {
return {
niveau: niveau,
score: percentage,
norm: Math.min(99, percentage),
sign: this._reussiteSignificative(percentage),
part: this._reussitePart(percentage),
epart: this._echecParticulier(percentage),
etotal: this._echecTotal(percentage)
};
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static _reussiteSignificative(percentage) { static _reussiteSignificative(percentage) {
return Math.floor(percentage / 2); return Math.floor(percentage / 2);
@@ -261,92 +272,34 @@ export class RdDResolutionTable {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static buildHTMLResults(caracValue, levelValue) { static subTable(carac, level, delta = { carac: 2, level: 5}) {
if (caracValue == undefined || isNaN(caracValue)) caracValue = 10; return {
if (levelValue == undefined || isNaN(levelValue)) levelValue = 0; carac,
level,
let cell = this.computeChances(caracValue, levelValue); minCarac: carac - (delta?.carac ?? 2),
cell.epart = cell.epart > 99 ? 'N/A' : cell.epart; maxCarac: carac + (delta?.carac ?? 2),
cell.etotal = cell.etotal > 100 ? 'N/A' : cell.etotal; minLevel: level - (delta?.level ?? 5),
cell.score = Math.min(cell.score, 99); maxLevel: level + (delta?.level ?? 5)
};
return `
<span class="table-proba-reussite competence-label">
Particulière: <span class="rdd-roll-part">${cell.part}</span>
- Significative: <span class="rdd-roll-sign">${cell.sign}</span>
- Réussite: <span class="rdd-roll-norm">${cell.score}</span>
- Echec Particulier: <span class="rdd-roll-epart">${cell.epart}</span>
- Echec Total: <span class="rdd-roll-etotal">${cell.etotal}</span>
</span>
`
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static buildHTMLTableExtract(caracValue, levelValue) { static async buildHTMLTable({ carac: carac, level: level, minCarac = 1, maxCarac = 21, minLevel = -10, maxLevel = 11 }) {
return this.buildHTMLTable(caracValue, levelValue, caracValue - 2, caracValue + 2, levelValue - 5, levelValue + 5) let colonnes = maxLevel - minLevel;
}
static buildHTMLTable(caracValue, levelValue, minCarac = 1, maxCarac = 21, minLevel = -10, maxLevel = 11) {
return this._buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel)
}
/* -------------------------------------------- */
static _buildHTMLTable(caracValue, levelValue, minCarac, maxCarac, minLevel, maxLevel) {
let countColonnes = maxLevel - minLevel;
minCarac = Math.max(minCarac, 1); minCarac = Math.max(minCarac, 1);
maxCarac = Math.min(maxCarac, caracMaximumResolution); maxCarac = Math.min(maxCarac, minCarac + 20);
minLevel = Math.max(minLevel, -10); minLevel = Math.max(minLevel, -10);
maxLevel = Math.max(Math.min(maxLevel, 22), minLevel + countColonnes); maxLevel = Math.max(Math.min(maxLevel, 30), minLevel + colonnes);
return await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/resolution-table.html', {
let table = $("<table class='table-resolution'/>") carac: carac,
.append(this._buildHTMLHeader(RdDResolutionTable.resolutionTable[0], minLevel, maxLevel)); difficulte: level,
min: minLevel,
for (var rowIndex = minCarac; rowIndex <= maxCarac; rowIndex++) { rows: RdDResolutionTable.incrementalArray(minCarac, maxCarac),
table.append(this._buildHTMLRow(RdDResolutionTable.resolutionTable[rowIndex], rowIndex, caracValue, levelValue, minLevel, maxLevel)); cols: RdDResolutionTable.incrementalArray(minLevel, maxLevel)
} });
table.append("</table>");
return table;
} }
static incrementalArray(min, max) {
/* -------------------------------------------- */ return Array.from(Array(max-min+1).keys()).map(i=>i+min)
static _buildHTMLHeader(dataRow, minLevel, maxLevel) {
let tr = $("<tr/>");
if (minLevel > -8) {
tr.append($("<th class='table-resolution-level'/>").text("-8"))
}
if (minLevel > -7) {
tr.append($("<th class='table-resolution-level'/>").text("..."));
}
for (let difficulte = minLevel; difficulte <= maxLevel; difficulte++) {
tr.append($("<th class='table-resolution-level'/>").text(Misc.toSignedString(difficulte)));
}
return tr;
}
/* -------------------------------------------- */
static _buildHTMLRow(dataRow, rowIndex, caracValue, levelValue, minLevel, maxLevel) {
let tr = $("<tr/>");
let max = maxLevel;
if (minLevel > -8) {
let score = dataRow[-8 + 10].score;
tr.append($("<td class='table-resolution-carac'/>").text(score))
}
if (minLevel > -7) {
tr.append($("<td/>"))
}
for (let difficulte = minLevel; difficulte <= max; difficulte++) {
let td = $("<td/>");
let score = dataRow[difficulte + 10].score;
if (rowIndex == caracValue && levelValue == difficulte) {
td.addClass('table-resolution-target');
} else if (difficulte == -8) {
td.addClass('table-resolution-carac');
}
tr.append(td.text(score));
}
return tr;
} }
} }

View File

@@ -1,4 +1,5 @@
import { ENTITE_BLURETTE, ENTITE_INCARNE} from "./constants.js"; import { ENTITE_BLURETTE, ENTITE_INCARNE } from "./constants.js";
import { RdDUtility } from "./rdd-utility.js";
/** /**
* Extend the base Dialog entity by defining a custom window to perform roll. * Extend the base Dialog entity by defining a custom window to perform roll.
@@ -6,34 +7,39 @@ import { ENTITE_BLURETTE, ENTITE_INCARNE} from "./constants.js";
*/ */
export class RdDEncaisser extends Dialog { export class RdDEncaisser extends Dialog {
static async encaisser(actor) {
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html',
{ ajustementsEncaissement: RdDUtility.getAjustementsEncaissement() }
);
new RdDEncaisser(html, actor).render(true);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(html, actor) { constructor(html, actor) {
// Common conf let dialogConf = {
let buttons = {}; title: "Jet d'Encaissement",
if (!actor.isEntite()){ content: html,
buttons = { }
if (!actor.isEntite()) {
dialogConf.default = "mortel";
dialogConf.buttons = {
"mortel": { label: "Mortel", callback: html => this.performEncaisser("mortel") }, "mortel": { label: "Mortel", callback: html => this.performEncaisser("mortel") },
"non-mortel": { label: "Non-mortel", callback: html => this.performEncaisser("non-mortel") }, "non-mortel": { label: "Non-mortel", callback: html => this.performEncaisser("non-mortel") },
"sonne": { label: "Sonné", callback: html => this.actor.setSonne() }, "sonne": { label: "Sonné", callback: html => this.actor.setSonne() },
}; };
} }
else if (actor.isEntite([ENTITE_BLURETTE, ENTITE_INCARNE])){ else if (actor.isEntite([ENTITE_BLURETTE, ENTITE_INCARNE])) {
buttons = { dialogConf.default = "cauchemar"
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") } dialogConf.buttons = {
"cauchemar": { label: "Cauchemar", callback: html => this.performEncaisser("cauchemar") }
} }
} }
let dialogConf = {
title: "Jet d'Encaissement",
content: html,
buttons: buttons,
default: "mortel"
}
let dialogOptions = { let dialogOptions = {
classes: ["rdddialog"], classes: ["rdd-roll-dialog"],
width: 320, width: 320,
height: 260 height: 'fit-content'
} }
// Select proper roll dialog template and stuff // Select proper roll dialog template and stuff
@@ -44,7 +50,18 @@ export class RdDEncaisser extends Dialog {
this.encaisserSpecial = "aucun"; this.encaisserSpecial = "aucun";
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.html.find('[name="modificateurDegats"]').val("0");
this.html.find('[name="modificateurDegats"]').change((event) => {
this.modifier = event.currentTarget.value; // Update the selected bonus/malus
});
this.html.find('[name="encaisserSpecial"]').change((event) => {
this.encaisserSpecial = event.currentTarget.value; // Update the selected bonus/malus
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
performEncaisser(mortalite) { performEncaisser(mortalite) {
@@ -58,22 +75,4 @@ export class RdDEncaisser extends Dialog {
} }
}); });
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
// Setup everything onload
$(function () {
$("#modificateurDegats").val("0");
});
html.find('#modificateurDegats').change((event) => {
this.modifier = event.currentTarget.value; // Update the selected bonus/malus
});
html.find('#encaisserSpecial').change((event) => {
this.encaisserSpecial = event.currentTarget.value; // Update the selected bonus/malus
});
}
} }

View File

@@ -13,47 +13,33 @@ export class RdDRollDialogEthylisme extends Dialog {
title: "Test d'éthylisme", title: "Test d'éthylisme",
content: html, content: html,
default: "rollButton", default: "rollButton",
buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => this.onButton(html) } } buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => onRoll(this.rollData) } }
}; };
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 270, 'z-index': 99999 } let dialogOptions = { classes: ["rdd-roll-dialog"], width: 400, height: 'fit-content', 'z-index': 99999 }
super(dialogConf, dialogOptions) super(dialogConf, dialogOptions)
//console.log("ETH", rollData);
this.onRoll = onRoll;
this.rollData = rollData; this.rollData = rollData;
this.actor = actor; this.actor = actor;
} }
async onButton(html) { activateListeners(html) {
this.onRoll(this.rollData); super.activateListeners(html);
this.html = html;
this.bringToTop();
this.html.find(".force-alcool").change((event) => {
this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value);
this.updateRollResult();
});
this.html.find(".force-alcool").val(Misc.toInt(this.rollData.forceAlcool));
this.updateRollResult();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.bringToTop(); // Ensure top level
// Get the rollData stuff
var rollData = this.rollData;
var dialog = this;
// Setup everything onload
$(function () {
$("#forceAlcool").val(Misc.toInt(rollData.forceAlcool));
dialog.updateRollResult();
});
// Update !
html.find('#forceAlcool').change((event) => {
rollData.forceAlcool = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
dialog.updateRollResult();
});
}
async updateRollResult() { async updateRollResult() {
this.html.find(".roll-ethylisme").text(this.rollData.vie + " / " + Misc.toSignedString(Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses));
// Mise à jour valeurs this.html.find(".table-resolution").remove();
$("#roll-param").text(this.rollData.vie + " / " + Misc.toSignedString(Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses));
$(".table-resolution").remove();
} }
} }

View File

@@ -9,12 +9,19 @@ const titleTableDeResolution = 'Table de résolution';
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDRollResolutionTable extends Dialog { export class RdDRollResolutionTable extends Dialog {
static resolutionTable = undefined;
/* -------------------------------------------- */ /* -------------------------------------------- */
static async open(rollData = {}) { static async open() {
RdDRollResolutionTable._setDefaultOptions(rollData); if (RdDRollResolutionTable.resolutionTable == undefined) {
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', rollData); const rollData = {}
const dialog = new RdDRollResolutionTable(rollData, html); RdDRollResolutionTable._setDefaultOptions(rollData);
dialog.render(true); let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', rollData);
RdDRollResolutionTable.resolutionTable = new RdDRollResolutionTable(rollData, html);
RdDRollResolutionTable.resolutionTable.render(true);
}
else{
RdDRollResolutionTable.resolutionTable.bringToTop();
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -53,11 +60,40 @@ export class RdDRollResolutionTable extends Dialog {
'lancer-fermer': { label: 'Lancer les dés et fermer', callback: html => this.onLancerFermer() } 'lancer-fermer': { label: 'Lancer les dés et fermer', callback: html => this.onLancerFermer() }
} }
}; };
super(conf, { classes: ["rdddialog"], width: 800, height: 800, 'z-index': 99999 }); super(conf, { classes: ["rdd-roll-dialog"], top: 50, width: 'fit-content', height: 'fit-content', 'z-index': 99999 });
this.rollData = rollData; this.rollData = rollData;
} }
activateListeners(html) {
super.activateListeners(html);
this.html = html;
this.bringToTop();
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
this.html.find("[name='diffConditions']").val(Misc.toInt(this.rollData.diffConditions));
this.updateRollResult();
this.html.find('.lancer-table-resolution').click((event) => {
this.onLancer();
});
// Update !
this.html.find("[name='diffLibre']").change((event) => {
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value);
this.updateRollResult();
});
this.html.find("[name='diffConditions']").change((event) => {
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value);
this.updateRollResult();
});
this.html.find("[name='carac']").change((event) => {
let caracKey = event.currentTarget.value;
this.rollData.selectedCarac = this.rollData.carac[caracKey];
this.updateRollResult();
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async onLancer() { async onLancer() {
await RdDResolutionTable.rollData(this.rollData); await RdDResolutionTable.rollData(this.rollData);
@@ -72,65 +108,36 @@ export class RdDRollResolutionTable extends Dialog {
await RdDResolutionTable.displayRollData(this.rollData); await RdDResolutionTable.displayRollData(this.rollData);
} }
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.bringToTop();
var dialog = this;
// Setup everything onload
function onLoad(){
$("#diffLibre").val(Misc.toInt(dialog.rollData.diffLibre));
$("#diffConditions").val(Misc.toInt(dialog.rollData.diffConditions));
dialog.updateRollResult();
}
$(function () { onLoad();});
html.find('#lancer').click((event) => {
this.onLancer();
});
// Update !
html.find('#diffLibre').change((event) => {
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value);
this.updateRollResult();
});
html.find('#diffConditions').change((event) => {
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value);
this.updateRollResult();
});
html.find('#carac').change((event) => {
let caracKey = event.currentTarget.value;
this.rollData.selectedCarac = this.rollData.carac[caracKey];
this.updateRollResult();
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateRollResult() { async updateRollResult() {
let rollData = this.rollData; let rollData = this.rollData;
rollData.caracValue = parseInt(rollData.selectedCarac.value) rollData.caracValue = parseInt(rollData.selectedCarac.value)
rollData.finalLevel = this._computeFinalLevel(rollData); rollData.finalLevel = this._computeFinalLevel(rollData);
const htmlTable = await RdDResolutionTable.buildHTMLTable({
carac: rollData.caracValue,
level: rollData.finalLevel,
maxCarac: 20,
maxLevel: 10
});
// Mise à jour valeurs // Mise à jour valeurs
$("#carac").val(rollData.caracValue); this.html.find("[name='carac']").val(rollData.caracValue);
$("#roll-param").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel)); this.html.find(".roll-param-resolution").text(rollData.selectedCarac.value + " / " + Misc.toSignedString(rollData.finalLevel));
$(".table-resolution").remove(); this.html.find("div.placeholder-resolution").empty().append(htmlTable)
$(".table-proba-reussite").remove();
$("#tableResolution").append(RdDResolutionTable.buildHTMLTable(rollData.caracValue, rollData.finalLevel));
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_computeFinalLevel(rollData) { _computeFinalLevel(rollData) {
const diffConditions = Misc.toInt(rollData.diffConditions); const diffConditions = Misc.toInt(rollData.diffConditions);
const diffLibre = this._computeDiffLibre(rollData); const diffLibre = Misc.toInt(rollData.diffLibre);
return diffLibre + diffConditions; return diffLibre + diffConditions;
} }
/* -------------------------------------------- */ async close() {
_computeDiffLibre(rollData) { await super.close();
return Misc.toInt(rollData.diffLibre); RdDRollResolutionTable.resolutionTable = undefined;
} }
} }

View File

@@ -6,7 +6,7 @@ import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js"; import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
/** /**
* Extend the base Dialog entity to select roll parameters * Extend the base Dialog entity to select roll parameters
@@ -16,48 +16,42 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
export class RdDRoll extends Dialog { export class RdDRoll extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async create(actor, rollData, dialogConfig, ...actions) { static async create(actor, rollData, dialogConfig, action) {
RdDRoll._ensureCorrectAction(action);
if (actor.isRollWindowsOpened()) {
ui.notifications.warn("Vous avez déja une fenêtre de Test ouverte, il faut la fermer avant d'en ouvrir une autre.")
return;
}
actor.setRollWindowsOpened(true);
RdDRoll._ensureCorrectActions(actions);
RdDRoll._setDefaultOptions(actor, rollData); RdDRoll._setDefaultOptions(actor, rollData);
const html = await renderTemplate(dialogConfig.html, rollData); const html = await renderTemplate(dialogConfig.html, rollData);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 }; let options = { classes: ["rdd-roll-dialog"], width: 600, height: 'fit-content', 'z-index': 99999, close: html => {} };
if (dialogConfig.options) { if (dialogConfig.close) {
mergeObject(options, dialogConfig.options, { overwrite: true }) options.close = dialogConfig.close;
} }
return new RdDRoll(actor, rollData, html, options, actions, dialogConfig.close); return new RdDRoll(actor, rollData, html, options, action);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _setDefaultOptions(actor, rollData) { static _setDefaultOptions(actor, rollData) {
const actorData = actor.system
let defaultRollData = { let defaultRollData = {
alias: actor.name, alias: actor.name,
ajustementsConditions: CONFIG.RDD.ajustementsConditions, ajustementsConditions: CONFIG.RDD.ajustementsConditions,
difficultesLibres: CONFIG.RDD.difficultesLibres, difficultesLibres: CONFIG.RDD.difficultesLibres,
etat: actor.getEtatGeneral(), etat: actor.getEtatGeneral(),
moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */ moral: actor.getMoralTotal(), /* La valeur du moral pour les jets de volonté */
carac: actorData.carac, carac: actor.system.carac,
finalLevel: 0, finalLevel: 0,
diffConditions: 0, diffConditions: 0,
diffLibre: rollData.competence?.system.default_diffLibre ?? 0, diffLibre: rollData.competence?.system.default_diffLibre ?? 0,
malusArmureValue: actor.getMalusArmure(),
surencMalusFlag: actor.isPersonnage() ? (actorData.compteurs.surenc.value < 0) : false,
surencMalusValue: actor.computeMalusSurEncombrement(),
useMalusSurenc: false,
useMoral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */
perteMoralEchec: false, /* Pour l'affichage dans le chat */ perteMoralEchec: false, /* Pour l'affichage dans le chat */
use: { libre: true, conditions: true, surenc: false, encTotal: false }, use: {
isMalusEncombrementTotal: rollData.competence ? RdDItemCompetence.isMalusEncombrementTotal(rollData.competence) : 0, moral: false, /* Est-ce que le joueur demande d'utiliser le moral ? Utile si le joueur change plusieurs fois de carac associée. */
useMalusEncTotal: false, libre: true,
conditions: true,
surenc: actor.isSurenc(),
encTotal: true
},
isMalusEncombrementTotal: RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
malusArmureValue: actor.getMalusArmure(),
surencMalusValue: actor.computeMalusSurEncombrement(),
encTotal: actor.getEncTotal(), encTotal: actor.getEncTotal(),
ajustementAstrologique: actor.ajustementAstrologique(), ajustementAstrologique: actor.ajustementAstrologique(),
surprise: actor.getSurprise(false), surprise: actor.getSurprise(false),
@@ -66,8 +60,8 @@ export class RdDRoll extends Dialog {
forceDiceResult: -1 forceDiceResult: -1
} }
// Mini patch :Ajout du rêve actuel // Mini patch :Ajout du rêve actuel
if ( actorData.type == "personnage") { if (actor.system.type == "personnage") {
defaultRollData.carac["reve-actuel"] = actorData.reve.reve defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
} }
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false }); mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
@@ -78,6 +72,7 @@ export class RdDRoll extends Dialog {
RollDataAjustements.calcul(rollData, actor); RollDataAjustements.calcul(rollData, actor);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getDiviseurSignificative(rollData) { static getDiviseurSignificative(rollData) {
let facteurSign = 1; let facteurSign = 1;
@@ -96,159 +91,133 @@ export class RdDRoll extends Dialog {
return facteurSign; return facteurSign;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static _ensureCorrectActions(actions) { static _ensureCorrectAction(action) {
if (actions.length == 0) { if (action.callbacks == undefined) {
throw 'No action defined'; console.warn('No callback defined for ', action.name);
action.callbacks = [{ action: r => console.warn(action.name, r) }];
} }
actions.forEach(action => {
if (action.callbacks == undefined) {
action.callbacks = [{ action: r => console.log(action.name, r) }];
}
});
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(actor, rollData, html, options, actions, close = undefined) { constructor(actor, rollData, html, options, action) {
let conf = { let conf = {
title: actions[0].label, title: action.label,
content: html, content: html,
buttons: {}, buttons: {
default: actions[0].name, "onAction": {
close: close label: action.label, callback: html => {
}; this.rollData.canClose = true;
for (let action of actions) { this.onAction(action)
conf.buttons[action.name] = { }
label: action.label, callback: html => {
this.rollData.canClose = true;
this.onAction(action, html)
} }
}; },
} default: "onAction",
close: options.close
};
super(conf, options); super(conf, options);
this.actor = actor; this.actor = actor;
this.rollData = rollData; this.rollData = rollData;
} }
close() {
if (this.rollData.canClose) {
this.actor.setRollWindowsOpened(false);
return super.close();
}
ui.notifications.info("Vous devez faire ce jet de dés!");
}
/* -------------------------------------------- */
async onAction(action, html) {
this.rollData.forceDiceResult = Number.parseInt($('#force-dice-result').val()) ?? -1;
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
this.actor.setRollWindowsOpened(false);
if (action.callbacks)
for (let callback of action.callbacks) {
if (callback.condition == undefined || callback.condition(this.rollData)) {
await callback.action(this.rollData);
}
}
}
/* -------------------------------------------- */
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
this.bringToTop(); this.bringToTop();
var dialog = this; console.log('RdDRoll.activateListeners', this.rollData);
function onLoad() { // Update html, according to rollData
let rollData = dialog.rollData; if (this.rollData.competence) {
console.log('Ouverture RdDRoll', rollData); const defaut_carac = this.rollData.competence.system.defaut_carac
// Update html, according to rollData // Set the default carac from the competence item
if (rollData.competence) { this.rollData.selectedCarac = this.rollData.carac[defaut_carac];
const defaut_carac = rollData.competence.system.defaut_carac this.html.find("[name='carac']").val(defaut_carac);
// Set the default carac from the competence item
rollData.selectedCarac = rollData.carac[defaut_carac];
$("#carac").val(defaut_carac);
}
if (rollData.selectedSort) {
dialog.setSelectedSort(rollData.selectedSort);
$(".draconic").val(rollData.selectedSort.system.listIndex); // Uniquement a la selection du sort, pour permettre de changer
}
RdDItemSort.setCoutReveReel(rollData.selectedSort);
$("#diffLibre").val(Misc.toInt(rollData.diffLibre));
$("#diffConditions").val(Misc.toInt(rollData.diffConditions));
dialog.updateRollResult();
} }
if (this.rollData.selectedSort) {
this.setSelectedSort(this.rollData.selectedSort);
this.html.find(".draconic").val(this.rollData.selectedSort.system.listIndex); // Uniquement a la selection du sort, pour permettre de changer
}
RdDItemSort.setCoutReveReel(this.rollData.selectedSort);
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
this.html.find("[name='diffConditions']").val(Misc.toInt(this.rollData.diffConditions));
this.updateRollResult(html);
// Setup everything onload this.html.find("[name='diffLibre']").change((event) => {
$(function () { onLoad(); });
// Update !
html.find('#diffLibre').change((event) => {
this.rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus this.rollData.diffLibre = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('#diffConditions').change((event) => { this.html.find("[name='diffConditions']").change((event) => {
this.rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus this.rollData.diffConditions = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('#force-dice-result').change((event) => { this.html.find("[name='force-dice-result']").change((event) => {
this.rollData.forceDiceResult = Misc.toInt(event.currentTarget.value); this.rollData.forceDiceResult = Misc.toInt(event.currentTarget.value);
}); });
html.find('#carac').change((event) => { this.html.find("[name='carac']").change((event) => {
let caracKey = event.currentTarget.value; let caracKey = event.currentTarget.value;
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.roll-draconic').change((event) => { this.html.find('.roll-draconic').change((event) => {
let draconicKey = Misc.toInt(event.currentTarget.value); let draconicKey = Misc.toInt(event.currentTarget.value);
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.roll-sort').change((event) => { this.html.find('.roll-sort').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value); let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSort(this.rollData.sortList[sortKey]); this.setSelectedSort(this.rollData.sortList[sortKey]);
this.updateRollResult(); this.updateRollResult(html);
$("#diffLibre").val(this.rollData.diffLibre); this.html.find("[name='diffLibre']").val(this.rollData.diffLibre);
}); });
html.find('.roll-signedraconique').change((event) => { this.html.find('.roll-carac-competence').change((event) => {
const competence = event.currentTarget.value;
this.rollData.competence = this.rollData.competences.find(it => it.name == competence);
this.updateRollResult(html);
});
this.html.find('.roll-signedraconique').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value); let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]); this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('#ptreve-variable').change((event) => { this.html.find("[name='ptreve-variable']").change((event) => {
let ptreve = Misc.toInt(event.currentTarget.value); let ptreve = Misc.toInt(event.currentTarget.value);
this.rollData.selectedSort.system.ptreve_reel = ptreve; this.rollData.selectedSort.system.ptreve_reel = ptreve;
console.log("RdDRollSelectDialog - Cout reve", ptreve); console.log("RdDRollSelectDialog - Cout reve", ptreve);
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find("[name='coupsNonMortels']").change((event) => { this.html.find("[name='coupsNonMortels']").change((event) => {
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel"; this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.cuisine-proportions').change((event) => { this.html.find('.cuisine-proportions').change((event) => {
this.rollData.proportions = Number(event.currentTarget.value); this.rollData.proportions = Number(event.currentTarget.value);
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.select-by-name').change((event) => { this.html.find('.select-by-name').change((event) => {
const attribute = event.currentTarget.attributes['name'].value; const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.value; this.rollData[attribute] = event.currentTarget.value;
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.checkbox-by-name').change((event) => { this.html.find('.checkbox-by-name').change((event) => {
const attribute = event.currentTarget.attributes['name'].value; const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.checked; this.rollData[attribute] = event.currentTarget.checked;
this.updateRollResult(); this.updateRollResult(html);
}); });
html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */ this.html.find('input.use-encTotal').change((event) => {
this.rollData.useMoral = !this.rollData.useMoral; this.rollData.use.encTotal = event.currentTarget.checked;
const appelMoral = html.find('.icon-appel-moral')[0]; this.updateRollResult(html);
const tooltip = html.find('.tooltipAppelAuMoralText')[0]; });
if (this.rollData.useMoral) { this.html.find('input.use-surenc').change((event) => {
this.rollData.use.surenc = event.currentTarget.checked;
this.updateRollResult(html);
});
this.html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
this.rollData.use.moral = !this.rollData.use.moral;
const appelMoral = this.html.find('.icon-appel-moral')[0];
const tooltip = this.html.find('.tooltipAppelAuMoralText')[0];
if (this.rollData.use.moral) {
if (this.rollData.moral > 0) { if (this.rollData.moral > 0) {
tooltip.innerHTML = "Appel au moral"; tooltip.innerHTML = "Appel au moral";
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg"; appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg";
@@ -260,16 +229,36 @@ export class RdDRoll extends Dialog {
tooltip.innerHTML = "Sans appel au moral"; tooltip.innerHTML = "Sans appel au moral";
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg"; appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg";
} }
this.updateRollResult(); this.updateRollResult(html);
}); });
// Section Méditation // Section Méditation
html.find('.conditionMeditation').change((event) => { this.html.find('.conditionMeditation').change((event) => {
let condition = event.currentTarget.attributes['id'].value; let condition = event.currentTarget.attributes['name'].value;
this.rollData.conditionMeditation[condition] = event.currentTarget.checked; this.rollData.conditionMeditation[condition] = event.currentTarget.checked;
this.updateRollResult(); this.updateRollResult(html);
}); });
} }
/* -------------------------------------------- */
close() {
if (this.rollData.canClose) {
return super.close();
}
ui.notifications.info("Vous devez faire ce jet de dés!");
}
async onAction(action) {
this.rollData.forceDiceResult = Number.parseInt(this.html.find("[name='force-dice-result']").val()) ?? -1;
await RdDResolutionTable.rollData(this.rollData);
console.log("RdDRoll -=>", this.rollData, this.rollData.rolled);
if (action.callbacks)
for (let callback of action.callbacks) {
if (callback.condition == undefined || callback.condition(this.rollData)) {
await callback.action(this.rollData);
}
}
}
async setSelectedSort(sort) { async setSelectedSort(sort) {
this.rollData.selectedSort = sort; // Update the selectedCarac this.rollData.selectedSort = sort; // Update the selectedCarac
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.system.draconic); this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.system.draconic);
@@ -277,30 +266,31 @@ export class RdDRoll extends Dialog {
this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7); this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7);
RdDItemSort.setCoutReveReel(sort); RdDItemSort.setCoutReveReel(sort);
const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort }); const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort });
$(".sort-ou-rituel").text(sort.system.isrituel ? "rituel" : "sort"); this.html.find(".sort-ou-rituel").text(sort.system.isrituel ? "rituel" : "sort");
$(".bonus-case").text(`${this.rollData.bonus}%`); this.html.find(".bonus-case").text(`${this.rollData.bonus}%`);
$(".details-sort").remove(); this.html.find(".placeholder-description-sort").children().remove();
$(".description-sort").append(htmlSortDescription); this.html.find(".placeholder-description-sort").append(htmlSortDescription);
$(".roll-draconic").val(sort.system.listIndex); this.html.find(".roll-draconic").val(sort.system.listIndex);
$(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.system.difficulte)); this.html.find(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.system.difficulte));
$(".div-sort-ptreve-fixe").text(sort.system.ptreve); this.html.find(".div-sort-ptreve-fixe").text(sort.system.ptreve);
const diffVariable = RdDItemSort.isDifficulteVariable(sort); const diffVariable = RdDItemSort.isDifficulteVariable(sort);
const coutVariable = RdDItemSort.isCoutVariable(sort); const coutVariable = RdDItemSort.isCoutVariable(sort);
HtmlUtility._showControlWhen($(".div-sort-non-rituel"), !sort.system.isrituel);
HtmlUtility._showControlWhen($(".div-sort-difficulte-var"), diffVariable); HtmlUtility._showControlWhen(this.html.find(".div-sort-non-rituel"), !sort.system.isrituel);
HtmlUtility._showControlWhen($(".div-sort-difficulte-fixe"), !diffVariable); HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-var"), diffVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-var"), coutVariable); HtmlUtility._showControlWhen(this.html.find(".div-sort-difficulte-fixe"), !diffVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable); HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-var"), coutVariable);
HtmlUtility._showControlWhen(this.html.find(".div-sort-ptreve-fixe"), !coutVariable);
} }
async setSelectedSigneDraconique(signe){ async setSelectedSigneDraconique(signe) {
this.rollData.signe = signe; this.rollData.signe = signe;
this.rollData.diffLibre = signe.system.difficulte, this.rollData.diffLibre = signe.system.difficulte,
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre)); $(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async updateRollResult() { async updateRollResult(html) {
let rollData = this.rollData; let rollData = this.rollData;
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat()) rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat())
@@ -310,36 +300,35 @@ export class RdDRoll extends Dialog {
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac); rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
let dmgText = Misc.toSignedString(rollData.dmg.total); let dmgText = Misc.toSignedString(rollData.dmg.total);
switch (rollData.mortalite){ switch (rollData.mortalite) {
case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break; case 'non-mortel': dmgText = `(${dmgText}) non-mortel`; break;
case 'empoignade': dmgText = `empoignade`; break; case 'empoignade': dmgText = `empoignade`; break;
} }
RollDataAjustements.calcul(rollData, this.actor); RollDataAjustements.calcul(rollData, this.actor);
rollData.finalLevel = this._computeFinalLevel(rollData); rollData.finalLevel = this._computeFinalLevel(rollData);
HtmlUtility._showControlWhen($(".diffMoral"), rollData.ajustements.moralTotal.used); const resolutionTable = await RdDResolutionTable.buildHTMLTable(RdDResolutionTable.subTable(rollData.caracValue, rollData.finalLevel))
HtmlUtility._showControlWhen($(".divAppelAuMoral"), rollData.use.appelAuMoral); const adjustements = await this.buildAjustements(rollData);
HtmlUtility._showControlWhen($("#etat-general"), !RdDCarac.isIgnoreEtatGeneral(rollData));
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData)); HtmlUtility._showControlWhen(this.html.find(".use-encTotal"), rollData.ajustements.encTotal.visible && RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac));
HtmlUtility._showControlWhen(this.html.find(".use-surenc"), rollData.ajustements.surenc.visible && RdDCarac.isActionPhysique(rollData.selectedCarac));
HtmlUtility._showControlWhen(this.html.find(".utilisation-moral"), rollData.use.appelAuMoral);
HtmlUtility._showControlWhen(this.html.find(".diffMoral"), rollData.ajustements.moralTotal.used);
HtmlUtility._showControlWhen(this.html.find(".divAppelAuMoral"), rollData.use.appelAuMoral);
// Mise à jour valeurs // Mise à jour valeurs
$(".dialog-roll-title").text(this._getTitle(rollData)); this.html.find(".dialog-roll-title").text(this._getTitle(rollData));
$("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel'); this.html.find("[name='coupsNonMortels']").prop('checked', rollData.mortalite == 'non-mortel');
$(".dmg-arme-actor").text(dmgText); this.html.find(".dmg-arme-actor").text(dmgText);
$('.table-ajustement').remove(); this.html.find("div.placeholder-ajustements").empty().append(adjustements);
$(".table-resolution").remove(); this.html.find("div.placeholder-resolution").empty().append(resolutionTable)
$(".table-proba-reussite").remove();
$("#tableAjustements").append(await this.buildAjustements(rollData));
$("#tableResolution").append(RdDResolutionTable.buildHTMLTableExtract(rollData.caracValue, rollData.finalLevel));
$("#tableProbaReussite").append(RdDResolutionTable.buildHTMLResults(rollData.caracValue, rollData.finalLevel));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async buildAjustements(rollData) { async buildAjustements(rollData) {
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData); return await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
return html;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -357,23 +346,11 @@ export class RdDRoll extends Dialog {
return 0; return 0;
} }
/* -------------------------------------------- */
_computeDiffLibre(rollData) {
let diffLibre = Misc.toInt(rollData.diffLibre);
if (rollData.draconicList && rollData.selectedSort) {
return RdDItemSort.getDifficulte(rollData.selectedSort, diffLibre);
}
return diffLibre;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
_computeMalusArmure(rollData) { _computeMalusArmure(rollData) {
let malusArmureValue = 0; let malusArmureValue = 0;
if (rollData.malusArmureValue && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) { if (rollData.malusArmureValue && (rollData.selectedCarac.label == "Agilité" || rollData.selectedCarac.label == "Dérobée")) {
$("#addon-message").text("Malus armure appliqué : " + rollData.malusArmureValue);
malusArmureValue = rollData.malusArmureValue; malusArmureValue = rollData.malusArmureValue;
} else {
$("#addon-message").text("");
} }
return malusArmureValue; return malusArmureValue;
} }

View File

@@ -1,12 +1,13 @@
import { Grammar } from "./grammar.js";
import { CompendiumTable, CompendiumTableHelpers, SystemCompendiums } from "./settings/system-compendiums.js";
export class RdDRollTables { export class RdDRollTables {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async genericGetTableResult(tableName, toChat) { static async genericGetTableResult(tableName, toChat) {
let table = RdDRollTables.getWorldTable(tableName) ?? (await RdDRollTables.getSystemTable(tableName)); let table = RdDRollTables.getWorldTable(tableName) ?? (await RdDRollTables.getSystemTable(tableName));
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"}); const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll" });
//console.log("RdDRollTables", tableName, toChat, ":", draw);
return draw.results.length > 0 ? draw.results[0] : undefined; return draw.results.length > 0 ? draw.results[0] : undefined;
} }
static getWorldTable(tableName) { static getWorldTable(tableName) {
@@ -14,7 +15,7 @@ export class RdDRollTables {
} }
static async getSystemTable(tableName) { static async getSystemTable(tableName) {
const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses"); const pack = SystemCompendiums.getPack("tables-diverses");
const index = await pack.getIndex(); const index = await pack.getIndex();
const entry = index.find(e => e.name === tableName); const entry = index.find(e => e.name === tableName);
return await pack.getDocument(entry._id); return await pack.getDocument(entry._id);
@@ -24,10 +25,9 @@ export class RdDRollTables {
static async drawItemFromRollTable(tableName, toChat = false) { static async drawItemFromRollTable(tableName, toChat = false) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const pack = game.packs.get(drawResult.documentCollection) const pack = game.packs.get(drawResult.documentCollection)
let doc = await pack.getDocument(drawResult.documentId) return await pack.getDocument(drawResult.documentId)
return doc
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async drawTextFromRollTable(tableName, toChat) { static async drawTextFromRollTable(tableName, toChat) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat); const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
@@ -36,58 +36,74 @@ export class RdDRollTables {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getCompetence(toChat = false) { static async getCompetence(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat); if (toChat == 'liste') {
return await RdDRollTables.listOrRoll('competences', 'Item', ['competence'], toChat, it => 1);
}
else {
return await RdDRollTables.drawItemFromRollTable("Détermination aléatoire de compétence", toChat);
}
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getSouffle(toChat = false) { static async getSouffle(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Souffles de Dragon", toChat); return await RdDRollTables.listOrRoll('souffles-de-dragon', 'Item', ['souffle'], toChat);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getQueue(toChat = false) { static async getQueue(toChat = false) {
let queue = await RdDRollTables.drawItemFromRollTable("Queues de dragon", toChat); return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat);
if (queue.name.toLowerCase().includes('lancinant') ) {
return await RdDRollTables.getDesirLancinant(toChat);
}
if (queue.name.toLowerCase().includes('fixe') ) {
return await RdDRollTables.getIdeeFixe(toChat);
}
return queue;
} }
static async getDesirLancinant(toChat = false) { static async getDesirLancinant(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Désirs lancinants", toChat); return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
it => it.system.frequence,
it => it.system.categorie == 'lancinant');
} }
static async getIdeeFixe(toChat = false) { static async getIdeeFixe(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Idées fixes", toChat); return await RdDRollTables.listOrRoll('queues-de-dragon', 'Item', ['queue'], toChat,
it => it.system.frequence,
it => it.system.categorie == 'ideefixe');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getTeteHR(toChat = false) { static async getTeteHR(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour haut-rêvants", toChat); return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-haut-revants', 'Item', ['tete'], toChat);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getTete(toChat = false) { static async getTete(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Têtes de Dragon pour tous personnages", toChat); return await RdDRollTables.listOrRoll('tetes-de-dragon-pour-tous-personnages', 'Item', ['tete'], toChat);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getOmbre(toChat = false) { static async getOmbre(toChat = false) {
return await RdDRollTables.drawItemFromRollTable("Ombre de Thanatos", toChat); return await RdDRollTables.listOrRoll('ombres-de-thanatos', 'Item', ['ombre'], toChat);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getTarot(toChat = true) { static async getTarot(toChat = true) {
return await RdDRollTables.drawItemFromRollTable("Tarot Draconique", toChat); return await RdDRollTables.listOrRoll('tarot-draconique', 'Item', ['tarot'], toChat);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getMaladresse(options = {toChat: false, arme: false}) { static async listOrRoll(compendium, type, subTypes, toChat, itemFrequence = it => it.system.frequence, filter = it => true) {
const table = new CompendiumTable(compendium, type, subTypes);
if (toChat == 'liste') {
return await table.toChatMessage(itemFrequence, filter);
}
const row = await table.getRandom(itemFrequence, filter);
if (row) {
await CompendiumTableHelpers.tableRowToChatMessage(row, type);
}
return row;
}
/* -------------------------------------------- */
static async getMaladresse(options = { toChat: false, arme: false }) {
return await RdDRollTables.drawTextFromRollTable( return await RdDRollTables.drawTextFromRollTable(
options.arme ? "Maladresse armé" : "Maladresses non armé", options.arme ? "Maladresse armé" : "Maladresses non armé",
options.toChat); options.toChat);
} }
} }

View File

@@ -19,17 +19,23 @@ export class RdDSheetUtility {
return $(event.currentTarget)?.parents(".item"); return $(event.currentTarget)?.parents(".item");
} }
static prepareItemDropParameters(destItemId, actorId, dragData, objetVersConteneur) { static prepareItemDropParameters(destItemId, actor, dragData, objetVersConteneur) {
const item = fromUuidSync(dragData.uuid) const item = fromUuidSync(dragData.uuid)
return { if (actor.canReceive(item)) {
destId: destItemId, return {
targetActorId: actorId, destId: destItemId,
itemId: item.id, targetActorId: actor.id,
sourceActorId: item.actor?.id, itemId: item.id,
srcId: objetVersConteneur[item.id], sourceActorId: item.actor?.id,
onEnleverConteneur: () => { delete objetVersConteneur[item.id]; }, srcId: objetVersConteneur[item.id],
onAjouterDansConteneur: (itemId, conteneurId) => { objetVersConteneur[itemId] = conteneurId; } onEnleverConteneur: () => { delete objetVersConteneur[item.id]; },
onAjouterDansConteneur: (itemId, conteneurId) => { objetVersConteneur[itemId] = conteneurId; }
}
} }
else {
ui.notifications.warn(`Impossible de donner ${item.name} à ${actor.name}: ${item.type} / ${actor.type}`);
}
return undefined;
} }
static async splitItem(item, actor, onSplit = () => { }) { static async splitItem(item, actor, onSplit = () => { }) {

View File

@@ -1,26 +1,29 @@
import { SHOW_DICE } from "./constants.js";
import { RollDataAjustements } from "./rolldata-ajustements.js"; import { RollDataAjustements } from "./rolldata-ajustements.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 { tmrConstants } from "./tmr-constants.js"; import { tmrConstants } from "./tmr-constants.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js"; import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js"; import { RdDTMRRencontreDialog } from "./rdd-tmr-rencontre-dialog.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { RdDRoll } from "./rdd-roll.js"; import { RdDRoll } from "./rdd-roll.js";
import { Poetique } from "./poetique.js"; import { Poetique } from "./poetique.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"; import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { PixiTMR } from "./tmr/pixi-tmr.js"; import { PixiTMR } from "./tmr/pixi-tmr.js";
import { Draconique } from "./tmr/draconique.js"; import { Draconique } from "./tmr/draconique.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js"; import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { STATUSES } from "./status-effects.js"; import { STATUSES } from "./settings/status-effects.js";
import { RdDRencontre } from "./item-rencontre.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
export class RdDTMRDialog extends Dialog { export class RdDTMRDialog extends Dialog {
static async create(html, actor, tmrData) { static async create(actor, tmrData) {
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', tmrData);
if (tmrData.mode != 'visu') { if (tmrData.mode != 'visu') {
// Notification au MJ // Notification au MJ
@@ -89,7 +92,7 @@ export class RdDTMRDialog extends Dialog {
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
); );
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -146,7 +149,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
_tokenRencontre(rencontre) { _tokenRencontre(rencontre) {
return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.coord); return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.system.coord);
} }
_tokenCaseSpeciale(casetmr) { _tokenCaseSpeciale(casetmr) {
const caseData = casetmr; const caseData = casetmr;
@@ -194,32 +197,33 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async activateListeners(html) { async activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
this.html = html;
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view); document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) { if (this.viewOnly) {
html.find('.lancer-sort').remove(); this.html.find('.lancer-sort').remove();
html.find('.lire-signe-draconique').remove(); this.html.find('.lire-signe-draconique').remove();
return; return;
} }
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue")); HtmlUtility._showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord())); HtmlUtility._showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord()));
// Roll Sort // Roll Sort
html.find('.lancer-sort').click((event) => { this.html.find('.lancer-sort').click((event) => {
this.actor.rollUnSort(this._getActorCoord()); this.actor.rollUnSort(this._getActorCoord());
}); });
html.find('.lire-signe-draconique').click((event) => { this.html.find('.lire-signe-draconique').click((event) => {
this.actor.rollLireSigneDraconique(this._getActorCoord()); this.actor.rollLireSigneDraconique(this._getActorCoord());
}); });
html.find('#dir-top').click((event) => this.moveFromKey("top")); this.html.find('#dir-top').click((event) => this.moveFromKey("top"));
html.find('#dir-top-left').click((event) => this.moveFromKey("top-left")); this.html.find('#dir-top-left').click((event) => this.moveFromKey("top-left"));
html.find('#dir-top-right').click((event) => this.moveFromKey("top-right")); this.html.find('#dir-top-right').click((event) => this.moveFromKey("top-right"));
html.find('#dir-bottom-left').click((event) => this.moveFromKey("bottom-left")); this.html.find('#dir-bottom-left').click((event) => this.moveFromKey("bottom-left"));
html.find('#dir-bottom-right').click((event) => this.moveFromKey("bottom-right")); this.html.find('#dir-bottom-right').click((event) => this.moveFromKey("bottom-right"));
html.find('#dir-bottom').click((event) => this.moveFromKey("bottom")); this.html.find('#dir-bottom').click((event) => this.moveFromKey("bottom"));
// Gestion du cout de montée en points de rêve // Gestion du cout de montée en points de rêve
let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse(); let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse();
@@ -241,14 +245,14 @@ export class RdDTMRDialog extends Dialog {
} }
const coord = this._getActorCoord(); const coord = this._getActorCoord();
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord)); HtmlUtility._showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
let ptsreve = document.getElementById("tmr-pointsreve-value"); let ptsreve = document.getElementById("tmr-pointsreve-value");
ptsreve.innerHTML = this.actor.system.reve.reve.value; ptsreve.innerHTML = this.actor.system.reve.reve.value;
let tmrpos = document.getElementById("tmr-pos"); let tmrpos = document.getElementById("tmr-pos");
if (this.isDemiReveCache()) { if (this.isDemiReveCache()) {
tmrpos.innerHTML = `?? ( ${ TMRUtility.getTMRType(coord)})`; tmrpos.innerHTML = `?? ( ${TMRUtility.getTMRType(coord)})`;
} else { } else {
tmrpos.innerHTML = `${coord} ( ${TMRUtility.getTMRLabel(coord)})`; tmrpos.innerHTML = `${coord} ( ${TMRUtility.getTMRLabel(coord)})`;
} }
@@ -276,29 +280,48 @@ export class RdDTMRDialog extends Dialog {
} }
await this.actor.santeIncDec("fatigue", this.cumulFatigue) await this.actor.santeIncDec("fatigue", this.cumulFatigue)
} }
await super.close(); // moving 1 cell costs 1 fatigue await super.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async onActionRencontre(action, tmr) {
switch (action) {
case 'derober':
await this.derober();
return;
case 'refouler':
await this.refouler();
break;
case 'maitriser':
await this.maitriserRencontre();
break;
case 'ignorer':
await this.ignorerRencontre();
break;
}
await this.postRencontre(tmr);
}
async derober() { async derober() {
await this.actor.addTMRRencontre(this.currentRencontre);
console.log("-> derober", this.currentRencontre); console.log("-> derober", this.currentRencontre);
await this.actor.addTMRRencontre(this.currentRencontre);
this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR."); this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR.");
this.close(); this.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async refouler() { async refouler() {
await this.actor.ajouterRefoulement(this.currentRencontre.refoulement ?? 1, `une rencontre ${this.currentRencontre.name}`); console.log("-> refouler", this.currentRencontre);
await this.actor.ajouterRefoulement(this.currentRencontre.system.refoulement, `${this.currentRencontre.system.genre == 'f' ? 'une' : 'un'} ${this.currentRencontre.name}`);
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
this.updateTokens(); this.updateTokens();
console.log("-> refouler", this.currentRencontre)
this.updateValuesDisplay(); this.updateValuesDisplay();
this.nettoyerRencontre(); this.nettoyerRencontre();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async ignorerRencontre() { async ignorerRencontre() {
console.log("-> ignorer", this.currentRencontre);
this._tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name); this._tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name);
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
this.updateTokens(); this.updateTokens();
@@ -307,7 +330,14 @@ export class RdDTMRDialog extends Dialog {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
colorierZoneRencontre(listCoordTMR) { // garder la trace de l'état en cours
setRencontreState(state, listCoordTMR) {
this.rencontreState = state;
this.$marquerCasesTMR(listCoordTMR ?? []);
}
/* -------------------------------------------- */
$marquerCasesTMR(listCoordTMR) {
this.currentRencontre.graphics = []; // Keep track of rectangles to delete it this.currentRencontre.graphics = []; // Keep track of rectangles to delete it
this.currentRencontre.locList = duplicate(listCoordTMR); // And track of allowed location this.currentRencontre.locList = duplicate(listCoordTMR); // And track of allowed location
for (let coordTMR of listCoordTMR) { for (let coordTMR of listCoordTMR) {
@@ -323,23 +353,6 @@ export class RdDTMRDialog extends Dialog {
} }
} }
/* -------------------------------------------- */
// garder la trace de l'état en cours
setStateRencontre(state) {
this.rencontreState = state;
}
/* -------------------------------------------- */
async choisirCasePortee(coord, portee) {
// Récupère la liste des cases à portées
this.colorierZoneRencontre(TMRUtility.getTMRPortee(coord, portee));
}
/* -------------------------------------------- */
async choisirCaseType(type) {
this.colorierZoneRencontre(TMRUtility.filterTMR(it => it.type == type).map(it => it.coord));
}
/* -------------------------------------------- */ /* -------------------------------------------- */
checkQuitterTMR() { checkQuitterTMR() {
@@ -364,15 +377,15 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async quitterLesTMRInconscient() { async quitterLesTMRInconscient() {
if (this.currentRencontre?.isPersistant) { await this.refouler();
await this.refouler();
}
this.close(); this.close();
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async maitriserRencontre() { async maitriserRencontre() {
this.actor.deleteTMRRencontreAtPosition(); console.log("-> maitriser", this.currentRencontre);
await this.actor.deleteTMRRencontreAtPosition();
this.updateTokens(); this.updateTokens();
let rencontreData = { let rencontreData = {
@@ -383,7 +396,7 @@ export class RdDTMRDialog extends Dialog {
rencontre: this.currentRencontre, rencontre: this.currentRencontre,
nbRounds: 1, nbRounds: 1,
canClose: false, canClose: false,
selectedCarac: {label: "reve-actuel"}, selectedCarac: { label: "reve-actuel" },
tmr: TMRUtility.getTMR(this._getActorCoord()) tmr: TMRUtility.getTMR(this._getActorCoord())
} }
@@ -392,8 +405,6 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _tentativeMaitrise(rencData) { async _tentativeMaitrise(rencData) {
console.log("-> matriser", rencData);
rencData.reve = this.actor.getReveActuel(); rencData.reve = this.actor.getReveActuel();
rencData.etat = this.actor.getEtatGeneral(); rencData.etat = this.actor.getEtatGeneral();
@@ -403,41 +414,67 @@ export class RdDTMRDialog extends Dialog {
? this._rollPresentCite(rencData) ? this._rollPresentCite(rencData)
: await RdDResolutionTable.roll(rencData.reve, RollDataAjustements.sum(rencData.ajustements)); : await RdDResolutionTable.roll(rencData.reve, RollDataAjustements.sum(rencData.ajustements));
let postProcess = await TMRRencontres.gererRencontre(this, rencData); const result = rencData.rolled.isSuccess
? rencData.rencontre.system.succes
: rencData.rencontre.system.echec;
await RdDRencontre.appliquer(result.effets, this, rencData);
rencData.poesie = { extrait: result.poesie, reference: result.reference };
rencData.message = this.formatMessageRencontre(rencData, result.message);
ChatMessage.create({ ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name), whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
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)
}); });
if (postProcess) {
/** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */
await postProcess(this, rencData);
}
else {
this.currentRencontre = undefined;
}
this.updateValuesDisplay(); this.updateValuesDisplay();
if (this.checkQuitterTMR()) { if (this.checkQuitterTMR()) {
return; return;
} }
else if (rencData.rolled.isEchec && rencData.rencontre.isPersistant) { if (this.rencontreState == 'persistant') {
setTimeout(() => { this._nouvelleTentativeMaitrise(rencData);
rencData.nbRounds++; }
if (ReglesOptionelles.isUsing("appliquer-fatigue")) { else if (!this.isRencontreDeplacement()) {
this.cumulFatigue += this.fatigueParCase; this.nettoyerRencontre();
} }
this._tentativeMaitrise(rencData); }
this._deleteTmrMessages(rencData.actor, rencData.nbRounds);
}, 2000); _nouvelleTentativeMaitrise(rencData) {
setTimeout(() => {
// TODO: remplacer par une boucle while(this.currentRencontre) ?
rencData.nbRounds++;
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
this._tentativeMaitrise(rencData);
this._deleteTmrMessages(rencData.actor, rencData.nbRounds);
}, 2000);
this.rencontreState == 'normal';
}
formatMessageRencontre(rencData, template) {
let messageDuree = ''
if (rencData.nbRounds > 1) {
if (rencData.rolled.isSuccess) {
messageDuree = ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`;
}
else {
messageDuree = ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`;
}
}
try {
const compiled = Handlebars.compile(template);
return compiled(rencData) + messageDuree ;
} catch (error) {
return template + messageDuree ;
} }
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
_rollPresentCite(rencontreData) { _rollPresentCite(rencData) {
let rolled = RdDResolutionTable.computeChances(rencontreData.reve, 0); let rolled = RdDResolutionTable.computeChances(rencData.reve, 0);
mergeObject(rolled, { caracValue: rencontreData.reve, finalLevel: 0, roll: rolled.score }); mergeObject(rolled, { caracValue: rencData.reve, finalLevel: 0, roll: rolled.score });
RdDResolutionTable.succesRequis(rolled); RdDResolutionTable.succesRequis(rolled);
return rolled; return rolled;
} }
@@ -481,15 +518,16 @@ export class RdDTMRDialog extends Dialog {
if (this._presentCite(tmr)) { if (this._presentCite(tmr)) {
return; return;
} }
let rencontre = await this._jetDeRencontre(tmr); this.currentRencontre = await this._jetDeRencontre(tmr);
if (this.currentRencontre) {
if (rencontre) { // Manages it if (this.rencontresExistantes.find(it => it.id == this.currentRencontre.id)){
if (rencontre.rencontre) rencontre = rencontre.rencontre; // Manage stored rencontres // rencontre en attente suite à dérobade
console.log("manageRencontre", rencontre); await this.maitriserRencontre();
this.currentRencontre = duplicate(rencontre); }
else {
let dialog = new RdDTMRRencontreDialog(this, this.currentRencontre, () => this.postRencontre(tmr)); let dialog = new RdDTMRRencontreDialog(this, this.currentRencontre, tmr);
dialog.render(true); dialog.render(true);
}
} }
else { else {
this.postRencontre(tmr); this.postRencontre(tmr);
@@ -502,15 +540,18 @@ export class RdDTMRDialog extends Dialog {
if (presentCite) { if (presentCite) {
this.minimize(); this.minimize();
const caseData = presentCite; const caseData = presentCite;
EffetsDraconiques.presentCites.choisirUnPresent(caseData, (type => this._utiliserPresentCite(presentCite, type, tmr))); EffetsDraconiques.presentCites.choisirUnPresent(caseData, (present => this._utiliserPresentCite(presentCite, present, tmr)));
} }
return presentCite; return presentCite;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async _utiliserPresentCite(presentCite, typeRencontre, tmr) { async _utiliserPresentCite(presentCite, present, tmr) {
this.currentRencontre = TMRRencontres.getRencontre(typeRencontre); this.currentRencontre = present.clone({
await TMRRencontres.evaluerForceRencontre(this.currentRencontre); 'system.force': await RdDDice.rollTotal(present.system.formule),
'system.coord': tmr.coord
}, {save: false});
await EffetsDraconiques.presentCites.ouvrirLePresent(this.actor, presentCite); await EffetsDraconiques.presentCites.ouvrirLePresent(this.actor, presentCite);
this.removeToken(tmr, presentCite); this.removeToken(tmr, presentCite);
@@ -532,33 +573,26 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
async _jetDeRencontre(tmr) { async _jetDeRencontre(tmr) {
let rencontre = this.rencontresExistantes.find(prev => prev.coord == tmr.coord); let rencontre = this.lookupRencontreExistente(tmr);
if (rencontre) { if (rencontre) {
return rencontre; return game.system.rdd.rencontresTMR.calculRencontre(rencontre, tmr);
} }
let locTMR = (this.isDemiReveCache() let locTMR = (this.isDemiReveCache()
? Misc.upperFirst(tmr.type) + " ??" ? TMRUtility.getTMRType(tmr.coord) + " ??"
: tmr.label + " (" + tmr.coord + ")"); : tmr.label + " (" + tmr.coord + ")");
let myRoll = await RdDDice.rollTotal("1dt"); let myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE });
if (TMRUtility.isForceRencontre() || myRoll == 7) { if (myRoll == 7) {
this._tellToUser(myRoll + ": Rencontre en " + locTMR); this._tellToUser(myRoll + ": Rencontre en " + locTMR);
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale()); return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre())
} else { } else {
this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR); this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR);
} }
} }
/* -------------------------------------------- */ lookupRencontreExistente(tmr) {
async rencontreTMRRoll(tmr, isMauvaise = false) { return this.rencontresExistantes.find(it => it.system.coord == tmr.coord)
let rencontre = TMRUtility.utiliseForceRencontre() ?? ?? this.rencontresExistantes.find(it => it.system.coord == "");
(isMauvaise
? await TMRRencontres.getMauvaiseRencontre()
: await TMRRencontres.getRencontreAleatoire(tmr.type));
rencontre.coord = tmr.coord;
rencontre.date = game.system.rdd.calendrier.getDateFromIndex();
rencontre.heure = game.system.rdd.calendrier.getCurrentHeure();
return rencontre;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -586,7 +620,7 @@ export class RdDTMRDialog extends Dialog {
maitrise: { verbe: 'maîtriser', action: 'Maîtriser le fleuve' } maitrise: { verbe: 'maîtriser', action: 'Maîtriser le fleuve' }
} }
rollData.double = EffetsDraconiques.isDoubleResistanceFleuve(this.actor) ? true : undefined, rollData.double = EffetsDraconiques.isDoubleResistanceFleuve(this.actor) ? true : undefined,
rollData.competence.system.defaut_carac = 'reve-actuel'; rollData.competence.system.defaut_carac = 'reve-actuel';
await this._rollMaitriseCaseHumide(rollData); await this._rollMaitriseCaseHumide(rollData);
} }
} }
@@ -741,7 +775,6 @@ export class RdDTMRDialog extends Dialog {
const dialog = await RdDRoll.create(this.actor, rollData, const dialog = await RdDRoll.create(this.actor, rollData,
{ {
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html', html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html',
options: { height: 420 },
close: html => { this.maximize(); } // Re-display TMR close: html => { this.maximize(); } // Re-display TMR
}, },
{ {
@@ -806,12 +839,13 @@ export class RdDTMRDialog extends Dialog {
async processSortReserve(sortReserve) { async processSortReserve(sortReserve) {
await this.actor.deleteEmbeddedDocuments('Item', [sortReserve.id]); await this.actor.deleteEmbeddedDocuments('Item', [sortReserve.id]);
console.log("declencheSortEnReserve", sortReserve); console.log("declencheSortEnReserve", sortReserve);
const heureCible = RdDCalendrier.getSigneAs('label', sortReserve.system.heurecible);
this._tellToUserAndGM(`Vous avez déclenché this._tellToUserAndGM(`Vous avez déclenché
${sortReserve.system.echectotal ? "<strong>l'échec total!</strong>" : "le sort"} ${sortReserve.system.echectotal ? "<strong>l'échec total!</strong>" : "le sort"}
en réserve <strong>${sortReserve.name}</strong> en réserve <strong>${sortReserve.name}</strong>
avec ${sortReserve.system.ptreve} points de Rêve avec ${sortReserve.system.ptreve} points de Rêve
en ${sortReserve.system.coord} (${TMRUtility.getTMRLabel(sortReserve.system.coord)}). en ${sortReserve.system.coord} (${TMRUtility.getTMRLabel(sortReserve.system.coord)}).
L'heure ciblée est ${sortReserve.system.heurecible}`); L'heure ciblée est ${heureCible}`);
this.close(); this.close();
} }
@@ -877,16 +911,14 @@ export class RdDTMRDialog extends Dialog {
if (this.isDemiReveCache()) { if (this.isDemiReveCache()) {
if (this.isTerreAttache(targetCoord) if (this.isTerreAttache(targetCoord)
|| this.isConnaissanceFleuve(currentCoord, targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord)
|| deplacementType == 'changeur') || deplacementType == 'changeur') {
{
// déplacement possible // déplacement possible
await this.actor.setTMRVisible(true); await this.actor.setTMRVisible(true);
this.demiReve = this._tokenDemiReve(); this.demiReve = this._tokenDemiReve();
this._trackToken(this.demiReve); this._trackToken(this.demiReve);
} }
else else {
{
ui.notifications.error(`Vous ne connaissez plus votre position dans les TMR. ui.notifications.error(`Vous ne connaissez plus votre position dans les TMR.
Vous devez utiliser les boutons de direction pour vous déplacer. Vous devez utiliser les boutons de direction pour vous déplacer.
Une fois que vous aurez retrouvé votre demi-rêve, demandez au gardien de vérifier et rendre les TMR visibles. Une fois que vous aurez retrouvé votre demi-rêve, demandez au gardien de vérifier et rendre les TMR visibles.
@@ -895,20 +927,18 @@ export class RdDTMRDialog extends Dialog {
} }
} }
switch (deplacementType){ switch (deplacementType) {
case 'normal': case 'normal':
case 'changeur':
case 'passeur':
await this._deplacerDemiReve(targetCoord, deplacementType); await this._deplacerDemiReve(targetCoord, deplacementType);
break; break;
case 'messager': case 'messager':
await this._messagerDemiReve(targetCoord); await this._messagerDemiReve(targetCoord);
break; break;
case 'changeur':
case 'passeur':
await this._deplacerDemiReve(targetCoord, deplacementType);
break;
default: default:
ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre"); ui.notifications.error("Vous ne pouvez pas vous déplacer que sur des cases adjacentes à votre position ou valides dans le cas d'une rencontre");
console.log("STATUS :", this.rencontreState, this.currentRencontre); console.log("STATUS :", this.rencontreState, this.currentRencontre);
} }
this.checkQuitterTMR(); this.checkQuitterTMR();
@@ -916,19 +946,23 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
_calculDeplacement(targetCoord, currentCoord, fromOddq, toOddq) { _calculDeplacement(targetCoord, currentCoord, fromOddq, toOddq) {
if (this.isRencontreDeplacement()) {
const isInArea = this.rencontreState == 'aucune' if (this.currentRencontre?.locList?.find(coord => coord == targetCoord)) {
? (this.isTerreAttache(targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord) || TMRUtility.distanceOddq(fromOddq, toOddq) <= 1) return this.rencontreState;
: this.currentRencontre?.locList?.find(coord => coord == targetCoord) ?? false }
if (isInArea) { }
switch (this.rencontreState) { else {
case 'aucune': return 'normal'; if (this.isTerreAttache(targetCoord) || this.isConnaissanceFleuve(currentCoord, targetCoord) || TMRUtility.distanceOddq(fromOddq, toOddq) <= 1) {
case 'passeur': case 'changeur': case 'messager': return this.rencontreState; return 'normal'
} }
} }
return 'erreur'; return 'erreur';
} }
isRencontreDeplacement() {
return ['passeur', 'changeur', 'messager'].includes(this.rencontreState);
}
/* -------------------------------------------- */ /* -------------------------------------------- */
async _messagerDemiReve(targetCoord) { async _messagerDemiReve(targetCoord) {
/* /*

View File

@@ -2,46 +2,41 @@
export class RdDTMRRencontreDialog extends Dialog { export class RdDTMRRencontreDialog extends Dialog {
/* -------------------------------------------- */ /* -------------------------------------------- */
constructor(tmrApp, rencontre, postRencontre) { constructor(tmrApp, rencontre, tmr) {
const dialogConf = { const dialogConf = {
title: "Rencontre en TMR!", title: "Rencontre en TMR!",
content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.force + "<br>", content: "Vous rencontrez un " + rencontre.name + " de force " + rencontre.system.force + "<br>",
buttons: { buttons: {
derober: { icon: '<i class="fas fa-check"></i>', label: "Se dérober", callback: () => { this.onButtonFuir(() => tmrApp.derober()); } }, derober: { icon: '<i class="fas fa-check"></i>', label: "Se dérober", callback: () => this.onButtonAction('derober') },
refouler: { icon: '<i class="fas fa-check"></i>', label: "Refouler", callback: () => this.onButtonAction(() => tmrApp.refouler()) }, maitiser: { icon: '<i class="fas fa-check"></i>', label: "Maîtriser", callback: () => this.onButtonAction('maitriser') }
maitiser: { icon: '<i class="fas fa-check"></i>', label: "Maîtriser", callback: () => this.onButtonAction(() => tmrApp.maitriserRencontre()) }
}, },
default: "derober" default: "derober"
}; }
if (rencontre.ignorer) { if ((rencontre.system.refoulement ?? 0) == 0) {
dialogConf.buttons.ignorer = { icon: '<i class="fas fa-check"></i>', label: "Ignorer", callback: () => this.onButtonAction(() => tmrApp.ignorerRencontre()) } dialogConf.buttons.ignorer = { icon: '<i class="fas fa-check"></i>', label: "Ignorer", callback: () => this.onButtonAction('ignorer') }
}; }
else {
dialogConf.buttons.refouler = { icon: '<i class="fas fa-check"></i>', label: "Refouler", callback: () => this.onButtonAction('refouler') }
}
const dialogOptions = { const dialogOptions = {
classes: ["tmrrencdialog"], classes: ["tmrrencdialog"],
width: 320, height: 240, width: 320, height: 'fit-content',
'z-index': 50 'z-index': 50
} }
super(dialogConf, dialogOptions); super(dialogConf, dialogOptions);
this.toClose = false; this.toClose = false;
this.rencontreData = duplicate(rencontre); this.tmr = tmr;
this.postRencontre = postRencontre;
this.tmrApp = tmrApp; this.tmrApp = tmrApp;
this.tmrApp.minimize(); this.tmrApp.minimize();
} }
async onButtonAction(action) { async onButtonAction(action) {
this.toClose = true; this.toClose = true;
await action(); this.tmrApp.onActionRencontre(action, this.tmr)
this.postRencontre();
} }
async onButtonFuir(action) {
this.toClose = true;
await action();
}
/* -------------------------------------------- */ /* -------------------------------------------- */
close() { close() {
if (this.toClose) { if (this.toClose) {

View File

@@ -1,19 +1,21 @@
/* Common useful functions shared between objects */ /* Common useful functions shared between objects */
import { ChatUtility } from "./chat-utility.js"; import { ChatUtility } from "./chat-utility.js";
import { RdDCombat } from "./rdd-combat.js"; 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 "./dialog-item-achat.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { RdDItem } from "./item.js"; import { RdDItem } from "./item.js";
import { Monnaie } from "./item-monnaie.js"; import { Monnaie } from "./item-monnaie.js";
import { RdDPossession } from "./rdd-possession.js"; import { RdDPossession } from "./rdd-possession.js";
import { RdDNameGen } from "./rdd-namegen.js"; import { RdDNameGen } from "./rdd-namegen.js";
import { RdDConfirm } from "./rdd-confirm.js"; import { RdDConfirm } from "./rdd-confirm.js";
import { RdDActor } from "./actor.js"; import { RdDCalendrier } from "./rdd-calendrier.js";
import { Environnement } from "./environnement.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
/* -------------------------------------------- */ /* -------------------------------------------- */
// This table starts at 0 -> niveau -10 // This table starts at 0 -> niveau -10
@@ -168,6 +170,12 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-suivants.html',
'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html', 'systems/foundryvtt-reve-de-dragon/templates/actor/liens-vehicules.html',
//Items //Items
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete-script.hbs',
'systems/foundryvtt-reve-de-dragon/templates/scripts/autocomplete.hbs',
'systems/foundryvtt-reve-de-dragon/templates/item/boutons-comestible.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-inventaire.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/item/partial-tab-environnement.html',
'systems/foundryvtt-reve-de-dragon/templates/header-item.html', 'systems/foundryvtt-reve-de-dragon/templates/header-item.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html',
@@ -178,10 +186,11 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item-sort-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-sort-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-herbe-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-herbe-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-ingredient-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-ingredient-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-faune-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-livre-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-livre-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-tache-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-tache-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-potion-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-potion-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-rencontresTMR-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-rencontre-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-queue-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-souffle-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-souffle-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-tarot-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-tarot-sheet.html',
@@ -192,22 +201,45 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-possession-sheet.html', 'systems/foundryvtt-reve-de-dragon/templates/item-possession-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html', 'systems/foundryvtt-reve-de-dragon/templates/item-extraitpoetique-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-base.html', // partial enums
'systems/foundryvtt-reve-de-dragon/templates/enum-caracteristiques.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-base-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-ingredient.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-ingredient.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-herbesoin-ingredient.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-herbesoin-ingredient.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-heures.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-niveau-ethylisme.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html',
'systems/foundryvtt-reve-de-dragon/templates/sort-draconic.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-queue.html',
'systems/foundryvtt-reve-de-dragon/templates/sort-tmr.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-draconic.html',
'systems/foundryvtt-reve-de-dragon/templates/niveau-ethylisme.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-type.html',
'systems/foundryvtt-reve-de-dragon/templates/casetmr-specific-list.html', 'systems/foundryvtt-reve-de-dragon/templates/enum-tmr-effet.html',
// Partials
'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffFixe.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-forcer.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-competences.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-hautrevant.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-frequence.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html',
'systems/foundryvtt-reve-de-dragon/templates/roll/explain.hbs',
'systems/foundryvtt-reve-de-dragon/templates/resolution-table.html',
// Dialogs // Dialogs
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
@@ -219,23 +251,9 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', 'systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html',
// Partials
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffFixe.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-forcer.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-item-description.html',
// Calendrier // Calendrier
'systems/foundryvtt-reve-de-dragon/templates/calendar-template.html', 'systems/foundryvtt-reve-de-dragon/templates/calendar-template.html',
'systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html', 'systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html',
'systems/foundryvtt-reve-de-dragon/templates/heures-select-option.html',
// HUD // HUD
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html',
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html',
@@ -266,6 +284,9 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html' 'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html'
]; ];
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() ?? 'NULL'); Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? 'NULL');
@@ -277,46 +298,28 @@ export class RdDUtility {
Handlebars.registerHelper('buildContenu', (objet) => { return new Handlebars.SafeString(RdDUtility.buildContenu(objet, 1, true)); }); Handlebars.registerHelper('buildContenu', (objet) => { return new Handlebars.SafeString(RdDUtility.buildContenu(objet, 1, true)); });
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord)); Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord)); Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('typeTmr-name', coord => TMRUtility.typeTmrName(coord)); Handlebars.registerHelper('typeTmr-name', type => TMRUtility.typeTmrName(type));
Handlebars.registerHelper('effetRencontre-name', coord => TMRUtility.typeTmrName(coord));
Handlebars.registerHelper('signeHeure', (key, heure) => RdDCalendrier.getSigneAs(key, heure));
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1))); Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionelles.isUsing(option)); Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionelles.isUsing(option));
Handlebars.registerHelper('trier', competences => competences.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 => competences.filter(it => it.system.isVisible) Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences));
.sort((a, b) => { Handlebars.registerHelper('linkCompendium', (pack, id, name) => RdDUtility.linkCompendium(pack, id, name));
if (a.name.startsWith("Survie") && b.name.startsWith("Survie")) { Handlebars.registerHelper('uniteQuantite', (itemId, actorId) => RdDUtility.getItem(itemId, actorId)?.getUniteQuantite());
if (a.name.includes("Cité")) return -1; Handlebars.registerHelper('isFieldInventaireModifiable', (type, field) => RdDItem.isFieldInventaireModifiable(type, field));
if (b.name.includes("Cité")) return 1; Handlebars.registerHelper('getFrequenceRarete', (rarete, field) => Environnement.getFrequenceRarete(rarete, field));
if (a.name.includes("Extérieur")) return -1;
if (b.name.includes("Extérieur")) return 1;
return a.name.localeCompare(b.name);
}
if (a.system.categorie.startsWith("melee") && b.system.categorie.startsWith("melee")) {
if (a.name.includes("Corps")) return -1;
if (b.name.includes("Corps")) return 1;
if (a.name.includes("Dague")) return -1;
if (b.name.includes("Dague")) return 1;
if (a.name.includes("Esquive")) return -1;
if (b.name.includes("Esquive")) return 1;
return a.name.localeCompare(b.name);
}
if (a.name.startsWith("Voie") && b.name.startsWith("Voie")) {
if (a.name.includes("Oniros")) return -1;
if (b.name.includes("Oniros")) return 1;
if (a.name.includes("Hypnos")) return -1;
if (b.name.includes("Hypnos")) return 1;
if (a.name.includes("Narcos")) return -1;
if (b.name.includes("Narcos")) return 1;
if (a.name.includes("Thanatos")) return -1;
if (b.name.includes("Thanatos")) return 1;
return a.name.localeCompare(b.name);
}
return a.name.localeCompare(b.name);
})
);
return loadTemplates(templatePaths); return loadTemplates(templatePaths);
} }
static getItem(itemId, actorId = undefined) {
return actorId ? game.actors.get(actorId)?.getObjet(itemId) : game.items.get(itemId);
}
static linkCompendium(pack, id, name) {
return `@Compendium[${pack}.${id}]{${name}}`;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async creerObjet(actorSheet) { static async creerObjet(actorSheet) {
let itemType = $(".item-type").val(); let itemType = $(".item-type").val();
@@ -325,7 +328,7 @@ export class RdDUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async selectObjetType(actorSheet) { static async selectObjetType(actorSheet) {
let typeObjets = RdDItem.getTypesObjetsEquipement(); let typeObjets = RdDItem.getItemTypesInventaire();
let options = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`; let options = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of typeObjets) { for (let typeName of typeObjets) {
options += `<option value="${typeName}">${typeName}</option>` options += `<option value="${typeName}">${typeName}</option>`
@@ -412,6 +415,7 @@ export class RdDUtility {
RdDUtility.filterEquipementParType(formData, itemTypes); RdDUtility.filterEquipementParType(formData, itemTypes);
formData.sorts = this.arrayOrEmpty(itemTypes['sort']); formData.sorts = this.arrayOrEmpty(itemTypes['sort']);
formData.rencontres = this.arrayOrEmpty(itemTypes['rencontre']);
formData.casestmr = this.arrayOrEmpty(itemTypes['casetmr']); formData.casestmr = this.arrayOrEmpty(itemTypes['casetmr']);
formData.signesdraconiques = this.arrayOrEmpty(itemTypes['signedraconique']); formData.signesdraconiques = this.arrayOrEmpty(itemTypes['signedraconique']);
formData.queues = this.arrayOrEmpty(itemTypes['queue']); formData.queues = this.arrayOrEmpty(itemTypes['queue']);
@@ -446,9 +450,9 @@ export class RdDUtility {
formData.livres = this.arrayOrEmpty(itemTypes['livre']); formData.livres = this.arrayOrEmpty(itemTypes['livre']);
formData.potions = this.arrayOrEmpty(itemTypes['potion']); formData.potions = this.arrayOrEmpty(itemTypes['potion']);
formData.ingredients = this.arrayOrEmpty(itemTypes['ingredient']); formData.ingredients = this.arrayOrEmpty(itemTypes['ingredient']);
formData.faunes = this.arrayOrEmpty(itemTypes['faune']);
formData.herbes = this.arrayOrEmpty(itemTypes['herbe']); formData.herbes = this.arrayOrEmpty(itemTypes['herbe']);
formData.monnaie = this.arrayOrEmpty(itemTypes['monnaie']); formData.monnaie = this.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.monnaie.sort(Monnaie.triValeurDenier());
formData.nourritureboissons = this.arrayOrEmpty(itemTypes['nourritureboisson']); formData.nourritureboissons = this.arrayOrEmpty(itemTypes['nourritureboisson']);
formData.gemmes = this.arrayOrEmpty(itemTypes['gemme']); formData.gemmes = this.arrayOrEmpty(itemTypes['gemme']);
@@ -461,6 +465,7 @@ export class RdDUtility {
.concat(formData.potions) .concat(formData.potions)
.concat(formData.ingredients) .concat(formData.ingredients)
.concat(formData.herbes) .concat(formData.herbes)
.concat(formData.faunes)
.concat(formData.monnaie) .concat(formData.monnaie)
.concat(formData.nourritureboissons) .concat(formData.nourritureboissons)
.concat(formData.gemmes); .concat(formData.gemmes);
@@ -534,8 +539,7 @@ export class RdDUtility {
if (!profondeur) profondeur = 1; if (!profondeur) profondeur = 1;
objet.niveau = profondeur; objet.niveau = profondeur;
const display = afficherContenu ? 'item-display-show' : 'item-display-hide'; const display = afficherContenu ? 'item-display-show' : 'item-display-hide';
//console.log("ITEM DISPLAYED", objet ); let strContenu = `<ul class='item-list alterne-list ${display} list-item-margin${Math.min(profondeur,6)}'>`;
let strContenu = `<ul class='item-list alterne-list ${display} list-item-margin${profondeur}'>`;
for (let subItem of objet.subItems) { for (let subItem of objet.subItems) {
strContenu += this.buildConteneur(subItem, profondeur + 1); strContenu += this.buildConteneur(subItem, profondeur + 1);
} }
@@ -752,29 +756,6 @@ export class RdDUtility {
return 0; return 0;
} }
/* -------------------------------------------- */
static async loadItems(filter, compendium) {
let items = game.items.filter(filter);
if (compendium) {
const ids = items.map(it => it.id);
const names = items.map(it => it.name.toLowerCase());
items = items.concat(await RdDUtility.loadCompendium(compendium, it => !ids.includes(it.id) && !names.includes(it.name.toLowerCase()) && filter(it)));
}
return items;
}
/* -------------------------------------------- */
static async loadCompendium(compendium, filter = it => true) {
let compendiumData = await RdDUtility.loadCompendiumData(compendium);
return compendiumData.filter(filter);
}
/* -------------------------------------------- */
static async loadCompendiumData(compendium) {
const pack = game.packs.get(compendium);
return await pack?.getDocuments() ?? [];
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async responseNombreAstral(callData) { static async responseNombreAstral(callData) {
let actor = game.actors.get(callData.id); let actor = game.actors.get(callData.id);
@@ -841,17 +822,10 @@ export class RdDUtility {
// Gestion du bouton payer // Gestion du bouton payer
html.on("click", '.payer-button', event => { html.on("click", '.payer-button', event => {
let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0; let sommeAPayer = Number(event.currentTarget.attributes['data-somme-a-payer']?.value ?? 0);
let quantite = event.currentTarget.attributes['data-quantite']?.value ?? 1;
let fromActorId = event.currentTarget.attributes['data-actor-id']?.value;
let jsondata = event.currentTarget.attributes['data-jsondata']
let objData
if (jsondata) {
objData = JSON.parse(jsondata.value)
}
let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:"); let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:");
if (actor) { if (actor) {
actor.depenserDeniers(sumdenier, objData, quantite, fromActorId); actor.payerSols(sommeAPayer);
ChatUtility.removeChatMessageId(RdDUtility.findChatMessageId(event.currentTarget)); ChatUtility.removeChatMessageId(RdDUtility.findChatMessageId(event.currentTarget));
} }
}); });
@@ -902,12 +876,12 @@ export class RdDUtility {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static createMonnaie(name, valeur_deniers, 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: randomID(16),
dasystemta: { dasystemta: {
quantite: 0, quantite: 0,
valeur_deniers: valeur_deniers, cout: cout,
encombrement: enc, encombrement: enc,
description: "" description: ""
} }
@@ -919,20 +893,20 @@ export class RdDUtility {
static afficherDemandePayer(som1, som2) { static afficherDemandePayer(som1, som2) {
som1 = (som1) ? som1.toLowerCase() : "0d"; som1 = (som1) ? som1.toLowerCase() : "0d";
som2 = (som2) ? som2.toLowerCase() : "0d"; som2 = (som2) ? som2.toLowerCase() : "0d";
let regExp = /(\d+)(\w+)/g; let regExp1 = /(\d+)(\w+)/g;
let p1 = regExp.exec(som1); let p1 = regExp1.exec(som1);
regExp = /(\d+)(\w+)/g; let regExp2 = /(\d+)(\w+)/g;
let p2 = regExp.exec(som2); let p2 = regExp2.exec(som2);
let sumd = 0; let deniers = 0;
let sums = 0; let sols = 0;
if (p1[2] == 'd') sumd += Number(p1[1]); if (p1[2] == 'd') deniers += Number(p1[1]);
if (p1[2] == 's') sums += Number(p1[1]); if (p1[2] == 's') sols += Number(p1[1]);
if (p2[2] == 'd') sumd += Number(p2[1]); if (p2[2] == 'd') deniers += Number(p2[1]);
if (p2[2] == 's') sums += Number(p2[1]); if (p2[2] == 's') sols += Number(p2[1]);
let sumtotald = sumd + (sums * 100); let sommeAPayer = sols + deniers/100;
let msgPayer = "La somme de " + sums + " Sols et " + sumd + " Deniers est à payer, cliquer sur le lien ci-dessous si besoin.<br>"; let msgPayer = `La somme de ${sols} Sols et ${deniers} Deniers est à payer<br>
msgPayer += "<a class='payer-button chat-card-button' data-somme-denier='" + sumtotald + "'>Payer</a>" <a class='payer-button chat-card-button' data-somme-a-payer='${sommeAPayer}'>Payer</a>`
ChatMessage.create({ content: msgPayer }); ChatMessage.create({ content: msgPayer });
} }
@@ -1007,7 +981,7 @@ export class RdDUtility {
} }
static slideOnDelete(sheet, htmlToDelete) { static slideOnDelete(sheet, htmlToDelete) {
return htmlToDelete.slideUp(200, () => sheet.render(false)); return htmlToDelete?.slideUp(200, () => sheet.render(false));
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@@ -6,7 +6,7 @@ import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js"; import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js"; import { RdDCarac } from "./rdd-carac.js";
import { RdDUtility } from "./rdd-utility.js"; import { RdDUtility } from "./rdd-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js"; import { ReglesOptionelles } from "./settings/regles-optionelles.js";
/** /**
* tous les ajustements pouvant s'appliquer. * tous les ajustements pouvant s'appliquer.
@@ -62,20 +62,20 @@ export const referenceAjustements = {
getValue: (rollData, actor) => actor.getMalusArmure() getValue: (rollData, actor) => actor.getMalusArmure()
}, },
encTotal: { encTotal: {
isVisible: (rollData, actor) => RdDItemCompetence.isMalusEncombrementTotal(rollData.competence), isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac) && RdDItemCompetence.isMalusEncombrementTotal(rollData.competence),
isUsed: (rollData, actor) => rollData.useMalusEncTotal, isUsed: (rollData, actor) => !rollData.oeuvre && RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac) && RdDItemCompetence.isMalusEncombrementTotal(rollData.competence) && rollData.use.encTotal,
getLabel: (rollData, actor) => 'Encombrement total', getLabel: (rollData, actor) => 'Encombrement total',
getValue: (rollData, actor) => -actor.getEncTotal() getValue: (rollData, actor) => -actor.getEncTotal()
}, },
surenc: { surenc: {
isVisible: (rollData, actor) => rollData.useMalusSurenc, isVisible: (rollData, actor) => actor.isSurenc(),
isUsed: (rollData, actor) => rollData.useMalusSurenc, isUsed: (rollData, actor) => rollData.use?.surenc,
getLabel: (rollData, actor) => 'Sur-encombrement', getLabel: (rollData, actor) => 'Sur-encombrement',
getValue: (rollData, actor) => actor.computeMalusSurEncombrement() getValue: (rollData, actor) => actor.computeMalusSurEncombrement()
}, },
moral: { moral: {
isVisible: (rollData, actor) => actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac) && rollData.useMoral, isVisible: (rollData, actor) => actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac) && rollData.use?.moral,
isUsed: (rollData, actor) => rollData.useMoral, isUsed: (rollData, actor) => rollData.use?.moral,
getLabel: (rollData, actor) => 'Appel au moral', getLabel: (rollData, actor) => 'Appel au moral',
getValue: (rollData, actor) => 1 getValue: (rollData, actor) => 1
}, },
@@ -120,7 +120,7 @@ export const referenceAjustements = {
isVisible: (rollData, actor) => rollData.tmr && rollData.rencontre?.name, isVisible: (rollData, actor) => rollData.tmr && rollData.rencontre?.name,
isUsed: (rollData, actor) => rollData.tmr && rollData.rencontre?.name, isUsed: (rollData, actor) => rollData.tmr && rollData.rencontre?.name,
getLabel: (rollData, actor) => rollData.rencontre?.name, getLabel: (rollData, actor) => rollData.rencontre?.name,
getValue: (rollData, actor) => - (rollData.rencontre?.force ?? 0) getValue: (rollData, actor) => - (rollData.rencontre?.system.force ?? 0)
}, },
ethylismeAlcool: { ethylismeAlcool: {
isVisible: (rollData, actor) => rollData.nbDoses != undefined, isVisible: (rollData, actor) => rollData.nbDoses != undefined,

View File

@@ -1,5 +1,5 @@
import { SYSTEM_RDD } from "./constants.js"; import { SYSTEM_RDD } from "../constants.js";
import { Misc } from "./misc.js"; import { Misc } from "../misc.js";
const listeReglesOptionelles = [ const listeReglesOptionelles = [
{ 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" },
@@ -18,6 +18,7 @@ const listeReglesOptionelles = [
{ group: 'Règles générales', name: 'appliquer-fatigue', descr: "Appliquer les règles de fatigue"}, { group: 'Règles générales', name: 'appliquer-fatigue', descr: "Appliquer les règles de fatigue"},
{ group: 'Règles générales', name: 'afficher-colonnes-reussite', descr: "Afficher le nombre de colonnes de réussite ou d'échec", default: false }, { group: 'Règles générales', name: 'afficher-colonnes-reussite', descr: "Afficher le nombre de colonnes de réussite ou d'échec", default: false },
{ group: 'Confirmations', name: 'confirmer-combat-sans-cible', descr: "Confirmer avant une attaque sans cible", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"}, { group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-refouler', descr: "Confirmer avant de refouler", scope: "client"}, { group: 'Confirmations', name: 'confirmation-refouler', descr: "Confirmer avant de refouler", scope: "client"},
{ group: 'Confirmations', name: 'confirmation-vider', descr: "Confirmer pour vider l'équipement", scope: "client"}, { group: 'Confirmations', name: 'confirmation-vider', descr: "Confirmer pour vider l'équipement", scope: "client"},
@@ -43,7 +44,7 @@ export class ReglesOptionelles extends FormApplication {
game.settings.registerMenu(SYSTEM_RDD, "rdd-options-regles", { game.settings.registerMenu(SYSTEM_RDD, "rdd-options-regles", {
name: "Choisir les règles optionelles", name: "Choisir les règles optionelles",
label: "Choix des règles optionelles", label: "Règles optionelles",
hint: "Ouvre la fenêtre de sélection des règles optionelles", hint: "Ouvre la fenêtre de sélection des règles optionelles",
icon: "fas fa-bars", icon: "fas fa-bars",
type: ReglesOptionelles type: ReglesOptionelles
@@ -61,8 +62,8 @@ export class ReglesOptionelles extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
const options = super.defaultOptions; const options = super.defaultOptions;
mergeObject(options, { mergeObject(options, {
id: "optional-settings", id: "regles-optionelles",
template: "systems/foundryvtt-reve-de-dragon/templates/regles-optionelles.html", template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionelles.html",
height: 600, height: 600,
width: 450, width: 450,
minimizable: false, minimizable: false,

View File

@@ -1,4 +1,4 @@
import { SYSTEM_RDD } from "./constants.js"; import { SYSTEM_RDD } from "../constants.js";
export const STATUSES = { export const STATUSES = {
StatusStunned : 'stun', StatusStunned : 'stun',
@@ -32,7 +32,7 @@ const demiReveStatusEffect = rddStatusEffects.find(it => it.id == STATUSES.Statu
const statusDemiSurprise = [STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained]; const statusDemiSurprise = [STATUSES.StatusStunned, STATUSES.StatusProne, STATUSES.StatusRestrained];
const statusSurpriseTotale = [STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma]; const statusSurpriseTotale = [STATUSES.StatusUnconscious, STATUSES.StatusBlind, STATUSES.StatusComma];
export class StatusEffects { export class StatusEffects extends FormApplication {
static onReady() { static onReady() {
const rddStatusIds = rddStatusEffects.map(it => it.id); const rddStatusIds = rddStatusEffects.map(it => it.id);
rddStatusEffects.forEach(it => it.flags = { core: { statusId: it.id } }); rddStatusEffects.forEach(it => it.flags = { core: { statusId: it.id } });
@@ -50,7 +50,7 @@ export class StatusEffects {
label: "Choix des effets", label: "Choix des effets",
hint: "Ouvre la fenêtre de sélection des effets/status appliqués aux acteurs", hint: "Ouvre la fenêtre de sélection des effets/status appliqués aux acteurs",
icon: "fas fa-bars", icon: "fas fa-bars",
type: StatusEffectsSettings, type: StatusEffects,
restricted: true restricted: true
}); });
@@ -69,13 +69,12 @@ export class StatusEffects {
} }
static _getUseStatusEffects() { static _getUseStatusEffects() {
const setting = game.settings.get(SYSTEM_RDD, "use-status-effects"); return game.settings.get(SYSTEM_RDD, "use-status-effects")?.split(',') ?? [];
return setting ? setting.split(',') : [];
} }
static _setUseStatusEffects(statusIds) { static _setUseStatusEffects(statusIds) {
if (game.user.isGM) { if (game.user.isGM) {
game.settings.set(SYSTEM_RDD, "use-status-effects", StatusEffects._toSetting(statusIds)); game.settings.set(SYSTEM_RDD, "use-status-effects", statusIds.join());
} }
for (let effect of CONFIG.RDD.allEffects) { for (let effect of CONFIG.RDD.allEffects) {
@@ -84,10 +83,6 @@ export class StatusEffects {
CONFIG.statusEffects = CONFIG.RDD.allEffects.filter(it => it.active); CONFIG.statusEffects = CONFIG.RDD.allEffects.filter(it => it.active);
} }
static _toSetting(statusIds) {
return statusIds.join();
}
static status(statusId) { static status(statusId) {
return rddStatusEffects.find(it => it.flags?.core?.statusId == statusId); return rddStatusEffects.find(it => it.flags?.core?.statusId == statusId);
} }
@@ -95,9 +90,7 @@ export class StatusEffects {
static demiReve() { static demiReve() {
return demiReveStatusEffect; return demiReveStatusEffect;
} }
}
class StatusEffectsSettings extends FormApplication {
constructor(...args) { constructor(...args) {
super(...args); super(...args);
} }
@@ -105,9 +98,9 @@ class StatusEffectsSettings extends FormApplication {
static get defaultOptions() { static get defaultOptions() {
const options = super.defaultOptions; const options = super.defaultOptions;
mergeObject(options, { mergeObject(options, {
id: "status-effects-settings", id: "status-effects",
template: "systems/foundryvtt-reve-de-dragon/templates/status-effects-settings.html", template: "systems/foundryvtt-reve-de-dragon/templates/settings/status-effects.html",
height: "800", height: 800,
width: 350, width: 350,
minimizable: false, minimizable: false,
closeOnSubmit: true, closeOnSubmit: true,

View File

@@ -0,0 +1,287 @@
import { HIDE_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
const COMPENDIUM_SETTING_PREFIX = 'compendium-';
const CONFIGURABLE_COMPENDIUMS = {
'tables-diverses': { label: "Tables aléatoires", type: "RollTable" },
'competences': { label: "Compétences", type: "Item" },
'extrait-poetique': { label: "Extraits poetiques", type: "Item" },
'queues-de-dragon': { label: "Queues de dragon", type: "Item" },
'ombres-de-thanatos': { label: "Ombres de Thanatos", type: "Item" },
'souffles-de-dragon': { label: "Souffles de Dragon", type: "Item" },
'tarot-draconique': { label: "Tarots draconiques", type: "Item" },
'rencontres': { label: "Rencontres dans les TMR", type: "Item" },
'tetes-de-dragon-pour-haut-revants': { label: "Têtes de dragons (haut-rêvant)", type: "Item" },
'tetes-de-dragon-pour-tous-personnages': { label: "Têtes de dragons (tous)", type: "Item" },
'faune-flore-mineraux': { label: "Herbes & plantes", type: "Item" },
'equipement': { label: "Equipements", type: "Item" },
}
/**
* ======= Gestion des accès aux compendiums systèmes (ou surchargés) =======
*/
export class SystemCompendiums extends FormApplication {
static init() {
Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => {
const definition = CONFIGURABLE_COMPENDIUMS[compendium];
mergeObject(definition, {
compendium: compendium,
default: SystemCompendiums._getDefaultCompendium(compendium),
setting: SystemCompendiums._getSettingCompendium(compendium)
});
game.settings.register(SYSTEM_RDD, definition.setting, {
name: definition.label,
default: definition.default,
scope: "world",
config: false,
type: String
});
});
game.settings.registerMenu(SYSTEM_RDD, "compendium-settings", {
name: "Choisir les compendiums système",
label: "Compendiums système",
hint: "Ouvre la fenêtre de sélection des compendiums système",
icon: "fas fa-bars",
type: SystemCompendiums
})
}
static getPack(compendium) {
return game.packs.get(SystemCompendiums.getCompendium(compendium)) ?? game.packs.get(SystemCompendiums._getDefaultCompendium(compendium));
}
static async getPackContent(compendium, docType) {
const pack = SystemCompendiums.getPack(compendium);
if (pack.metadata.type == docType) {
return await pack.getDocuments();
}
return [];
}
static async getCompetences(actorType) {
switch (actorType ?? 'personnage') {
case 'personnage': return await SystemCompendiums.getWorldOrCompendiumItems('competence', 'competences');
case 'creature': return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-creatures');
case 'entite': return await SystemCompendiums.getWorldOrCompendiumItems('competencecreature', 'competences-entites');
case 'vehicule': return [];
}
}
/* -------------------------------------------- */
static async getWorldOrCompendiumItems(itemType, compendium) {
let items = game.items.filter(it => it.type == itemType);
if (compendium) {
const ids = items.map(it => it.id);
const names = items.map(it => it.name.toLowerCase());
const compendiumItems = await SystemCompendiums.getItems(compendium);
items = items.concat(compendiumItems
.filter(it => it.type == itemType)
.filter(it => !ids.includes(it.id))
.filter(it => !names.includes(it.name.toLowerCase())));
}
return items;
}
static async getItems(compendium, itemType = undefined) {
const items = await SystemCompendiums.getPackContent(compendium, 'Item');
return (itemType ? items.filter(it => it.type == itemType) : items);
}
static async getContent(compendium, type, filter, itemFrequence, sorting) {
let elements = await SystemCompendiums.getPackContent(compendium, type);
elements = elements.filter(filter).filter(it => itemFrequence(it) > 0);
if (sorting) {
elements = elements.sort(sorting);
}
return elements;
}
static async getDefaultItems(compendium) {
const pack = game.packs.get(SystemCompendiums._getDefaultCompendium(compendium));
if (pack.metadata.type == 'Item') {
return await pack.getDocuments();
}
return [];
}
static getCompendium(compendium) {
const setting = CONFIGURABLE_COMPENDIUMS[compendium]?.setting;
return setting ? game.settings.get(SYSTEM_RDD, setting) : SystemCompendiums._getDefaultCompendium(compendium);
}
static _getSettingCompendium(compendium) {
return COMPENDIUM_SETTING_PREFIX + compendium;
}
static _getDefaultCompendium(compendium) {
return `${SYSTEM_RDD}.${compendium}`;
}
constructor(...args) {
super(...args);
}
static get defaultOptions() {
const options = super.defaultOptions;
mergeObject(options, {
id: "system-compendiums",
template: "systems/foundryvtt-reve-de-dragon/templates/settings/system-compendiums.html",
height: 'fit-content',
width: 600,
minimizable: false,
closeOnSubmit: true,
title: "Compendiums système"
});
return options;
}
getData() {
const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS)
.map(it => mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) }));
const availableCompendiums = game.packs.map(pack => {
return {
name: pack.collection,
path: pack.collection.replace('.', " / "),
type: pack.metadata.type
}
});
return mergeObject(super.getData(), {
systemCompendiums: systemCompendiums,
availableCompendiums: availableCompendiums
});
}
activateListeners(html) {
html.find("select.system-compendium-setting").change((event) => {
const compendium = $(event.currentTarget).data('compendium')
const value = $(event.currentTarget).val();
const systemCompendium = CONFIGURABLE_COMPENDIUMS[compendium];
game.settings.set(SYSTEM_RDD, systemCompendium.setting, value);
});
}
}
/**
* ======= Gestion de jets dans une table correspondant à un compendium =======
*/
export class CompendiumTable {
constructor(compendium, type, subTypes, sorting = undefined) {
this.compendium = compendium;
this.type = type;
this.subTypes = subTypes;
this.sorting = sorting ?? Misc.ascending(it => it.name);
}
async getContent(itemFrequence = it => it.system.frequence, filter = it => true) {
return await SystemCompendiums.getContent(this.compendium,
this.type,
it => this.subTypes.includes(it.type) && filter(it),
itemFrequence,
this.sorting);
}
async buildTable(itemFrequence = it => it.system.frequence, filter = it => true) {
const elements = await this.getContent(filter, itemFrequence);
return CompendiumTableHelpers.buildTable(elements, itemFrequence);
}
async getRandom(itemFrequence = it => it.system.frequence, filter = it => true, forcedRoll = undefined) {
const table = await this.buildTable(itemFrequence, filter);
return await CompendiumTableHelpers.getRandom(table, this.type, this.subTypes, forcedRoll, SystemCompendiums.getCompendium(compendium));
}
async toChatMessage(itemFrequence = it => it.system.frequence, filter = it => true, typeName = undefined) {
const table = await this.buildTable(itemFrequence, filter);
await CompendiumTableHelpers.tableToChatMessage(table, this.type, this.subTypes, typeName);
return true;
}
}
/**
* ======= Gestion de tables correspondant à un compendium =======
*/
export class CompendiumTableHelpers {
static buildTable(elements, itemFrequence) {
let max = 0;
const total = elements.map(it => itemFrequence(it)).reduce(Misc.sum(), 0);
return elements.map(it => {
const frequence = itemFrequence(it);
let row = { document: it, frequence: frequence, min: max + 1, max: max + frequence, total: total };
max += frequence;
return row;
});
}
static async getRandom(table, type, subTypes, forcedRoll = undefined, localisation = undefined) {
if (table.length == 0) {
ui.notifications.warn(`Aucun ${Misc.typeName(type, subTypes[0])} trouvé dans ${localisation ?? ' les compendiums'}`);
return undefined;
}
return await CompendiumTableHelpers.selectRow(table, forcedRoll);
}
/* -------------------------------------------- */
static async selectRow(table, forcedRoll = undefined) {
if (table.length == 0) {
return undefined
}
const total = table[0].total;
const formula = `1d${total}`;
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é`);
forcedRoll = undefined;
}
const roll = forcedRoll ? { total: forcedRoll, formula } : await RdDDice.roll(formula, { showDice: HIDE_DICE });
const row = table.find(it => it.min <= roll.total && roll.total <= it.max);
row.roll = roll;
return row;
}
/* -------------------------------------------- */
static async tableRowToChatMessage(row, type = 'Item') {
if (!row) {
return;
}
const percentages = (row.total == 100) ? '%' : ''
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.html', {
roll: row.roll,
document: row.document,
percentages,
typeName: Misc.typeName(type, row.document.type),
isGM: game.user.isGM,
});
const messageData = {
// flavor: flavorContent,
user: game.user.id,
type: CONST.CHAT_MESSAGE_TYPES.ROLL,
roll: row.roll,
sound: CONFIG.sounds.dice,
content: flavorContent
};
ChatMessage.create(messageData, { rollMode: "gmroll" });
}
/* -------------------------------------------- */
static async tableToChatMessage(table, type, subTypes, typeName = undefined) {
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.html', {
img: RdDItem.getDefaultImg(subTypes[0]),
typeName: typeName ?? Misc.typeName(type, subTypes[0]),
table,
isGM: game.user.isGM,
});
ChatMessage.create({
user: game.user.id,
whisper: game.user.id,
content: flavorContent
}, { rollMode: "gmroll" });
}
}

56
module/targets.js Normal file
View File

@@ -0,0 +1,56 @@
import { ENTITE_NONINCARNE } from "./constants.js";
import { DialogSelectTarget } from "./dialog-select-target.js";
export class Targets {
static listTargets() {
return Array.from(game.user.targets);
}
static hasTargets() {
return Targets.listTargets().length > 0;
}
static extractTokenData(target) {
if (!target) {
return undefined
}
return { id: target.id, name: target.document.name, img: target.document.texture.src ?? target.actor.img ?? 'icons/svg/mystery-man.svg' };
}
static isTargetEntite(target) {
return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
}
static async selectOneToken(onSelectTarget = target => { }) {
const targets = Targets.listTargets();
switch (targets.length) {
case 0: return;
case 1:
onSelectTarget(targets[0]);
return;
default:
{
const tokens = targets.map(it => Targets.extractTokenData(it))
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select-target.html", {
tokens: tokens
});
new DialogSelectTarget(html, onSelectTarget, targets).render(true);
}
}
}
static getTarget() {
const targets = Targets.listTargets();
switch (targets.length) {
case 1:
return targets[0];
case 0:
ui.notifications.warn("Vous devez choisir une cible à attaquer!");
break;
default:
ui.notifications.warn("Vous devez choisir une cible (et <strong>une seule</strong>) à attaquer!");
return;
}
}
}

View File

@@ -1,500 +1,132 @@
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums, CompendiumTable, CompendiumTableHelpers } from "./settings/system-compendiums.js";
import { TMRUtility } from "./tmr-utility.js"; import { TMRUtility } from "./tmr-utility.js";
import { TMRType } from "./tmr-utility.js";
/* -------------------------------------------- */
const typeRencontres = {
messager: {
msgSucces: async (rencData) => {
if (rencData.actor.isTMRCache()){
return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort, mais vous ne savez pas où vous êtes.`;
}
return `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases ${rencData.tmr.label}.`;
},
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
},
poesieSucces: {
reference: "La chevelure, Charles Baudelaire",
extrait: `J'irai là-bas où l'arbre et l'homme, pleins de sève,
<br>Se pâment longuement sous l'ardeur des climats ;
<br>Fortes tresses, soyez la houle qui m'enlève !`
},
poesieEchec: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `En réalité, tous les éléments du rêve des Dragons expriment
le Draconic : chaque pierre, chaque fleur, chaque goutte d'eau,
chaque nuage est porteur d'un message dans la langue des Dragons`}
},
passeur: {
msgSucces: async (rencData) => {
if (rencData.actor.isTMRCache()){
return `Le ${rencData.rencontre.name} vous propose de vous transporter, mais vous ne savez pas où vous êtes.`;
}
return `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`;
},
msgEchec: async (rencData)=> `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
},
poesieSucces: {
reference: "Femmes damnées (2), Charles Baudelaire",
extrait: `Comme je descendais des Fleuves impassibles,
<br>Je ne me sentis plus guidé par les haleurs :
<br>Des Peaux-Rouges criards les avaient pris pour cibles,
<br>Les ayant cloués nus aux poteaux de couleurs.`},
poesieEchec: {
reference: "Le bateau ivre, Arthur Rimbaud",
extrait: `Loin des peuples vivants, errantes, condamnées,
<br>A travers les déserts courez comme les loups ;
<br>Faites votre destin, âmes désordonnées,
<br>Et fuyez l'infini que vous portez en vous !`}
},
fleur: {
msgSucces: async (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`,
msgEchec: async (rencData)=> `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force),
poesieSucces: {
reference: "L'Ennemi, Charles Baudelaire",
extrait: `Et qui sait si les fleurs nouvelles que je rêve
<br>Trouveront dans ce sol lavé comme une grève
<br>Le mystique aliment qui ferait leur vigueur ?`},
poesieEchec: {
reference: "Une charogne, Charles Baudelaire",
extrait: `Et le ciel regardait la carcasse superbe
<br>Comme une fleur s'épanouir.
<br>La puanteur était si forte, que sur l'herbe
<br>Vous crûtes vous évanouir.`},
},
mangeur: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`,
postEchec: async (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force),
poesieSucces: {
reference: "Conseil, Victor Hugo",
extrait: `Rois ! la bure est souvent jalouse du velours.
<br>Le peuple a froid l'hiver, le peuple a faim toujours.
<br>Rendez-lui son sort plus facile.
<br>Le peuple souvent porte un bien rude collier.
<br>Ouvrez l'école aux fils, aux pères l'atelier,
<br>À tous vos bras, auguste asile !`},
poesieEchec: {
reference: "El Desdichado, Gérard de Nerval",
extrait: `Suis-je Amour ou Phébus ?... Lusignan ou Biron ?
<br>Mon front est rouge encor du baiser de la Reine ;
<br>J'ai rêvé dans la Grotte où nage la sirène...`}
},
changeur: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: async (rencData) => `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte sur une autre ${TMRType[rencData.tmr.type].name} sans attendre votre avis.`,
postSucces: async (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCaseType(rencData.tmr.type);
},
postEchec: async (tmrDialog, rencData) => {
const newTMR = await TMRUtility.getTMRAleatoire(it => it.type == rencData.tmr.type && it.coord != rencData.tmr.coord);
await tmrDialog.actor.forcerPositionTMRInconnue(newTMR);
tmrDialog.positionnerDemiReve(newTMR.coord);
},
poesieSucces: {
reference: "Caligula - IIIème chant, Gérard de Nerval",
extrait: `Allez, que le caprice emporte
<br>Chaque âme selon son désir,
<br>Et que, close après vous, la porte
<br>Ne se rouvre plus qu'au plaisir.`},
poesieEchec: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Les sages ont encore coutume de dire :
<br>&laquo; Mais comment les Dragons peuvent-ils
être influencés par une créature qui, tout
bien considéré, n'existe pas vraiment pour eux,
qui n'est que le fantasme de leur activité nocturne ? &raquo;`}
},
briseur: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: async (tmrDialog, rencData) => tmrDialog.close(),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `La légende affirme que ce sont les Gnomes qui furent
les premiers haut-rêvants. En observant les pierres précieuses,
les gemmes qui sont les larmes de joie des Dragons, ils parvinrent à
en comprendre la langue. Et l'ayant comprise, ils purent s'en servir
pour influencer le cours du rêve`},
poesieEchec: {
reference: "Quand le rêve se brise, Cypora Sebagh",
extrait: `Quand le rêve se brise,
<br>Dans la plainte du jour,
<br>Ma mémoire devient grise
<br>Et sombre, tour à tour,
<br>Dans le puits du silence
<br>Et de la solitude ;
<br>Elle reprend son errance
<br>Parmi la multitude.`}
},
reflet: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: async (rencData)=> `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
poesieSucces: {
reference: "Une charogne, Charles Baudelaire",
extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve,
<br>Une ébauche lente à venir
<br>Sur la toile oubliée, et que l'artiste achève
<br>Seulement par le souvenir.`},
poesieEchec: {
reference: "La chevelure, Charles Baudelaire",
extrait: `Longtemps ! toujours ! ma main dans ta crinière lourde
<br>Sèmera le rubis, la perle et le saphir,
<br>Afin qu'à mon désir tu ne sois jamais sourde !
<br>N'es-tu pas l'oasis où je rêve, et la gourde
<br>Où je hume à longs traits le vin du souvenir`}
},
passeurfou: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: async (rencData)=> TMRRencontres.msgEchecPasseurFou(rencData),
postEchec: async (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData),
poesieSucces: {
reference: "Un Fou et un Sage, Jean de La Fontaine",
extrait: `Certain Fou poursuivait à coups de pierre un Sage.
<br>Le Sage se retourne et lui dit : Mon ami,
<br>C'est fort bien fait à toi ; reçois cet écu-ci :
<br>Tu fatigues assez pour gagner davantage.`},
poesieEchec: {
reference: "Guitare, Victor Hugo",
extrait: `Je la voyais passer de ma demeure,
<br>Et c'était tout.
<br>Mais à présent je m'ennuie à toute heure,
<br>Plein de dégoût,
<br>Rêveur oisif, l'âme dans la campagne,
<br>La dague au clou ...
<br>Le vent qui vient à travers la montagne
<br>M'a rendu fou !`}
},
tbblanc: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: async (rencData)=> `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement
des temps, le commencement des rêves. Durant cette période plus mythique
que réellement historique, les Dragons aimaient à se rêver eux-mêmes.`},
poesieEchec: {
reference: "Les Djinns, Victor Hugo",
extrait: `C'est l'essaim des Djinns qui passe,
<br>Et tourbillonne en sifflant !
<br>Les ifs, que leur vol fracasse,
<br>Craquent comme un pin brûlant.`},
},
tbnoir: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les
Gnomes s'enfoncèrent profondément sous les montagnes et la magie passa aux
mains des Humains qui en usèrent et abusèrent, se croyant devenus les maîtres du monde`},
poesieEchec: {
reference: "Lily, Pierre Perret",
extrait: `Elle aurait pas cru sans le voir
<br>Que la couleur du désespoir
<br>Là-bas aussi ce fût le noir.`},
},
tbrouge: {
msgSucces: async (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: async (rencData)=> `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData),
poesieSucces: {
reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet",
extrait: `Qu'est-ce de votre vie ? un tourbillon rouant
<br>De fumière à flot gris, parmi l'air se jouant,
<br>Qui passe plus soudain que foudre meurtrière.`},
poesieEchec: {
reference: "Les Djinns, poème Victor Hugo",
extrait: `Cris de l'enfer! voix qui hurle et qui pleure !
<br>L'horrible essaim, poussé par l'aquilon,
<br>Sans doute, ô ciel ! s'abat sur ma demeure.
<br>Le mur fléchit sous le noir bataillon.
<br>La maison crie et chancelle penchée,
<br>Et l'on dirait que, du sol arrachée,
<br>Ainsi qu'il chasse une feuille séchée,
<br>Le vent la roule avec leur tourbillon !`},
},
rdd: {
msgSucces: async (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`,
msgEchec: async (rencData)=> `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: async (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData),
postEchec: async (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le monde est Rêve de Dragons, mais nous ne savons
<br>ni leur apparence ni qui sont les dragons.
<br>En dépit de l'iconographie qui les clame
<br>immenses créatures ailées crachant des flammes`},
poesieEchec: {
reference: "El Desdichado, Gérard de Nerval",
extrait: `Je suis le Ténébreux, le Veuf, l'Inconsolé,
<br>Le Prince d'Aquitaine à la Tour abolie :
<br>Ma seule Etoile est morte, et mon luth constellé
<br>Porte le Soleil noir de la Mélancolie.`}
},
}
/* -------------------------------------------- */
const mauvaisesRencontres = [
{ code: "mangeur", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6", refoulement: 2, isMauvaise: true },
{ code: "mangeur2d6", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "2d6", refoulement: 2, isMauvaise: true },
{ code: "reflet+4", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true },
{ code: "tbblanc+4", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6+4", refoulement: 2, isPersistant: true, isMauvaise: true },
{ code: "tbnoir+4", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8+4", refoulement: 2, isPersistant: true, isMauvaise: true },
{ code: "passfou", name: "Passeur fou", type: "passeurfou", genre: "m", force: "2d8", refoulement: 2, isMauvaise: true },
{ code: "tbrouge", name: "Tourbillon rouge", type: "tbrouge", genre: "m", force: "2d8", refoulement: 3, isPersistant: true, isMauvaise: true }
]
/* -------------------------------------------- */
const rencontresStandard = [
{ code: "messager", name: "Messager des Rêves", type: "messager", genre: "m", force: "2d4", ignorer: true },
{ code: "passeur", name: "Passeur des Rêves", type: "passeur", genre: "m", force: "2d4", ignorer: true },
{ code: "fleur", name: "Fleur des Rêves", type: "fleur", genre: "f", force: "1d6", ignorer: true },
{ code: "mangeur", name: "Mangeur de Rêve", type: "mangeur", genre: "m", force: "1d6" },
{ code: "changeur", name: "Changeur de Rêve", type: "changeur", genre: "m", force: "2d6" },
{ code: "briseur", name: "Briseur de Rêve", type: "briseur", genre: "m", force: "2d6", quitterTMR: true },
{ code: "reflet", name: "Reflet d'ancien Rêve", type: "reflet", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbblanc", name: "Tourbillon blanc", type: "tbblanc", genre: "m", force: "2d6", isPersistant: true },
{ code: "tbnoir", name: "Tourbillon noir", type: "tbnoir", genre: "m", force: "2d8", isPersistant: true },
{ code: "rdd", name: "Rêve de Dragon", type: "rdd", genre: "m", force: "1dr + 7", refoulement: 2, quitterTMR: true }
];
const rencontresPresentCite = [
{ code: "messager2d6", name: "Messager des Rêves", type: "messager", genre: "m", force: "2d6", ignorer: true },
{ code: "passeur2d6", name: "Passeur des Rêves", type: "passeur", genre: "m", force: "2d6", ignorer: true },
{ code: "fleur2d6", name: "Fleur des Rêves", type: "fleur", genre: "f", force: "2d6", ignorer: true }
]
const rencontresAll = [].concat(rencontresStandard).concat(mauvaisesRencontres).concat(rencontresPresentCite);
const tableRencontres = {
cite: [{ code: 'messager', range: [1, 25] }, { code: 'passeur', range: [26, 50] }, { code: 'fleur', range: [51, 65] }, { code: 'mangeur', range: [66, 70] }, { code: 'changeur', range: [71, 80] }, { code: 'briseur', range: [81, 85] }, { code: 'reflet', range: [86, 90] }, { code: 'tbblanc', range: [91, 94] }, { code: 'tbnoir', range: [95, 97] }, { code: 'rdd', range: [98, 100] }],
sanctuaire: [{ code: 'messager', range: [1, 25] }, { code: 'passeur', range: [26, 50] }, { code: 'fleur', range: [51, 65] }, { code: 'mangeur', range: [66, 70] }, { code: 'changeur', range: [71, 80] }, { code: 'briseur', range: [81, 85] }, { code: 'reflet', range: [86, 90] }, { code: 'tbblanc', range: [91, 94] }, { code: 'tbnoir', range: [95, 97] }, { code: 'rdd', range: [98, 100] }],
plaines: [{ code: 'messager', range: [1, 20] }, { code: 'passeur', range: [21, 40] }, { code: 'fleur', range: [41, 55] }, { code: 'mangeur', range: [56, 60] }, { code: 'changeur', range: [61, 75] }, { code: 'briseur', range: [76, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }],
pont: [{ code: 'messager', range: [1, 20] }, { code: 'passeur', range: [21, 40] }, { code: 'fleur', range: [41, 55] }, { code: 'mangeur', range: [56, 60] }, { code: 'changeur', range: [61, 75] }, { code: 'briseur', range: [76, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }],
collines: [{ code: 'messager', range: [1, 15] }, { code: 'passeur', range: [16, 30] }, { code: 'fleur', range: [31, 42] }, { code: 'mangeur', range: [43, 54] }, { code: 'changeur', range: [55, 69] }, { code: 'briseur', range: [70, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }],
foret: [{ code: 'messager', range: [1, 15] }, { code: 'passeur', range: [16, 30] }, { code: 'fleur', range: [31, 42] }, { code: 'mangeur', range: [43, 54] }, { code: 'changeur', range: [55, 69] }, { code: 'briseur', range: [70, 82] }, { code: 'reflet', range: [83, 88] }, { code: 'tbblanc', range: [89, 93] }, { code: 'tbnoir', range: [94, 97] }, { code: 'rdd', range: [98, 100] }],
monts: [{ code: 'messager', range: [1, 10] }, { code: 'passeur', range: [11, 20] }, { code: 'fleur', range: [21, 26] }, { code: 'mangeur', range: [27, 44] }, { code: 'changeur', range: [45, 59] }, { code: 'briseur', range: [60, 75] }, { code: 'reflet', range: [76, 85] }, { code: 'tbblanc', range: [86, 92] }, { code: 'tbnoir', range: [93, 97] }, { code: 'rdd', range: [98, 100] }],
desert: [{ code: 'messager', range: [1, 10] }, { code: 'passeur', range: [11, 20] }, { code: 'fleur', range: [21, 26] }, { code: 'mangeur', range: [27, 44] }, { code: 'changeur', range: [45, 59] }, { code: 'briseur', range: [60, 75] }, { code: 'reflet', range: [76, 85] }, { code: 'tbblanc', range: [86, 92] }, { code: 'tbnoir', range: [93, 97] }, { code: 'rdd', range: [98, 100] }],
fleuve: [{ code: 'messager', range: [1, 5] }, { code: 'passeur', range: [6, 10] }, { code: 'fleur', range: [11, 13] }, { code: 'mangeur', range: [14, 37] }, { code: 'changeur', range: [38, 49] }, { code: 'briseur', range: [50, 65] }, { code: 'reflet', range: [66, 79] }, { code: 'tbblanc', range: [80, 89] }, { code: 'tbnoir', range: [90, 97] }, { code: 'rdd', range: [98, 100] }],
lac: [{ code: 'messager', range: [1, 5] }, { code: 'passeur', range: [6, 10] }, { code: 'fleur', range: [11, 13] }, { code: 'mangeur', range: [14, 37] }, { code: 'changeur', range: [38, 49] }, { code: 'briseur', range: [50, 65] }, { code: 'reflet', range: [66, 79] }, { code: 'tbblanc', range: [80, 89] }, { code: 'tbnoir', range: [90, 97] }, { code: 'rdd', range: [98, 100] }],
marais: [{ code: 'messager', range: [1, 2] }, { code: 'passeur', range: [3, 4] }, { code: 'fleur', range: [5, 5] }, { code: 'mangeur', range: [6, 29] }, { code: 'changeur', range: [30, 39] }, { code: 'briseur', range: [40, 60] }, { code: 'reflet', range: [61, 75] }, { code: 'tbblanc', range: [76, 86] }, { code: 'tbnoir', range: [87, 97] }, { code: 'rdd', range: [98, 100] }],
gouffre: [{ code: 'messager', range: [1, 2] }, { code: 'passeur', range: [3, 4] }, { code: 'fleur', range: [5, 5] }, { code: 'mangeur', range: [6, 29] }, { code: 'changeur', range: [30, 39] }, { code: 'briseur', range: [40, 60] }, { code: 'reflet', range: [61, 75] }, { code: 'tbblanc', range: [76, 86] }, { code: 'tbnoir', range: [87, 97] }, { code: 'rdd', range: [98, 100] }],
necropole: [{ code: 'mangeur', range: [1, 20] }, { code: 'changeur', range: [21, 30] }, { code: 'briseur', range: [31, 50] }, { code: 'reflet', range: [51, 65] }, { code: 'tbblanc', range: [66, 80] }, { code: 'tbnoir', range: [81, 97] }, { code: 'rdd', range: [98, 100] }],
desolation: [{ code: 'mangeur', range: [1, 20] }, { code: 'changeur', range: [21, 30] }, { code: 'briseur', range: [31, 50] }, { code: 'reflet', range: [51, 65] }, { code: 'tbblanc', range: [66, 80] }, { code: 'tbnoir', range: [81, 97] }, { code: 'rdd', range: [98, 100] }]
}
/* -------------------------------------------- */ /* -------------------------------------------- */
export class TMRRencontres { export class TMRRencontres {
static gestionRencontre = {}
/* -------------------------------------------- */
static init() { static init() {
for (let type in typeRencontres) { const tmrRencontre = new TMRRencontres();
TMRRencontres.register(type, typeRencontres[type]); game.system.rdd.rencontresTMR = tmrRencontre;
}
} }
/* -------------------------------------------- */ constructor(){
static register(type, rencontre) { this.table = new CompendiumTable('rencontres', 'Item', 'rencontre', Misc.ascending(it => it.system.ordreTri));
TMRRencontres.gestionRencontre[type] = rencontre;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
/** /**
* Retourne une recontre en fonction de la case et du tirage * Retourne une recontre en fonction de la case et du tirage
* @param {*} terrain * @param {*} terrain
* @param {*} roll * @param {*} forcedRoll
*/ */
static async rollRencontre(terrain, roll = undefined) { async rollRencontre(terrain, forcedRoll) {
if (!terrain) { terrain = TMRUtility.findTMRLike(terrain);
ChatMessage.create({ content: "Un type de case doit être indiqué (par exemple sanctuaire, desert ou cité)" }); if (terrain == undefined) {
return false; return undefined;
} }
if (!roll || roll <= 0 || roll > 100) {
roll = await RdDDice.rollTotal("1d100"); if (forcedRoll && (forcedRoll <= 0 || forcedRoll > 100)) {
forcedRoll = undefined;
} }
let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll); const codeTerrain = Grammar.toLowerCaseNoAccent(terrain)
ChatMessage.create({ const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
user: game.user.id, const frequence = it => it.system.frequence[codeTerrain];
whisper: [game.user.id], const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${rencontre.force} Points de Rêve` if (row) {
}); await CompendiumTableHelpers.tableRowToChatMessage(row);
return false; }
return row?.document;
}
async chatTable(terrain) {
const codeTerrain = Grammar.toLowerCaseNoAccent(terrain)
const isMauvaise = codeTerrain == 'mauvaise';
const filtreMauvaise = isMauvaise ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
const typeName = isMauvaise ? 'Mauvaises rencontres' : `Rencontres en ${Misc.upperFirst(terrain)}`;
return await this.table.toChatMessage(frequence, filtreMauvaise, typeName);
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
static getRencontre(index) { async createRencontre(rencontre, tmr = undefined) {
let rencontre; return rencontre.clone({
if (isNaN(index)) { 'system.force': await RdDDice.rollTotal(rencontre.system.formule),
rencontre = rencontresAll.find(r => r.type == index) ?? rencontresAll.find(r => r.code == index) 'system.coord': tmr?.coord,
'system.date': game.system.rdd.calendrier.getDateFromIndex(),
'system.heure': game.system.rdd.calendrier.getCurrentHeure()
}, { save: false });
}
async calculRencontre(rencontre, tmr = undefined) {
if (rencontre.system.coord == "") {
rencontre.system.coord = tmr?.coord;
} }
else if (0 <= index && index < rencontresAll.length) { if (rencontre.system.force == 0) {
rencontre = rencontresAll[index]; rencontre.system.force = await RdDDice.rollTotal(rencontre.system.formule);
} }
if (rencontre) { if (rencontre.system.date == "") {
return duplicate(rencontre); rencontre.system.date = game.system.rdd.calendrier.getDateFromIndex();
} }
else { if (rencontre.system.heure == "") {
ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.<br>Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`) rencontre.system.heure = game.system.rdd.calendrier.getCurrentHeure();
}
return rencontre;
}
async getPresentsCite() {
const rencontres = await SystemCompendiums.getDefaultItems('rencontres');
return rencontres.filter(it => !it.system.mauvaiseRencontre && it.system.presentCite).map(it =>
it.clone({ 'system.formule': "2d6" }, { save: false }));
}
async getReveDeDragon(force) {
const rencontres = await SystemCompendiums.getDefaultItems('rencontres');
const reveDeDragon = rencontres.find(it => Grammar.equalsInsensitive(it.name, 'Rêve de Dragon'));
return reveDeDragon?.clone({ 'system.force': force }, { save: false });
}
/* -------------------------------------------- */
async getRencontreAleatoire(tmr, mauvaise) {
const codeTerrain = mauvaise ? 'mauvaise' : tmr.type;
const filtreMauvaise = codeTerrain == 'mauvaise' ? it => it.system.mauvaiseRencontre : it => !it.system.mauvaiseRencontre;
const frequence = it => it.system.frequence[codeTerrain];
const row = await this.table.getRandom(frequence, filtreMauvaise);
if (row) {
const rencontre = await this.createRencontre(row.document, tmr);
await this.$chatRolledRencontre(row, rencontre, tmr);
return rencontre;
} }
return undefined; return undefined;
} }
/* -------------------------------------------- */
static async getRencontreAleatoire(terrain, roll = undefined) {
if (!roll || roll <= 0 || roll > 100) {
roll = await RdDDice.rollTotal("1d100");
}
terrain = Grammar.toLowerCaseNoAccent(terrain);
const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code;
const rencontre = duplicate(rencontresStandard.find(it => it.code == code));
rencontre.roll = roll;
await TMRRencontres.evaluerForceRencontre(rencontre);
return rencontre;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getMauvaiseRencontre(index = undefined) { async $chatRolledRencontre(row, rencontre,tmr) {
const rencontre = duplicate( const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.html',
(index && index >= 0 && index < mauvaisesRencontres.length) {
? mauvaisesRencontres[index] roll: row.roll,
: await RdDDice.rollOneOf(mauvaisesRencontres)); rencontre,
await TMRRencontres.evaluerForceRencontre(rencontre); row,
return rencontre; percentages: (row.total == 100) ? '%' : '',
} tmr,
isGM: game.user.isGM,
/* -------------------------------------------- */ });
static async evaluerForceRencontre(rencontre) { const messageData = {
const rollForce = new Roll(rencontre.force); user: game.user.id,
await rollForce.evaluate(); type: CONST.CHAT_MESSAGE_TYPES.ROLL,
rencontre.force = rollForce.total; roll: row.roll,
return rencontre.force; sound: CONFIG.sounds.dice,
} content: flavorContent
};
/* -------------------------------------------- */ ChatMessage.create(messageData, { rollMode: "gmroll" });
static isReveDeDragon(rencontre) {
return rencontre.type == "rdd";
}
/* -------------------------------------------- */
static getGestionRencontre(name) {
let gestion = TMRRencontres.gestionRencontre[name];
if (!gestion) {
ui.notifications.error(`La rencontre ${name} est inconnue, pas de méthode de gestion associée`)
gestion = TMRRencontres.gestionRencontre['messager'];
}
return gestion;
}
/* -------------------------------------------- */
static async gererRencontre(tmrDialog, rencData) {
let gestion = TMRRencontres.getGestionRencontre(rencData.rencontre.type);
if (rencData.rolled.isSuccess) {
rencData.message = await gestion.msgSucces(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`;
}
rencData.poesie = gestion.poesieSucces;
return gestion.postSucces;
}
rencData.message = await gestion.msgEchec(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`;
}
rencData.poesie = gestion.poesieEchec;
return gestion.postEchec;
}
/* -------------------------------------------- */
static async msgEchecPasseurFou(tmrData) {
tmrData.sortReserve = RdDDice.rollOneOf(tmrData.actor.itemTypes['sortreserve']);
if (tmrData.sortReserve) {
// Passeur fou positionne sur la case d'un sort en réserve
tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord);
} else {
// Déplacement aléatoire de la force du Passeur Fou
const newCoord = await RdDDice.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force));
tmrData.newTMR = TMRUtility.getTMR(newCoord);
}
if (tmrData.sortReserve) {
return `Le ${tmrData.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${tmrData.newTMR.label} déclencher votre sort en réserve de ${tmrData.sortReserve.name}.`;
}
else {
return `Le ${tmrData.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${tmrData.newTMR.label}`;
}
}
/* -------------------------------------------- */
static async postEchecPasseurFou(tmrDialog, tmrData) {
if (tmrData.sortReserve) {
await tmrDialog.processSortReserve(tmrData.sortReserve);
}
await tmrDialog.positionnerDemiReve(tmrData.newTMR.coord);
if (tmrData.sortReserve) {
tmrDialog.close();
}
}
/* -------------------------------------------- */
static async onPostEchecTourbillon(tmrDialog, tmrData, cases) {
await tmrData.actor.reveActuelIncDec(-cases);
await TMRRencontres._toubillonner(tmrDialog, tmrData.actor, cases);
}
/* -------------------------------------------- */
static async onPostEchecTourbillonRouge(tmrDialog, rencontre) {
await rencontre.actor.reveActuelIncDec(-2); // -2 pts de Reve a chaque itération
TMRRencontres._toubillonner(tmrDialog, rencontre.actor, 4);
await rencontre.actor.santeIncDec("vie", -1); // Et -1 PV
}
/* -------------------------------------------- */
static async _toubillonner(tmrDialog, actor, cases) {
let coord = actor.system.reve.tmrpos.coord;
for (let i = 0; i < cases; i++) {
coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
}
await tmrDialog.positionnerDemiReve(coord)
}
/* -------------------------------------------- */
static async onPostSuccessReveDeDragon(tmrDialog, tmrData) {
if (tmrData.rolled.isPart) {
await tmrData.actor.appliquerAjoutExperience(tmrData);
}
await tmrData.actor.resultCombatReveDeDragon(tmrData);
}
/* -------------------------------------------- */
static async onPostEchecReveDeDragon(tmrDialog, tmrData) {
await tmrData.actor.resultCombatReveDeDragon(tmrData);
tmrDialog.close();
} }
} }

View File

@@ -1,4 +1,3 @@
import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js"; import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js"; import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js"; import { RdDDice } from "./rdd-dice.js";
@@ -287,13 +286,30 @@ export class TMRUtility {
const tmr = TMRMapping[coord]; const tmr = TMRMapping[coord];
return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label; return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label;
} }
static findTMRLike(type, options = {inclusMauvaise:true}) {
const choix = [...Object.values(TMRType)]
if (options.inclusMauvaise){
choix.push({name: 'Mauvaise'});
}
const selection = Misc.findAllLike(type, choix).map(it => it.name);
if (selection.length == 0) {
ui.notifications.warn(`Un type de TMR doit être indiqué, '${type}' n'est pas trouvé dans ${choix}`);
return undefined;
}
if (selection.length > 1) {
ui.notifications.warn(`Plusieurs types de TMR pourraient correspondre à '${type}': ${selection}`);
return undefined;
}
return selection[0];
}
static typeTmrName(type) { static typeTmrName(type) {
return Misc.upperFirst(TMRType[Grammar.toLowerCaseNoAccent(type)].name); return Misc.upperFirst(TMRType[Grammar.toLowerCaseNoAccent(type)].name);
} }
static buildSelectionTypesTMR(typesTMR) { static buildSelectionTypesTMR(typesTMR) {
typesTMR= typesTMR?? []; typesTMR = typesTMR?? [];
return Object.values(TMRType).map(value => Misc.upperFirst(value.name)) return Object.values(TMRType).map(value => Misc.upperFirst(value.name))
.sort() .sort()
.map(name => { return { name: name, selected: typesTMR.includes(name) } }); .map(name => { return { name: name, selected: typesTMR.includes(name) } });
@@ -307,35 +323,6 @@ export class TMRUtility {
return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais'; return tmr.type == 'fleuve' || tmr.type == 'lac' || tmr.type == 'marais';
} }
/* -------------------------------------------- */
/** Some debug functions */
static async setForceRencontre(index, force = undefined) {
this.prochaineRencontre = TMRRencontres.getRencontre(index);
if (this.prochaineRencontre) {
if (force) {
this.prochaineRencontre.force = force;
}
else {
await TMRRencontres.evaluerForceRencontre(this.prochaineRencontre);
}
console.log("La prochaine rencontre sera:", this.prochaineRencontre.name, " force:", this.prochaineRencontre.force);
}
else {
ui.notifications.warn("Pas de prochaine rencontre valide pour " + index);
}
}
/* -------------------------------------------- */
static isForceRencontre() {
return this.prochaineRencontre;
}
/* -------------------------------------------- */
static utiliseForceRencontre() {
const rencontre = this.prochaineRencontre;
this.prochaineRencontre = undefined;
return rencontre;
}
/* -------------------------------------------- */ /* -------------------------------------------- */
static async getDirectionPattern() { static async getDirectionPattern() {
return await RdDDice.rollOneOf(tmrRandomMovePatten); return await RdDDice.rollOneOf(tmrRandomMovePatten);
@@ -343,24 +330,15 @@ export class TMRUtility {
/* -------------------------------------------- */ /* -------------------------------------------- */
static async deplaceTMRAleatoire(actor, coord) { static async deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, await TMRUtility.getDirectionPattern(), 1); const currentOddq = TMRUtility.coordTMRToOddq(coord);
} const direction = await TMRUtility.getDirectionPattern();
currentOddq.col = currentOddq.col + direction.col;
/* -------------------------------------------- */ currentOddq.row = currentOddq.row + direction.row;
static async deplaceTMRSelonPattern(actor, coordTMR, direction, nTime) { if (this.isOddqInTMR(currentOddq)) { // Sortie de carte ! Ré-insertion aléatoire
let coord; return TMRUtility.getTMR(TMRUtility.oddqToCoordTMR(currentOddq));
for (let i = 0; i < nTime; i++) { } else {
let currentOddq = TMRUtility.coordTMRToOddq(coordTMR); return await actor.reinsertionAleatoire('Sortie de carte');
currentOddq.col = currentOddq.col + direction.col;
currentOddq.row = currentOddq.row + direction.row;
if (this.isOddqInTMR(currentOddq)) { // Sortie de carte ! Ré-insertion aléatoire
coord = TMRUtility.getTMR(TMRUtility.oddqToCoordTMR(currentOddq));
} else {
coord = await actor.reinsertionAleatoire('Sortie de carte');
}
console.log("Nouvelle case iteration !!!", i, coord);
} }
return coord;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -372,9 +350,12 @@ export class TMRUtility {
return Object.values(TMRMapping).filter(filter); return Object.values(TMRMapping).filter(filter);
} }
static getCasesType(type) {
return TMRUtility.filterTMR(it => it.type == type).map(it => it.coord);
}
static findTMR(search) { static findTMR(search) {
const labelSearch = Grammar.toLowerCaseNoAccent(search) return TMRUtility.filterTMR(it => Grammar.includesLowerCaseNoAccent(it.label, search) || it.coord == search);
return TMRUtility.filterTMR(it => Grammar.toLowerCaseNoAccent(it.label).match(labelSearch) || it.coord == search);
} }
static filterTMRCoord(filter) { static filterTMRCoord(filter) {

View File

@@ -0,0 +1,18 @@
import { Grammar } from "../grammar.js";
import { Draconique } from "./draconique.js";
import { Misc } from "../misc.js";
export class AugmentationSeuil extends Draconique {
constructor() {
super();
}
type() { return 'tete' }
match(item) { return Draconique.isTeteDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('augmentation du seuil de reve'); }
manualMessage() { return false }
async onActorCreateOwned(actor, tete) {
const seuil = Misc.toInt(actor.system.reve.seuil.value) + 2;
await actor.update({ "system.reve.seuil.value": seuil })
}
}

View File

@@ -17,6 +17,7 @@ import { Pelerinage } from "./pelerinage.js";
import { Periple } from "./periple.js"; 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";
export class EffetsDraconiques { export class EffetsDraconiques {
@@ -37,6 +38,7 @@ export class EffetsDraconiques {
static pelerinage = new Pelerinage(); static pelerinage = new Pelerinage();
static periple = new Periple(); static periple = new Periple();
static urgenceDraconique = new UrgenceDraconique(); static urgenceDraconique = new UrgenceDraconique();
static augmentationSeuil = new AugmentationSeuil();
static init() { static init() {
Draconique.register(EffetsDraconiques.carteTmr); Draconique.register(EffetsDraconiques.carteTmr);
@@ -56,6 +58,7 @@ export class EffetsDraconiques {
Draconique.register(EffetsDraconiques.pelerinage); Draconique.register(EffetsDraconiques.pelerinage);
Draconique.register(EffetsDraconiques.periple); Draconique.register(EffetsDraconiques.periple);
Draconique.register(EffetsDraconiques.urgenceDraconique); Draconique.register(EffetsDraconiques.urgenceDraconique);
Draconique.register(EffetsDraconiques.augmentationSeuil)
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@@ -116,6 +119,10 @@ export class EffetsDraconiques {
.filter(it => Grammar.includesLowerCaseNoAccent(it.name, name)); .filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
} }
static countAugmentationSeuil(actor) {
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'Augmentation du seuil de rêve').length;
}
static isDonDoubleReve(actor) { static isDonDoubleReve(actor) {
return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'Don de double-rêve').length>0; return EffetsDraconiques.filterItems(actor, Draconique.isTeteDragon, 'Don de double-rêve').length>0;
} }

View File

@@ -46,15 +46,13 @@ export class PresentCites extends Draconique {
} }
async choisirUnPresent(casetmr, onChoixPresent) { async choisirUnPresent(casetmr, onChoixPresent) {
const presents = await game.system.rdd.rencontresTMR.getPresentsCite()
const buttons = {};
presents.forEach(r => buttons['present'+r.id] = { icon: '<i class="fas fa-check"></i>', label: r.name, callback: async () => onChoixPresent(r) });
let d = new Dialog({ let d = new Dialog({
title: "Présent des cités", title: "Présent des cités",
content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faite votre choix`, content: `La ${this.tmrLabel(casetmr)} vous offre un présent, faites votre choix`,
buttons: { buttons: buttons
messager: { icon: '<i class="fas fa-check"></i>', label: "Un Messager des rêves", callback: () => onChoixPresent('messager2d6') },
passeur: { icon: '<i class="fas fa-check"></i>', label: "Un Passeur des rêves", callback: () => onChoixPresent('passeur2d6') },
fleur: { icon: '<i class="fas fa-check"></i>', label: "Une Fleur des rêves", callback: () => onChoixPresent('fleur2d6') },
},
default: "fleur"
}); });
d.render(true); d.render(true);
} }

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