Compare commits

...

510 Commits

Author SHA1 Message Date
3ac9f487d0 Fix: perte de rêve potions enchantées
La perte de rêve des potions enchantées bloquait le processus de
récupération de château dormant
2023-12-22 20:12:58 +01:00
fa67c3d9c1 Merge pull request 'Version 11.2.11' (#692) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#692
2023-12-22 09:30:48 +01:00
5b443f9ac0 Version 11.2.11 2023-12-22 02:25:30 +01:00
b0098574a0 Fix: refoulement
Le refoulement ne fonctionnait plus. Merci à javascript+VSCode
pour l'incapacité de fournir de l'analyse de code statique...
2023-12-22 02:21:22 +01:00
5729f7e926 Bordure des images de profils
Remplacement de la bordure noire inesthétique avec des images de
profil sous forme de badge ronds, en utilisant juste une variation
de couleur de fond.
2023-12-22 02:21:22 +01:00
0b66c945b8 Mise à jour couleur images compcreature
Passage du blanc à la couleur habituelle
2023-12-22 02:21:22 +01:00
f0fc44e00f Merge pull request '11.2.10 - Les expériences d'Akarlikarlikar' (#691) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#691
2023-12-11 09:34:21 +01:00
6b7c2ad2f9 Version 11.2.10 2023-12-10 22:26:52 +01:00
0ac5d317ce Icônes des boutons cuisiner/manger 2023-12-10 22:19:51 +01:00
f8a90fc3c3 Fontawsome solid
traduction de fas => fa-solid
2023-12-10 22:19:51 +01:00
6dd647b787 Expérience des caractéristiques dérivées
Une fenêtre de répartition est ouverte quand plusieurs
caractéristiques peuvent recevoir l'expérience. Sinon,
l'expérience est attribuée automatiquement.

L'expérience n'est plus ajoutée en Force si supérieure à Taille+4
2023-12-10 22:19:51 +01:00
1c55491ac7 Ajustements des tooltips TMR 2023-12-10 22:19:50 +01:00
2b08678518 Merge pull request 'Version 11.2.9 - La barbe d'Akarlikarlikar' (#690) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#690
2023-12-09 16:23:41 +01:00
355f2e4088 Version 11.2.9 2023-12-09 15:33:33 +01:00
e0862105f9 Icône d'état empoignade 2023-12-09 15:33:33 +01:00
3ab48511a0 Sort en réserve en fleuve
Les sorts en réserve en fleuve sont indiqués sur toutes les cases fleuve
2023-12-09 15:33:33 +01:00
05cd02b694 Fix: deprecation effects flags.core.statusId
Remplacement de la logique basée sur les flags par le set de "statuses"
2023-12-09 15:33:33 +01:00
56a5d06f16 Fix erreur console ouverture TMR
quand TMR pas affichées, bringToTop ne marche pas
2023-12-09 15:33:32 +01:00
f34db764cb Permettre les jets de chance sans astrologie
Quand on fait un jet de chance pour la journée, permettre de
ne pas utiliser l'ajustement astrologique
2023-12-09 15:33:32 +01:00
7267cd4096 Amélioration de tooltips
- style en phase avec le système
- icones attaque/d6/soins pour le HUD
- tooltip plus détaillé pour le HUD
- icône et bouton pour déterminer les chiffres astraux (astrologie)
- tooltips pour les boutons archétype
- suppression de log sur chaque point de coeur
2023-12-09 15:33:32 +01:00
e4bd2d2f27 Merge pull request 'v11' (#689) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#689
2023-12-08 13:24:05 +01:00
eb09714579 Version 11.2.8 2023-12-08 04:03:53 +01:00
62cc3fc96b Correction de l'ajustement de luminosité
On passe de la nuit début vaisseau au jour fin vaisseau
2023-12-08 04:00:17 +01:00
5e140546ea Les tooltips de compétences et l'expérience
Limitation du tooltip sur les compétences qui masquait les
informations d'expérience
2023-12-08 03:07:27 +01:00
ab9a21f402 Utilisation de get plutôt que find par id 2023-12-08 02:38:57 +01:00
8e41250f64 Affichage de cœur dans les ajustements 2023-12-08 02:38:23 +01:00
095eed9da3 Fix: éliminer le risque de jets qui plante
Bloquait les rencontres en TMR.

Quand un rollData ne contient pas les sous-noeuds pouvant être
utilisés par les ajustements possibles, le jet de dés était perdu.

Le calcul d'ajustements ajoute maintenant les noeuds use/ajustements
s'ils ne sont pas fournis, pour éviter le risque.
2023-12-08 02:37:47 +01:00
55c98d1dce Merge pull request '11.2.7' (#688) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#688
2023-12-04 09:29:35 +01:00
b5dc14687e Version 11.2.7 2023-12-04 02:35:47 +01:00
1208eb8ae1 Amélioration des tooltips
- title/alt remplacés par des data-tooltip
- description de ce que font les boutons
- description des items survolés
2023-12-04 02:32:26 +01:00
a46acb7952 Merge pull request 'Action de visualisation avec droits limités' (#687) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#687
2023-12-03 20:05:31 +01:00
a68057900d Action de visualisation avec droits limités 2023-12-02 14:40:39 +01:00
57bc1b6c1f Merge pull request '11.2.6 - Les réveils difficiles d'Akarlikarlikar' (#686) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#686
2023-11-28 00:17:04 +01:00
6101bc91a6 Version 11.2.6 2023-11-27 23:49:43 +01:00
33ced5715d Le coeur s'applique à ChâteauDormant 2023-11-27 23:45:33 +01:00
50db9ba709 Fix Chateau Dormant pour les potions 2023-11-27 23:43:45 +01:00
957e31b188 Fix subacteurs 2023-11-27 14:32:39 +01:00
74571c9966 Correction sur Items 2023-11-26 22:51:33 +01:00
5155fb4669 Correction sur Class 2023-11-26 19:58:32 +01:00
698ed75d46 Fix version 2023-11-24 08:52:42 +01:00
37ba7166bf Merge pull request 'v11.2.2 - Les tendres moments d'Akarlikarlikar' (#685) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#685
2023-11-24 08:51:05 +01:00
28af8c3c58 v11.2.2 - Les tendres moments d'Akarlikarlikar
- On peut maintenant avoir des points de cœur pour des suivants/
   compagnons
  - diminuer les points de coeurs fait perdre du moral
  - on peut proposer un tendre moment
  - les jets de volonté peuvent être ajustés selon les points de cœur
- Fixes
  - La résistance est de 1 par défaut pour les équipements
  - Les armes de créatures sont de nouveau utilisables depuis les tokens
  - Pas de notifications de signe draconique quand on regarde les TMR
   sans monter
  - Correction d'un problème de contextes WebGL causé par des
   ouvertures/fermetures de TMRs
  - On peut maintenant prendre un objet d'un acteur-token pour
    l'ajouter à un autre acteur
  - On ne peut plus donner d'objets d'un acteur à un acteur-token
2023-11-24 03:02:18 +01:00
4a03c222d5 Gestion des points de coeur
- Les suivants/compagnons/amoureux sont dans l'onglet description
- si acteurs "liés", ils peuvent avoir des points de coeur
- les jets de volonté peuvent être ajustés s'ils concernent un
  compagnon pour lequel on a du coeur
- on peut ajouter des points de coeur (entre la gestion de Chateau
  dormant par le gardien et le jet de repos si ce mode est utilisé)
- on peut retirer des points de coeur en perdant du moral (mêmes
  conditions)
- on peut passer de tendres moments si les deux acteurs acceptent
- les tendre moments font jouer un jet de moral adapté
- on peut perdre un point de coeur suite à un tendre moment qui ne fait
  pas gagner de moral
2023-11-24 02:57:43 +01:00
135546467d Envoi de message à plusieurs acteurs 2023-11-24 02:51:59 +01:00
b5db2a9ef3 Cleanup - preparation Coeur
Simplification de code:
- des Méthodes simples sur une ligne
- utilisation de item.update au lieu de updateEmbeddedDocuments
  quand possibe
- renommage des templates SubActeur
- déplacement de logs quand compétence non trouvée
2023-11-24 02:51:59 +01:00
bfb7b9b6bf taille des options 2023-11-24 02:51:59 +01:00
f0b7306885 Fix: animaux
- état général corrigé
- ajout de blessure, mise à jour endurance, ...
- calcul du malus d'état général
- ajustement des jets selon points de vie perdus
2023-11-24 02:51:52 +01:00
af410c1823 Typo: Tarot, Le Gibet 'Chute' 2023-11-24 02:49:49 +01:00
bf2b387fc4 Fix: Hooks.once('ready') not called
Sur Firefor, le onReady n'est jamais appelé, le système n'est alors
pas totalement initialisé, toute la partie calendrier n'est pas prête,
et donc les ajustement d'astrologie.
2023-11-24 02:49:49 +01:00
dfd915f8d1 Fix: prendre un objet d'un token
On peut maintenant prendre un objet à l'acteur d'un token non lié.

Avertissement quand on donne un objet à un token
2023-11-23 17:08:37 +01:00
4fe487a0ec Fix: problème de contexte WebGL
WARNING: Too many active WebGL contexts. Oldest context will be lost.

Semble lié à la destruction incorrecte de l'Application PIXI des TMR,
en cas de nombreuses ouvertures/fermetures
2023-11-23 17:08:37 +01:00
0ec31d8ddc Fix: double class 2023-11-23 00:33:19 +01:00
1bee911c35 Fix: pas de notification de signe si viewonly 2023-11-23 00:33:19 +01:00
ed7471875f Fix: armes des créatures utilisables 2023-11-23 00:33:18 +01:00
f50e9cd305 Déplacement terre d'attache 2023-11-21 21:08:46 +01:00
a2fcb9a453 Résistance 1 par défaut 2023-11-21 21:08:46 +01:00
3018e3522c Merge pull request 'v11.2.1 - La technique d'Akarlikarlikar' (#684) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#684
2023-11-20 23:32:34 +01:00
d16dec3278 Résistance par défaut de 1
Pour que les armes ne soient pas cassées par défaut
2023-11-20 18:55:01 +01:00
339e128b98 Version 11.2.1 - La technique d'Akarlikarlikar
- On peut créer des armes pour Corps à corps et Esquive. Barreaux de
chaise, armes improvisées, techniques d'art martiaux, pas de côté pour
faire trébucher l'adversaire... A vous de voir comment imaginer de
nouvelles "armes".
- Les armes avec une résistance de 0 ne peuvent pas être utilisées,
une image et un rappel indiquent qu'elles sont cassées
2023-11-20 18:42:29 +01:00
b1b56c13bf Montrer les armes cassées
Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
2023-11-20 17:24:50 +01:00
b07a3e18df Autoriser les armes de corps-à-corps
Barreaux de chaise, armes improvisées, techniques d'art martiaux, ...
peuvent être gérés comme des armes.
2023-11-20 17:24:50 +01:00
f446d897a7 Merge pull request 'v11.2.0 - Les Terres médianes d'Akarlikarlikar' (#683) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#683
2023-11-20 07:04:11 +01:00
4e89720341 Version 11.2.0 2023-11-20 00:44:27 +01:00
c1a5bd6eb3 Fix: jets d'encaissement forcés par le Gardien
Les jets d'encaissement forcés par le gardien ne peuvent plus donner
le deuxième d10 négatif si le MJ force un résultat inférieur à 11
2023-11-20 00:44:26 +01:00
bfd3b0d74a Réduction de l'espace des TMR 2023-11-20 00:44:26 +01:00
da3091dc4b Fix: urgence draconique, complément 2023-11-20 00:44:26 +01:00
c7e00749c9 Fix: deplacement aleatoire
Le déplacement aléatoire ne prenait pas compte de la différence
entre colonnes paires/impaires
2023-11-15 22:11:44 +01:00
30d41861fa Support hot reload for templates and css 2023-11-15 22:03:57 +01:00
60cebe60eb Fix #99 2023-11-15 16:34:59 +01:00
ac09e1854b Typo: Tricollet 2023-11-14 01:51:32 +01:00
9ff68884ce Merge pull request 'v11.1.6 - Les dissections de Werther de Zloth' (#682) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#682
2023-11-12 22:15:26 +01:00
09986115b8 Version 11.1.6 2023-11-12 21:18:52 +01:00
511ee5f241 Fix: encaissement joueur à valider par MJ 2023-11-12 21:18:07 +01:00
306d7c2150 Fix: délai de guérison après rétrogradation
Lorsqu'une blessure critique/grave rétrograde naturellement, le délai
avant le jet de récupération suivant est correctement augmenté.
2023-11-12 21:17:38 +01:00
5624bb1bf3 Merge pull request 'Fix: ajout de compétences aux créatures' (#681) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#681
2023-11-12 16:35:40 +01:00
b588c5f7f8 Fix: ajout de compétences aux créatures 2023-11-12 15:06:58 +01:00
6de34178b3 Sync version 2023-11-12 00:35:51 +01:00
0c90fba346 Merge pull request 'Préparation 11.1.5' (#680) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#680
2023-11-12 00:35:06 +01:00
f43b7ac651 Préparation Changelog 11.1.5 2023-11-12 00:33:25 +01:00
ac436bbb25 Fix: Recevoir une queue annulait l'insomnie 2023-11-12 00:24:42 +01:00
9093eadb23 Fix: urgence draconique 2023-11-12 00:22:29 +01:00
5821fc611f Fix: case pour trou noir 2023-11-11 22:33:51 +01:00
381242c8d0 Fix: le jet de vie indique la mort
Jusque là, le 20 indiquait la mort, mais ne diminuait pas la vie
en dessous de - SConst

Désormais:
- la vie passe à -SConst - 1 sur 20 au jet de vie
- Le message indique que le personnage est mort si sa vie est
  inférieure à -SConst
- le jet de vie n'est pas fait si le personnage est déjà mort
2023-11-11 21:30:25 +01:00
3ca33e85b7 Fix case pour réserve extensible 2023-11-11 21:30:02 +01:00
01399e922a Suppression de certains warnings 2023-11-11 20:38:16 +01:00
c6afb8d445 Fix demande defense 2023-11-11 20:23:07 +01:00
4d68318d85 Fix release 2023-11-11 09:07:28 +01:00
7811eae728 Merge pull request 'v11.1.3 - Werther de Zloth l'Onirique' (#679) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#679
2023-11-11 09:06:00 +01:00
2e74ccd1fe Fix: tooltip TMR par dessus les autres sprites 2023-11-11 00:52:57 +01:00
f98ece4ffd Version 11.1.3 2023-11-11 00:44:45 +01:00
ed068a8ddd Affichage du facteur significative 2023-11-11 00:44:11 +01:00
c938778267 Fix: afficher "0" au lieu de "+0" 2023-11-11 00:44:08 +01:00
9056514951 Fix: un plat raté est mauvais, pas exotique 2023-11-11 00:33:20 +01:00
1047720c24 Fix: jet d'appréciation sans compétence 2023-11-10 23:23:28 +01:00
43bcf1c336 Fix: afficher/masquer points de tâche 2023-11-10 23:22:45 +01:00
14d4638e56 Fix: error dans les logs si aucune scène active 2023-11-10 19:56:25 +01:00
c761aeceb3 Fix: calcul de l'état général 2023-11-10 19:54:32 +01:00
1759e6d1c3 Fix: tooltips sorts TMRs 2023-11-10 03:39:35 +01:00
ecb47addba Fix changelog 2023-11-10 01:27:52 +01:00
b18f93fbfb Merge pull request 'v11.1.2' (#678) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#678
2023-11-09 17:02:31 +01:00
19bfee7ea5 Release fix 2023-11-09 08:51:39 +01:00
93e44bb982 Version 11.1.2 2023-11-09 00:53:03 +01:00
12df910b3a Macro "Mon Personnage" pour les joueurs 2023-11-09 00:53:03 +01:00
2a3989ac2e Fix: les jets d'encaissement 2023-11-09 00:53:03 +01:00
ab884713f6 Merge pull request 'v11' (#677) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#677
2023-11-06 23:22:18 +01:00
940237852b Version 11.1.1 2023-11-06 23:06:02 +01:00
78ee23da96 Fix: proportions du gibier cuisiné 2023-11-06 23:06:02 +01:00
862a267683 Fix: ouvrir contenants des véhicules/créatures 2023-11-06 23:06:02 +01:00
2373acc295 Fix: afficher les vues détaillées 2023-11-06 23:06:02 +01:00
249d171511 Merge pull request 'v11.1.0 - Les choix de Werther de Zloth' (#676) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#676
2023-11-04 23:57:27 +01:00
018b6a32dd Nouveau personnage avec token lié par défaut 2023-11-04 18:50:07 +01:00
44ec511aa6 Version 11.1.0 2023-11-04 18:46:36 +01:00
ff44de3b3c Fix: charge en force 2023-11-04 18:46:36 +01:00
8101b905d8 Fix: choisir les haut rêvant pour signes
La fenêtre de signes draconiques ne sélectionne plus tout les
haut-rêvants par défaut
2023-11-04 18:34:30 +01:00
27dd89024e Cleanup 2023-11-04 18:34:30 +01:00
69a653d1e5 Jet de moral de château dormant optionnel 2023-11-04 18:31:54 +01:00
bea4124388 Séparation de l'Actor Créature 2023-11-04 18:31:53 +01:00
e5bb2e9afc Fix bug TMR sans fatigue 2023-11-04 18:31:53 +01:00
1d3ae9bb1a Séparation de l'Actor Entités 2023-11-04 18:17:40 +01:00
d4be2957a3 cleanup commerce 2023-11-04 18:16:20 +01:00
6c9d03be92 Récupération de rêve optionnelle 2023-11-04 18:16:20 +01:00
5a50917730 Récupération d'éthylisme optionnelle 2023-11-04 18:16:20 +01:00
d285e866be Récupération de chance optionnelle 2023-11-04 18:16:19 +01:00
ece9ab6f64 Séparation de l'Actor Vehicule 2023-11-04 18:16:19 +01:00
038e922f0f Option transformation de stress 2023-11-04 18:16:19 +01:00
728c5f2f8e Sur creation de personnage, force le lien du token 2023-11-04 17:48:59 +01:00
e6592f8333 Merge pull request 'v11.0.28 - les fractures de Khrachtchoum' (#675) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#675
2023-10-30 22:34:39 +01:00
42567e7ca0 Amélioration de fenêtre de jets
- indication du type de dégâts
- affichage du moral avant l'icone d'appel au moral
- meilleur alignement des différentes options
2023-10-30 21:33:38 +01:00
9d1fe6d8fd Version 11.0.28 2023-10-30 19:47:08 +01:00
f5bd0f32f4 Fix: affichage de la gravité des blessures
Le type de blessure est indiqué dans le résumé d'encaissement
2023-10-30 19:42:56 +01:00
fad29f9652 Jet de vie par les propriétaires
Les messages de tour sont séparés en deux:
- un message pour tout le monde disant de qui c'est le tour
- un message pour les propriétaires du token pour les informations
  de santé (jets de vie à faire, ...)

Seul les propriétaires peuvent déclencher les jets de vie
2023-10-30 19:40:21 +01:00
9d51631d5c Merge pull request 'v11.0.27' (#674) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#674
2023-10-25 00:02:40 +02:00
d1b73e7658 Version 11.0.27 2023-10-24 22:51:45 +02:00
54158ee10d Fix disparition du tooltip dans les TMR
Passage den eventMode static permet de ne pas faire disparaître le
tooltip.
2023-10-24 22:44:51 +02:00
e089bdf9c8 Surencombrement seulement sur actions physiques
CF p70
2023-10-24 22:32:49 +02:00
41ab593059 Fix: fabrication de potion depuis l'herbe
La fabrication ne marchait plus
2023-10-24 22:24:54 +02:00
42ad4c5b26 Fix Restauration TMR si minimisée
Lors d'une action dans les TMRs, si la fenêtre est minimisée,
on la réaffiche
2023-10-24 22:16:49 +02:00
85f8a716d4 Merge pull request '## v11.0.26 - le crépuscule de Khrachtchoum' (#673) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#673
2023-10-24 07:07:01 +02:00
47f305d865 Les attaques de créatures fonctionnent de nouveau 2023-10-24 00:50:16 +02:00
407b4f82d9 Version 11.0.26 2023-10-24 00:43:16 +02:00
c950f568fd Fix: les TMRs sont en arrière plan 2023-10-24 00:30:00 +02:00
0ed90f6177 Macros pour le corps à corps
Cas particulier car 3 utilisations possibles, et pas d'armes
2023-10-23 23:48:07 +02:00
b74fc27079 Minor cleanup 2023-10-23 23:38:34 +02:00
a65d4511c5 Fix Macros de combat et corps à corps
- gestion des armes à 1/2 mains depuis les armes / le combat
- gestion correcte des compétences d'attaques de créatures
- message pour les macros de compétence d'arme
2023-10-23 23:29:02 +02:00
e61417c44e Merge pull request '## v11.0.25 - la vision du rêve de Khrachtchoum' (#672) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#672
2023-10-22 21:40:42 +02:00
8ca725bd38 Version 11.0.25 2023-10-22 16:17:53 +02:00
441a5965c7 Fix TMR minimize/maximize
Au lieu de minimiser les TMRs, les actions dans les TMRs sont bloquées
tant qu'une action liée au TMRs est en cours.
2023-10-22 16:17:37 +02:00
f08c8f93da Merge pull request '## v11.0.24 - les couleurs de Khrachtchoum' (#671) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#671
2023-10-22 09:40:26 +02:00
d28362bf14 Version 11.0.24 2023-10-22 00:36:14 +02:00
e506382d18 typo: Nécropole de Throat 2023-10-22 00:36:10 +02:00
c1cecc76b3 Nouvelles TMRs 2023-10-22 00:19:45 +02:00
f2a3e1db45 Merge pull request 'v11.0.23 - la lumière de Khrachtchoum' (#669) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#669
2023-10-20 07:12:09 +02:00
b69359a47d Version 11.0.23 2023-10-20 02:36:49 +02:00
fe6c2e2ff2 Ajustement de luminosité automatique
Activable par le MJ avec le bouton lumière du calendrier
2023-10-20 02:36:00 +02:00
9bd13a6021 Comptence de creatures 2023-10-18 21:18:29 +02:00
a29630f9a2 Merge pull request 'v11.0.21 - les automatismes de Khrachtchoum le Problémeux' (#668) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#668
2023-10-18 21:17:03 +02:00
c7fd9f7596 Version 11.0.22
les automatismes de Khrachtchoum le Problémeux
2023-10-18 21:13:50 +02:00
7b18fd25c3 Macro pour compétences de créature 2023-10-18 21:08:01 +02:00
5c256e2c49 F>ix version 2023-10-04 21:44:41 +02:00
1c475348d5 Gestion des armes dans hotbar 2023-10-04 21:24:51 +02:00
de5d32f88f Gestion des armes dans hotbar 2023-10-04 09:33:24 +02:00
76a02d60ca Gestion des armes dans hotbar 2023-10-04 09:07:49 +02:00
724c556b9e Merge pull request 'v11' (#667) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#667
2023-10-04 09:07:10 +02:00
7dfba94a11 Nettoyage de date
Pas de "T" entre date et heure
2023-10-03 21:03:19 +02:00
928c7bbcfe Désespoir 2023-08-28 01:46:43 +02:00
222a06a978 Fix remoteCall 2023-08-15 17:24:01 +02:00
b4edaf8584 Fix remoteActorCall 2023-08-13 20:43:32 +02:00
3c062afd56 Fix remoteActorCall 2023-08-13 20:42:54 +02:00
6de4fff403 Merge pull request 'v11.0.15 - L'apprentissage de Khrachtchoum' (#666) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#666
2023-08-03 09:10:32 +02:00
3543f081b2 Version 11.0.15 2023-08-03 00:41:16 +02:00
56f14e12a2 Fix: regression sur les particulières
L'utilisation de la méthode clone() pôur cloner la compétence
supprime l'id de la compétence, du coup l'update pour y
ajouter de l'expérience ne marchait plus et bloquait la suite de la
résolution (pas de messages dans le tchat, ...)
2023-08-03 00:41:16 +02:00
e226af5ac5 Merge pull request 'v11.0.14' (#665) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#665
2023-07-30 09:25:10 +02:00
d8be37a2ec v11.0.14 2023-07-29 23:47:08 +02:00
ba2d9de7b6 Version 11.0.13
Les pincettes de Khrachtchoum le Problémeux
- Correction du calcul de la place restante lors de l'ajout dans un conteneur
2023-07-29 23:44:56 +02:00
6b8fb3267a Fix: calcul de la place dans un conteneur
Correction de l'ajout dans un conteneur, en faisant un calcul arrondi
pour éviter les problèmes de virgule flotante
2023-07-29 23:42:22 +02:00
05d6f64a31 Merge pull request 'v11.0.13 - La multiplication de l'eau de Khrachtchoum le Problémeux' (#664) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#664
2023-07-28 10:11:26 +02:00
c0570e58b4 Version 11.0.13 2023-07-27 19:21:48 +02:00
8389d578bc Fix: achat d'objet illimités
Lors de l'achat à un commerce avec une quantité illimité, on était
tout de même limité à la quantité de l'objet, même si elle n'était
pas diminuée
2023-07-27 19:17:57 +02:00
f05ef79b97 Merge pull request 'v11.0.12 - Les poids de la mesure de Khrachtchoum le Problémeux' (#663) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#663
2023-07-14 00:36:37 +02:00
d2a8bfae4f v11.0.12 - Les poids de la mesure
- Correction des malus de surencombrement
- Le malus armure est correctement affiché dans l'onglet des
  caractéristiques
2023-07-13 01:02:03 +02:00
d54834fa71 Amélioration des messages d'art 2023-07-13 01:02:03 +02:00
c898bf5212 Merge pull request 'Encombrement et malus armure' (#661) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#661
2023-07-11 14:46:14 +02:00
a118dc7334 Correction sur-Encombrement v2
Le malus appliqué est maintenant correct.

Avant, le malus pouvait avoir une virgule, et donc être arrondi
dans le malus vraiment appliqué même si affiché correctement.
2023-07-11 02:53:34 +02:00
46401e5d63 Cleanup: simplification _computeFinalLevel
méthode supprimée dasn RdDRoll (car basée sur les ajustements),
pas utile ici non plus.
2023-07-11 02:36:39 +02:00
7eb1d9f838 Fix affichage Malus Armure
Le malus armure est correctement affiché dans l'onglet caractéristiques.

Il n'est plus stocké dans l'acteur mais calculé.
2023-07-11 02:36:39 +02:00
1d8f4ebb88 Merge pull request 'Fix: sélection de compendiums que pour le MJ' (#660) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#660
2023-07-09 11:09:28 +02:00
145a92f462 Fix: sélection de compendiums que pour le MJ 2023-07-07 00:47:05 +02:00
5148d02314 Correction sur arrondi sur-encombrement 2023-07-01 21:28:18 +02:00
000c89b11a Merge pull request 'V11.0.11 - Les bleus de Khrachtchoum le Problémeux' (#659) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#659
2023-06-25 09:48:17 +02:00
5d4a18aac5 Version 11.0.11 2023-06-24 23:59:25 +02:00
34b5df637f Notifier le joueur qu'il peut passer sa nuit
Lorsque le MJ configure la nuit des personnages, une notification est
envoyée aux joueurs pour leur dire de gérer leur nuit.
2023-06-24 23:50:05 +02:00
22572ca98c Support des armes non mortelles 2023-06-24 23:40:07 +02:00
a6a1c1009e Merge pull request 'v11.0.10 - Les Songes de Khrachtchoum le Problémeux' (#658) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#658
2023-06-24 09:22:24 +02:00
288cf9162c Version v11.0.10 2023-06-24 01:48:34 +02:00
4b1381e535 Decompte des heure en cas de réveil
Si le gardien gère la durée des nuits, en cas de rêve de dragon,
les heures restant à dormir sont mises à jour.
2023-06-24 01:41:12 +02:00
78336a3f45 Fix: affichage sommeil avec RdD première heure
Le message ne s'affichait pas en cas de rêve de dragon dès la
première récupération
2023-06-24 01:19:54 +02:00
3001ae44de Endurance limitée en cas d'insomnie 2023-06-24 01:19:54 +02:00
a43ceb3188 Fix: lire depuis un livre 2023-06-24 01:19:54 +02:00
9e95a44efd Fix: click pour se déplacer dans les TMR 2023-06-24 01:19:54 +02:00
179ea0c85b Fix: selection de TMR des signes draconiques 2023-06-24 01:19:53 +02:00
3821b5bea1 Merge pull request 'v11.0.9 - Les Souvenirs de Khrachtchoum le Problémeux' (#657) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#657
2023-06-21 10:40:17 +02:00
2739c650d9 Version 11.0.9 - Les Souvenirs de Khrachtchoum 2023-06-20 23:43:59 +02:00
b101d58bee Correction typo "optionnelle" 2023-06-20 23:43:58 +02:00
0e3d721fc7 Nouvelle incarnation de l'archétype 2023-06-20 23:35:38 +02:00
e1e45a83be Correction titre des fenêtres Item 2023-06-20 23:35:38 +02:00
3b14e54829 Mode de saisie d'archétype 2023-06-20 23:35:38 +02:00
615a3f1315 Organisation des règles optionelles 2023-06-20 03:05:48 +02:00
ca72d088cc Merge pull request 'v11 - report v10.7.20' (#656) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#656
2023-06-19 15:36:53 +02:00
ac89b948ca Mise à jour du système
- lien vers le change log
- organisation des compendiums par défaut
2023-06-16 23:33:44 +02:00
f22c4d2ec8 Fin d'empoignade
En cours de round en atteignant 2 points d'empoignade, on peut
uniquement entraîner au sol.

En fin de round, si la victime est immobilisée, on peut projeter, ou
faire perdre de l'endurance
2023-06-15 02:03:49 +02:00
ffd80394d3 Restreindre les actions d'empoignade
Seul le propriétaire du défenseur peut effecuer les contres
d'empoignade ou tenter de se libérer.

Seul le propriétaire de l'empoigneur peut tenter d'empêcher
la libération du défenseur, de projeter au sol, ou de faire perdre
de l'endurance.
2023-06-15 02:03:43 +02:00
0959d1b18e Correction malus de taille empoignade 2023-06-15 02:03:37 +02:00
24e58abfcc Fix empoignade
- les items d'empoignade sont ajoutés par le MJ
- les caractéristiques du défenseur sont utilisées pour la défense
- la difficulté d'attaque est imposée au défenseur
- les particulières sont en finesse (p133)
2023-06-15 02:03:30 +02:00
7d292c009d Update v11 branch 2023-06-14 08:31:14 +02:00
4bf075786c Merge pull request 'v11 report v10.7.19' (#654) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#654
2023-06-14 08:28:49 +02:00
a2a04ade4c Migration des compendiums 2023-06-14 02:12:32 +02:00
2db6895c76 Gestion des difficultés de Possession
- gestion de la difficulté imposée sur la défense
- gestion des particulières en attaque considérées en finesse
- utilisation du rêve actuel pour les personnages
2023-06-14 02:12:28 +02:00
e46f35ef92 Catégories des compétences de créatures
Les créatures peuvent avoir des compétences d'armes (lancer,
mêlée, tir, armes naturelles), de parade, de possession, et générales.

Les initiatives sont cohérentes. Les possessions sont en phase 10
d'initiative.
2023-06-14 02:12:22 +02:00
9e050d3e12 Fix commerce achat MJ sans personnage
Correction sur les achats: l'objet acheté vient forcément soit d'un
personnage-vendeur, soit des Items globaux.

Ne pas essayer d'acheter autrement car on aurait des données d'item
non structurées, et donc ça ne fonctionnerait pas.
2023-06-14 02:12:15 +02:00
81492f2857 Merge pull request 'v11.0.6 - Report v10.7.18' (#652) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#652
2023-06-08 06:51:57 +02:00
959e751e48 Correction rendu changelog en ligne 2023-06-08 01:47:04 +02:00
b6a124b57d v11.0.6 2023-06-08 01:44:17 +02:00
db2ca945a8 Fix: la date des blessures ne marchait plus
la liste des types (pour aider à la saisie) est une idée mitigée

- ça évite les fautes d'orthographe dans les constantes de types
Mais:
- on peut oublier un type
- si le type n'est pas défini, il est undefined
  (donc risques de regressions)

Saisie de tous les types du template.
2023-06-08 01:35:06 +02:00
667d764db1 Cherry pick v10 gixes 2023-06-05 20:19:42 +02:00
4273f5f48f Fix: validation encaissement MJ 2023-06-05 20:18:05 +02:00
6c4a8eb70f Correction de liens
Quelques liens pointaient sur les icones du bazaar de forge-vtt
2023-06-05 20:17:40 +02:00
eb029e8d66 Fix affichage des "objets" dans les commerces
La confusion entre les Item "objets" et le champ formData.objets
rendait les Item "objets" indisponibles (par exemple, les vêtements)
2023-06-05 20:17:19 +02:00
9ee14b3b56 Add .db again? 2023-06-04 22:17:02 +02:00
3203fae111 Add .db again? 2023-06-04 20:53:15 +02:00
755301275b Add .db again? 2023-06-04 20:51:49 +02:00
f6d5dc9d7c Add .db again? 2023-06-04 20:49:55 +02:00
5e9b47af1f Add .db again? 2023-06-04 20:47:47 +02:00
18dfb36a78 v11 release 2023-05-29 13:47:08 +02:00
febccd508f v11 release 2023-05-29 13:40:38 +02:00
b147f8937b v11 release 2023-05-29 13:33:31 +02:00
55a93b317a v10/v11 compat 2023-05-29 08:50:13 +02:00
02a630152d v10/v11 compat 2023-05-29 08:50:08 +02:00
ad8ac0de77 v10/v11 compat 2023-05-29 08:42:16 +02:00
dceb6f026f v10/v11 compat 2023-05-29 08:41:59 +02:00
ad37ee1b8e v10/v11 compat 2023-05-29 08:38:22 +02:00
4d40e2fe59 Merge pull request 'cherry-pick changements v10' (#647) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#647
2023-05-29 07:47:58 +02:00
9d7e57d9fb Changelog v11 2023-05-28 22:11:16 +02:00
717029e572 Tri des listes d'items 2023-05-28 22:11:16 +02:00
d6f8976298 Utilisation de la dateReel du calendrier 2023-05-28 22:11:16 +02:00
92e93cbbea Refonte du journal d'expérience
Reprise du journal d'expérience pour:
- afficher ancienne/nouvelle valeur
- la valeur du changement
- si c'est manuel / automatique
- identifier les dépenses de stress
- identifier les augmentations de compétences
- les changements des compteurs
2023-05-28 22:11:16 +02:00
994eaad9a9 Ajout des acteurs accordés aux entités 2023-05-28 22:11:16 +02:00
cfed7e2afa v10/v11 compat 2023-05-25 21:16:59 +02:00
436f9e6fa4 v10/v11 compat 2023-05-25 21:06:03 +02:00
18a50197cd v10/v11 compat 2023-05-25 21:05:43 +02:00
b6910612f8 v10/v11 compat 2023-05-25 21:04:27 +02:00
4ba1ec8a2e v10/v11 compat 2023-05-25 21:04:02 +02:00
75a0f7c322 v10/v11 compat 2023-05-25 20:40:59 +02:00
e2a9f55740 Initial commit for v11 support 2023-05-25 20:39:53 +02:00
1e0788cde8 Merge pull request 'v11' (#645) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#645
2023-05-25 20:37:01 +02:00
c10195f753 Version 10.7.13 2023-05-25 20:23:54 +02:00
4d7317b964 Gestion de l'armure
Correction de la détérioration d'une armure variable

Séparation du code d'armure dans l'Item RdDArmureItem
2023-05-25 20:20:43 +02:00
7b1fa009bb Utilisation de constantes pour les types
(sans effet)
2023-05-12 22:56:59 +02:00
71bb8a14e1 Fix sieste 2023-04-28 08:35:26 +02:00
5444bc7fd8 Merge pull request 'Changelog et fix mineur' (#643) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#643
2023-04-28 08:33:59 +02:00
debaf1da34 Changelog v10.6 & v10.7
Récupéré des messages postés
2023-04-27 14:20:35 +02:00
69e2ab9000 Fix: sélection de sieste pour le repos
Quand le MJ gère les changements de jours, la fenêtyre de repos ne
proposait pas les options dormir/chateau dormant, mais utilisait
l'option "dormir" par défaut
2023-04-27 14:20:35 +02:00
24218ed062 Changelog 2023-04-22 20:34:30 +02:00
da4e18dc3c Gestion de l'empoignade 2023-04-22 07:55:26 +02:00
154a9b7a37 Gestion de l'empoignade 2023-04-21 23:09:40 +02:00
fb8189606b Merge pull request 'v10: pinaillages mineurs' (#642) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#642
2023-04-21 23:08:10 +02:00
cfbfad27bd cleanup Empoignade 2023-04-21 22:30:21 +02:00
f541849306 Centralisation du message empoignade
Déplacement dans le module empoignade du message et de
la vérification d'empoignade en cours.

Le message est donc centralisé (possible de le modifier une fois pour
toutes les utilisations)
2023-04-21 22:30:21 +02:00
d2d1891838 cleanup itemTypes
Utilisation de itemTypes plutôt que de méthode listItems ou de
filtrer les items par type.

Potentiellement, itemTypes peut être précalculé par Foundry
C'est aussi un peu plus lisibles (conditions du filter moins longues,
et le filtrage par type est mis en avant en premier)
2023-04-21 22:30:21 +02:00
5580b6d59c Debug: à la recherche de l'Item qui ne se vend pas 2023-04-21 21:38:21 +02:00
40c45c30de Equiper des vêtements, bijoux, ...
Permettre d'équiper les objets "de base" en plus des armes et armures
2023-04-21 21:38:21 +02:00
1b6c5256cc Gestion de l'empoignade 2023-04-21 18:18:41 +02:00
c0e6759164 Gestion de l'empoignade 2023-04-21 18:18:20 +02:00
a096590a07 Merge pull request 'Version 10.7.7 - Les bobos de Sémolosse' (#641) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#641
2023-04-15 07:42:39 +02:00
9883048fb5 Version 10.7.7
Les bobos de Sémolosse
2023-04-14 20:57:16 +02:00
7bec42c4cf Fix Mise à jour du texte de l'heure joueurs 2023-04-14 20:31:47 +02:00
6708dc0da9 Fix rituels Lecture/Détection aura Hypnos 2023-04-14 20:31:15 +02:00
96c2da0d05 Fix: thème astral par un joueur
La recherche des chjiffres astrologiques par les joueurs ne marchait
plus
2023-04-14 01:19:44 +02:00
2b19250e8b Log: debug cas d'échec achatVente 2023-04-07 01:14:50 +02:00
957eabcac7 Fix: sélection sous l'horloge 2023-04-07 01:14:50 +02:00
285937c201 Merge pull request 'Version 10.7.6 - L'origine des maux de Sémolosse' (#640) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#640
2023-03-31 07:22:28 +02:00
93965ce91a Version 10.7.6 2023-03-31 01:42:25 +02:00
18aba9adff Pas de bordure pour les boutons avance rapide 2023-03-31 01:32:52 +02:00
0a5662ff71 Couleurs jour nuit plus visibles 2023-03-31 01:32:24 +02:00
bf98e4eae2 Fix toggle horloge
Affiche/masque correctement l'horloge pour le MJ et les joueurs
2023-03-31 01:31:09 +02:00
e32a1d25f6 Ne pas fermer l'horloge sur escape
Surcharge de la méthode close pour empêcher la fermeture
2023-03-31 00:51:05 +02:00
327943c4aa Fix mise à jour sur action des herbes/potions
Par exemple, la mise à jour de quantité d'herbe ne se faisait pas
dans les liste d'équipement des feuilles de conteneurs, lors d'une
fabrication de potion dans les items
2023-03-31 00:47:25 +02:00
de56fa909a Ajout bouton Item diminuer quantité
Pour diminuer la quantité des objets multiples sans avoir à éditer
2023-03-30 02:56:06 +02:00
2aa62cffe9 Bonus de sorts en fleuve
Le bonus de sort en fleuve est identique pour toutes les cases fleuve.
2023-03-30 01:31:41 +02:00
c57f140c54 Ajout de l'origine d'une blessure
En combat, indication de l'origine des blessures
2023-03-30 00:19:18 +02:00
9cf14f8b75 Merge pull request 'Version 10.7.5 - La montre-gousset de Sémolosse' (#639) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#639
2023-03-29 23:06:31 +02:00
b8e7b21e14 Version 10.7.5
La montre-gousset de Sémolosse
2023-03-29 23:00:23 +02:00
c1d02d9fda Ajout d'une horloge analogique
Amélioration de la fenêtre calendrier:
* plus compacte
* horloge analogique
* normalement compatible pop-out
* minimisable (juste la barre de titre)
2023-03-29 23:00:23 +02:00
23af30a538 Merge pull request 'Version 10.7.4 - Les ligatures de Sémolosse' (#638) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#638
2023-03-24 23:16:49 +01:00
4e1b663dec Version 10.7.4
Les ligatures de Sémolosse
2023-03-24 21:37:32 +01:00
c9d98c57da Cleanup: templates non internes 2023-03-24 21:26:42 +01:00
0aef139cf8 Fix: boutons pour réserve en sécurité 2023-03-24 21:26:42 +01:00
9c85293714 Fix: bouton pour jet de vie sur critique 2023-03-24 21:26:42 +01:00
ab1c04ae17 Fix: La chirurgie dans les tâches
Re-déplacement des tâches de chirurgie, maintenant que les soins de
blessures sont facilités (par les tokens)
2023-03-24 21:26:42 +01:00
a585e0faba Fix: affichage bonus de cases
Les bonus de cases sont visibles pour les sorts attachés à un personnage
2023-03-24 21:26:42 +01:00
50c730ba72 Fix: queues non refoulables 2023-03-24 21:26:42 +01:00
928a60f092 Add flags 2023-03-23 17:03:40 +01:00
e5c2f52b0e Merge pull request 'Version 10.7.3 - Les tisanes de Sémolosse' (#637) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#637
2023-03-23 17:02:56 +01:00
f9391523f8 Version 10.7.3
Les tisanes de Sémolosse
2023-03-23 01:44:35 +01:00
55434762f4 Masquer bonus premiers soins si soins complets 2023-03-23 01:43:41 +01:00
5e6ffc7846 Fix: bonus d'herbe de potion non enchantée 2023-03-23 01:42:48 +01:00
3344e20936 Fix: consommation potion enchantée 2023-03-23 01:41:37 +01:00
5a66e4e741 Fix horloge aiguille des heures
L'aiguille des heures pointe sur l'heure au début de l'heure
draconique, comme pour une montre.

Début couronne, l'aiguille des heures et des minutes sont donc
toutes les deux en haut.
2023-03-21 22:00:24 +01:00
d329724d63 Merge pull request '10.7.2 - les maux de dents de Semolosse' (#636) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#636
2023-03-20 23:32:08 +01:00
8a5405c9f5 Version 10.7.2
les maux de dents de Semolosse
2023-03-20 23:29:46 +01:00
ea992aae46 Fix: récupération des blessures 2023-03-20 23:28:25 +01:00
0bfcfec58f Fix jet carac 2023-03-16 23:17:52 +01:00
88e00c59bc Fix actor 2023-03-16 23:12:08 +01:00
d314dc39a0 Fix actor 2023-03-16 23:10:17 +01:00
30bb803da2 Merge pull request 'v10.7.0 - l'os de Sémolosse' (#635) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#635
2023-03-16 23:09:10 +01:00
dd79e16ea5 Version 10.7.0 2023-03-15 01:29:55 +01:00
83e2d56fd4 Boutons soins&blessures 2023-03-15 01:29:48 +01:00
afc23dfa7b Fix: message sans jet d'endurance 2023-03-15 01:29:48 +01:00
3e189cbe5f Ajout des blessures sur encaissement 2023-03-15 01:29:48 +01:00
d0475e8677 Suppression anciennes blessures 2023-03-15 00:41:48 +01:00
a3694c1673 Cleanup 2023-03-15 00:41:47 +01:00
9e6d5856b1 Gestion des soins avancés
- raccourci soins HUD
- edition rapide des Item blessure
- gestion des taches de soins liées aux blessures
2023-03-15 00:41:47 +01:00
acc880b53f Preparation soins HUD 2023-03-15 00:41:47 +01:00
2598ae3489 Ajout item Blessure 2023-03-15 00:35:22 +01:00
4f5fb63751 Tri alphabétique des constantes 2023-03-15 00:35:21 +01:00
d739a7993a rollCaracCompetence avec dialog 2023-03-15 00:35:21 +01:00
41335cd433 Renommage méthode jet sans dialog 2023-03-15 00:35:21 +01:00
e470d76ea0 Méthode de fenêtre de jet partagée 2023-03-15 00:35:21 +01:00
ffccc819f1 Fix: merge d'options sur token 2023-03-15 00:35:21 +01:00
45bfc69b39 Ajout d'option pour informer si pas de cible
Pour le HUD, on peut vouloir utiliser la cible (soins)
2023-03-15 00:23:21 +01:00
79e9358072 Préparation Calendrier avant migration
Les migrations peuvent avoir besoin du temps courant.
Le calendrier est recréé après.
2023-03-15 00:23:21 +01:00
5cab418e62 Merge pull request 'v10.6.25 - fix erreur synchro astrologie/heure' (#634) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#634
2023-03-14 22:41:45 +01:00
7809f7c21a Version 10.6.25 2023-03-14 22:14:04 +01:00
1bac204071 Fix astrologie 2023-03-14 21:56:59 +01:00
3bf5beb67b Sync merge manuel 2023-03-09 23:49:37 +01:00
ac1da6e979 Update archetype/theme 2023-03-09 23:25:34 +01:00
67735197bc Merge pull request 'Version 10.6.21 - La théière de Pralinor' (#632) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#632
2023-03-08 23:17:45 +01:00
f81dc9a5f5 Version 10.6.21
La théière de Pralinor
2023-03-08 23:08:40 +01:00
a563233d6b Fix: les PNJs peuvent de nouveau dormir 2023-03-08 23:08:40 +01:00
0c11013694 Ajout Aiguille Horloge 2023-03-08 22:48:40 +01:00
77cf72a752 Intégration astrologie
Intégration du thème astral dans les fenêtres d'astrologie
2023-03-08 22:34:05 +01:00
42ed5da2d4 Création de tableaux d'entiers
ajout d'une méthode propre pour construire un tableau d'entiers
consécutifs
2023-03-08 02:00:38 +01:00
5fd3a43b2a Merge pull request 'Version 10.6.20 - Les Oracles de Pralinor: vous mangerez à Couronne' (#631) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#631
2023-03-07 13:32:21 +01:00
1bb710ce83 Version 10.6.20
Les Oracles de Pralinor: vous mangerez à Couronne
2023-03-07 11:13:56 +01:00
80579032ea Ajout de la fenêtre de thème astral
Accessible par macro/depuis les fenêtres d'astrologie
2023-03-07 10:46:31 +01:00
a810e20eca Merge pull request 'Version 10.6.19 - La cerise de Pralinor' (#630) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#630
2023-02-24 09:56:29 +01:00
c6f0aaeba0 Version 10.6.19 - La cerise de Pralinor 2023-02-24 00:50:06 +01:00
3c3be7409d Fix: problème de nombre d'utilisations 2023-02-24 00:38:14 +01:00
f97345e407 Fix: recherche avec droits limités 2023-02-24 00:33:49 +01:00
4cc50fc190 Ajout Haubert d'Oniros 2023-02-18 12:26:58 +01:00
26967fe1cd Merge pull request '10.6.18 - Les insomnies de Pralinor' (#629) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#629
2023-02-17 10:16:29 +01:00
b23dcaace5 Version 10.6.18
Les insomnies de Pralinor
2023-02-17 01:31:18 +01:00
045ee76013 Fix: transfert du moral à chateau dormant 2023-02-17 01:29:21 +01:00
7fed3844b5 Fix: calcul du nombre d'heures dormi
Le calcul était incorrect (5 au lieu de 4), du coup Chateau Dormant
ne se déclenchait pas.
2023-02-17 01:28:30 +01:00
b5571e6c7a Merge pull request 'v10.6.17 - Les désordres de Pralinor' (#628) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#628
2023-02-14 08:13:44 +01:00
b5eac8ccfa Version 10.6.17
Les désordres de Pralinor
2023-02-13 22:49:21 +01:00
673196c644 Fix: trier le contenu 2023-02-11 21:20:12 +01:00
9741028914 Fix: suppression doublons 2023-02-11 20:52:29 +01:00
10daab2bcd Merge pull request 'v10.6.16' (#627) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#627
2023-02-11 17:05:42 +01:00
99d2d38279 Version 10.6.16 2023-02-11 01:24:58 +01:00
e30825db6b Commerce "Liste d'équipement" 2023-02-11 01:24:58 +01:00
10ed4d9382 Corrections d'équipements
Séparation de:
- flèches et carreaux (qui deviennent des munitions)
- Luth et viole
- Burin, gouge, ciseau
- Lime, Râpe
- Alène, poinçon

Ajout de l'herbe à pipe
Ajout de prix à l'herbe de lune (qualité 3 par défaut)

Sang et Liquide deviennent de bêtes objets
2023-02-11 01:24:58 +01:00
2ffa0d8dc7 Fix: utiliser les compétences des humanoïdes
Utiliser les compétences de l'acteur empêchait l'édition des armes
(et objets liés à une compétence) stockées sur un animal, dans un
véhicule, ou dans un commerce
2023-02-11 01:24:58 +01:00
f229537206 Merge pull request 'v10.6.15' (#626) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#626
2023-02-10 21:37:33 +01:00
5c31c7bd7f Version 10.6.15 2023-02-10 21:30:30 +01:00
4cf428f630 Fix: messages et insomnie
Amélioration des messages de sommeil (nombre d'heure, seulement les
récupérations de rêve effectives, ...)

Les insomnies ne durent bien que 12h draconique à partir du prochain
chateau dormant (elles pouvaient durer 3 jours par erreur).
2023-02-10 02:01:55 +01:00
0c1b70f3f0 Fix: recherche dans arbre de conteneurs
On affiche bien tous les conteneurs intermédiaires
2023-02-10 02:01:55 +01:00
b7ea857bb4 Merge pull request '10.6.14' (#625) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#625
2023-02-09 07:22:14 +01:00
0238976ce8 Version 10.6.14 2023-02-08 21:17:20 +01:00
31fd91336a Correction affichage calendrier
Correction de l'affichage incorrect pour Chateau Dormant et
Poisson Acrobate

Nettoyage du css
2023-02-08 21:09:07 +01:00
c70b6c9d5f Dialog chateau-dormant
Pour permettre de pré-remplir les infos de chateau dormant
2023-02-08 21:09:07 +01:00
07d0d92f57 Suppression code commentaire 2023-02-08 00:24:05 +01:00
a2968697f4 Jet de moral neutre sans effet si moral à 0 2023-02-07 21:37:43 +01:00
fb7dbe6ea0 Merge pull request 'v10.6.13' (#624) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#624
2023-02-07 19:28:34 +01:00
59641bf5cf Version 10.6.13
Recherche dans les commerces
2023-02-07 18:08:13 +01:00
4ee4445836 Fix: message sur jet de moral neutre 2023-02-07 18:07:26 +01:00
1a346a21c3 Recherche dans les commerces 2023-02-07 18:07:26 +01:00
c6c0dd43fd Merge pull request 'Recherche dans l'inventaire' (#623) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#623
2023-02-05 23:00:20 +01:00
d69a07d4dd Version 10.6.12 2023-02-05 20:32:47 +01:00
56379a9234 Fix: bouton d'ajout d'objet 2023-02-05 20:30:19 +01:00
fbcc167272 Recherche dans l'inventaire
Par nom ou par type, et dans les contenants
2023-02-05 20:26:51 +01:00
703ab2579d Merge P3 2023-02-03 08:35:02 +01:00
6b7e881bf2 Merge pull request 'v10.6.11' (#621) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#621
2023-02-03 08:34:06 +01:00
dc3ceb1732 Déplacements des effets de rencontre
classe placée dans le dossier "tmr"
2023-02-03 02:23:46 +01:00
7a0132cf8d La griffe morbide donne un poison
Ajouter l'effet "poison: griffe morbide de thanatos" à la victime pour
agir "comme" un poison (sauf qu'un jet de vie jamais positif remplace
l'habituel jet de constitution).
2023-02-03 02:23:46 +01:00
ca1ea5a854 La récupération est bloquée par les maladies
Pas de récupération de vie ou de blessures possibles sous l'effet d'un
poison ou d'une maladie
2023-02-03 02:23:46 +01:00
9bdde92d61 Minot fixes 2023-02-02 08:56:00 +01:00
74313b7fd3 Merge pull request 'fixes' (#620) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#620
2023-02-02 08:55:24 +01:00
9a9399a581 Alchimie: températures et difficulté
- toujours afficher les difficultés des températures/consistances
- renommer "couleur" en "température" à l'affichage
- mise à jour des recettes du compendium
2023-02-02 01:24:42 +01:00
95a7ac73d0 Fix: description en mode edition 2023-02-02 01:21:06 +01:00
ab4c118d12 Fix: Sustentation consommée parfois concaténée 2023-02-02 00:53:32 +01:00
681358238d Merge branch 2023-02-01 10:11:33 +01:00
5511acc876 Merge pull request 'Alignement description en haut' (#619) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#619
2023-02-01 10:10:42 +01:00
2e144851d4 Alignement description en haut 2023-01-31 21:40:35 +01:00
9f24aee1f3 Merge pull request 'Recherche par nom' (#618) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#618
2023-01-31 07:32:09 +01:00
e605ab405a Version 10.6.8 2023-01-30 22:08:11 +01:00
86f69566a6 Recherche par nom
Dans la fenêtre de recherche, possibilité de chercher sur le nom
des objets en plus des autres critères
2023-01-30 22:08:11 +01:00
2561a658f2 Merge pull request 'v10.6.7' (#617) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#617
2023-01-28 20:50:52 +01:00
8a1d1fd253 Version 10.6.7 2023-01-28 18:08:47 +01:00
e42f384d7f Masquer le bouton si pas utilisable
Pour créer un nouvel objet, il faut être "owner"
2023-01-28 16:46:17 +01:00
d381191692 Monnaie pour gérer la fortune 2023-01-28 16:35:45 +01:00
53a7230f1d Fix: Actions dans un conteneur
Les actions dans un conteneur (ouvrir un des sous conteneurs par
exemple) n'étaient pas disponibles.
Ceci était lié à la structure des données contenant les droits
différente pour les items et les acteurs.

La gestion des droits était mélangées et faite de façons différentes.
Maintenant, les "options" dans les données du formulaire contiennent
les informations de droits d'accès et sont utilisées.
2023-01-28 16:34:09 +01:00
4d5651c2d3 Reprise de l'arbre d'inventaire
Soucis lors de l'affichage dans la fenêtre d'un conteneur
2023-01-28 15:43:31 +01:00
61474172a7 Fix: gestion de la fenêtre de vente
les nombre de lots ne marchaient plus (toujourts 1 de proposé)
2023-01-28 11:36:22 +01:00
083806612b Merge pull request 'v10.6.7' (#616) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#616
2023-01-25 10:26:26 +01:00
1c417d02a1 Version 10.6.6 2023-01-24 22:35:39 +01:00
ee9e7d2adb Messages compétences troncs en notifications
Lors d'une création de perso, ça spamme trop le tchat
2023-01-24 22:33:45 +01:00
fa3334273d Fix: ligne de carac vide à cause de la beauté
Une lighne de carac était ajouée lors de l'édition de la beauté.
2023-01-24 22:33:45 +01:00
05b73a41a5 Inversion: Taille puis poids
C'est dans cet ordre dans les scénarios
2023-01-24 22:33:45 +01:00
842243485a Corrections d'armes rudimentaires 2023-01-24 22:12:43 +01:00
1e53f2d9e8 Minot fix 2023-01-24 18:13:27 +01:00
792fcc1b39 Merge pull request 'v10' (#615) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#615
2023-01-24 15:22:36 +01:00
3d914a29c3 Fix: édition de carac créature 2023-01-24 01:43:10 +01:00
7fe7c1e9bd Fix: +dom pas affiché 2023-01-21 19:54:04 +01:00
d86b81fbbc Merge pull request 'v10.6.4' (#614) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#614
2023-01-21 16:57:37 +01:00
22da2807d8 Fix2: update de stress transformé 2023-01-21 00:17:36 +01:00
76e03b07ed v10.6.4 2023-01-20 23:53:03 +01:00
e4098c813b Les remèdes sont bien catégorisés 2023-01-20 23:53:03 +01:00
90aecd6cc0 Suppression compendium taches de soins
Avantageusement remplacé par les boutons de soins
2023-01-20 23:53:03 +01:00
254709f55b Recherche de potion par catégorie 2023-01-20 23:53:02 +01:00
064472dc11 Ajout de l'utilisation 'cuisine' 2023-01-20 23:52:37 +01:00
7a67cb7cea Prise en compte des milieux
Les filtrages par milieux prennent en compte la rareté/fréquence
du milieu
2023-01-20 23:52:09 +01:00
7f051e76be Tri par ordre alphabétique (tous compendiums)
Le tri étati fait séparément pas compendium, du coup, la présentation
des résultats n'était pas toujours pratique
2023-01-20 23:52:09 +01:00
38db7fb7c8 Cas où le stress peut être concaténé
Vu deux fois:
- passage de "29" à "290" en ajoutant 0
- valeur "00"
2023-01-20 23:52:08 +01:00
c448f32bb8 Merge pull request 'v10.6.3' (#613) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#613
2023-01-19 10:50:27 +01:00
e194514965 Taille de titre soins 2023-01-19 02:46:54 +01:00
a790c36618 Soins des blessures
Maintenant, les tâches peuvent être créées directement
dans l'onglet combat, à côté des blessures.

Les tâches des oins sont dans cet onglet
2023-01-19 02:42:25 +01:00
f221bb31eb Version 10.6.3 2023-01-19 01:50:02 +01:00
bdc2d8db3a Fix blocage du round
Les ActiveEffect n'ont pas de system, et causaint une exception
dans la méthode de passage de fin de round
2023-01-19 01:48:41 +01:00
782dc38268 Ajout de message si rencontre perdue
Ajout d'un message pour comprendre comment une rencontre peut
être perdue ( Issue #612)
2023-01-19 01:48:41 +01:00
024e355586 Fix: Affichage d'anciens objets temporels
Les objets temporels créés avant la 10.5.0 ne pouvaient pas être édités
2023-01-19 01:48:41 +01:00
37704558e0 Combat bloqué en cas d'init négative
Le code essayait de modifier le total d'un roll, qui n'est pas un
champ mais une methode get de la classe Roll
2023-01-19 01:48:41 +01:00
d816490839 Expérience sur jets de résistance
Une réussite particulière à un JR de difficulté négative fait
gagner un point d’expérience. On ne gagne qu’un seul point
quelle que soit la difficulté du JR, et cet unique point va
toujours en caractéristique RÊVE, jamais en Draconic.

Pour l'éthylisme, le jet de vie n'est pas un jet d'action, mais de
résistance, limitation à 1 point d'expérience pour lutter contre
l'alcoolisme optimisateur.
2023-01-19 01:48:41 +01:00
a4186da540 Merge pull request '10.6.2' (#611) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#611
2023-01-18 08:40:40 +01:00
b8b4a1ff14 Version 10.6.2 2023-01-18 02:01:53 +01:00
8925a4979d Ajout de fréquence aux équipements 2023-01-18 02:01:27 +01:00
851a208aee Généralisation des fréquences
Tout objet d'inventaire a une fréquence (en ville/village, ou autre
milieu)
2023-01-18 02:01:27 +01:00
4df04fe06f Configuration de la recherche 2023-01-18 00:12:34 +01:00
f4d074fa31 Paramétrage des compendiums de recherche 2023-01-17 21:51:49 +01:00
f7595a1bfe Taille Quantité dans commerces
Agrandissement pour mieux afficher jusqu'à 4 chiffres au cas
en cas d'objets en grande quantité, avec d'autres limités
2023-01-16 23:20:29 +01:00
86feb12811 Fix: /table milieu
régression causée par les changements de la fenêtre de recherche
2023-01-16 23:17:17 +01:00
2383094254 Increase relese 2023-01-15 23:37:06 +01:00
2a72f6ffea Merge pull request 'v10.6.1' (#610) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#610
2023-01-15 23:36:12 +01:00
3cc56c615c Amélioration "effacer les filtres" 2023-01-15 23:30:32 +01:00
948309bb4f Drag depuis la fenêtre de recherche 2023-01-15 23:21:19 +01:00
40fdff4057 Image du token pour les Commerces non liés 2023-01-15 21:40:18 +01:00
c972913a67 Amélioration des plantes comestibles&poisons 2023-01-15 15:55:35 +01:00
0d5c8e5304 Amélioration de recherches 2023-01-15 15:54:40 +01:00
0aba6d2f0a Fix: Typo monnaie "Dragon" 2023-01-15 12:42:53 +01:00
df3e181d7f Merge pull request 'Les classifications de Pralinor' (#609) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#609
2023-01-14 08:54:27 +01:00
8877939b9f Version 10.6.0 2023-01-14 01:56:47 +01:00
7334f2d8e6 Liens des plantes toxiques vers leur poisons 2023-01-14 01:56:47 +01:00
ceff3d1b50 Le retour du poisson acrobate 2023-01-14 01:56:47 +01:00
a4802d1113 Séparation ingrédients/plantes 2023-01-14 01:18:17 +01:00
162a6a04b8 Fenetre de recherche et tirage 2023-01-14 01:18:17 +01:00
0c36cf3c47 Fix ouverture de conteneurs 2023-01-13 01:53:25 +01:00
969e5f6b2d Rename: isAgiliteOuDerobee
Plutôt que isAgiliteOuDerivee qui pourrait inclure la Mêlée
2023-01-13 01:53:25 +01:00
306ecacc98 Les commerces ne gèrent pas d'encombrement 2023-01-13 01:53:25 +01:00
2dc86e6679 Fix: jet de volonté éthylisme
Dans certains cas, les jets d'éthylisme concaténaient
moral et éthylisme
2023-01-13 01:53:25 +01:00
484530d67d Fix: chronologie si le journal est supprimé 2023-01-13 01:53:25 +01:00
a08890dcb0 min-width calendrier pour titres courts
Pour certaines dates, les boutons lyre / vaisseau s'affichaient
sur 2 lignes
2023-01-12 20:53:35 +01:00
1956fdd755 Merge pull request 'Version 10.5.4 - le pense-bête d'Astrobazzarh' (#608) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#608
2023-01-10 23:11:49 +01:00
651356159a Version 10.5.4 - le pense-bête d'Astrobazzarh 2023-01-10 23:06:18 +01:00
ca304109d5 Cleanup 2023-01-10 23:06:18 +01:00
9c0d08cb6f Organiser la chronologie par date 2023-01-10 23:06:18 +01:00
f9fd8a1e24 Message si le journal est inaccessible 2023-01-10 23:06:18 +01:00
03f84eb3f7 Chronologie +/-
Quand le journal est sélectionné, la fenêtre de chronologie s'ouvre avec
les informations présaisies masquées.

Le bouton + permet de les afficher. Le bouton - de les masquer.
2023-01-10 23:06:18 +01:00
05e48b61ff Renommage showControlWhen
Vu que la méthode est publique
2023-01-10 22:17:30 +01:00
f20788d6d9 Merge pull request 'v10.5.3' (#607) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#607
2023-01-10 07:49:17 +01:00
009639dd5f Version 10.5.3 2023-01-09 23:23:29 +01:00
14542cf7cd Suppression template inutile
N'est plus utilisé, maintenant que les services sont des objets
dans les boutiques
2023-01-09 23:22:20 +01:00
f4f2db68e0 Table d'astrologie avec toutes les heures 2023-01-09 23:22:20 +01:00
7e75715d88 Merge pull request 'v10.5.2' (#606) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#606
2023-01-08 23:59:34 +01:00
d62d1c45bc Version 10.5.2 2023-01-08 23:36:53 +01:00
62914c343f Fix: à l'heure de => heure 2023-01-08 23:27:08 +01:00
9349e81580 Reformatage du calendrier 2023-01-08 23:21:14 +01:00
404539a004 Fix: ajout d'heure ajoute des minutes
Lors du passage à Lyre, on ajoutait 6 minutes
2023-01-08 23:20:54 +01:00
9eaeceafc4 Autofocus sur le texte pour la chronologie 2023-01-08 20:42:28 +01:00
1cd3bdef25 Amélioration titre du calendrier 2023-01-08 20:42:28 +01:00
fa356bd7f8 Fix calcul des heures de chance 2023-01-08 20:42:28 +01:00
771c8c9c8e Merge pull request 'Fix: migration automatique de calendrier quand l'heure est à Vaisseau+0 minutes' (#605) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#605
2023-01-08 18:44:42 +01:00
ca860a0243 Version 10.5.1 2023-01-08 16:37:38 +01:00
2e36221018 Fix de la migration quand l'heure est à 0 2023-01-08 16:36:54 +01:00
07e203513a Merge pull request '10.5.0' (#604) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#604
2023-01-08 09:49:45 +01:00
31960ce940 La périodicité est migrée 2023-01-08 01:03:03 +01:00
19118911b9 Version 10.5.0 2023-01-08 00:58:44 +01:00
652ae4cf51 Fix: enlever le bloc noir en pause 2023-01-08 00:57:50 +01:00
cf340f73f1 Migration maladies et poisons
Séparation de l'incubation / la périodicité
2023-01-08 00:57:05 +01:00
3782ed9055 Gestion d'update de timestamp 2023-01-07 23:58:33 +01:00
c3076fdbfc Gestion de la périodicité/temporalité 2023-01-07 23:28:30 +01:00
739fcbdf09 Calendrier/timestamp, suite
Correction autour des éditeurs/affichages
Migration de la date du monde dans les settings
2023-01-07 20:06:21 +01:00
19b3adc222 Cleanup logs 2023-01-07 20:06:21 +01:00
388629d36e Fix: édition des compétences de créatures 2023-01-07 20:06:21 +01:00
912b1d3df3 Gestion d'items temporels
- Séparation des timestamp / calendrier

Les poisons/maladies/souffles/queues/rencontres/signes peuvent
être temporaires.

- Ajout de champs pour stocker les timestamps de début et fin
- définition de la durée (selon les items)
- extraction des classes spécialisées des items
- initialisation des dates de début/fin des effets temporaires à
  l'ajout d'un item temporel
- préparation de la suppression automatique
- Fix de mauvaise présentations sur les dialog d'astrologie
  et d'édition du calendrier
2023-01-07 02:22:44 +01:00
11e4ad09d3 Ignore jsconfig.json and modules 2023-01-05 22:23:47 +01:00
8844f76b65 Les joueurs ne peuvent plus créer de signes
Les commandes /signe+ / /signe
2023-01-05 20:56:42 +01:00
ec24126e75 Cleanup: Suppression listes inutiles 2023-01-05 20:31:29 +01:00
b3c6845e68 Fix: la maladie bloque le calendrier
Le postItem d'une maladie bloquait le raffraîchissement du calendrier
2023-01-05 20:31:29 +01:00
cf8df182ba Merge pull request 'v10.4.9' (#603) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#603
2023-01-05 16:11:17 +01:00
30cc8419c5 Version 10.4.9 2023-01-05 14:44:38 +01:00
5ab6c5989e Fix: name unique pour tabulations 2023-01-05 14:36:01 +01:00
46df3d9f11 Fix: regression sur les ventes 2023-01-05 14:32:35 +01:00
6a6759087c Merge commerces fixes 2023-01-04 21:17:50 +01:00
a7ce1db7c5 Merge pull request 'Corrections mineurs commerces et ventes' (#602) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#602
2023-01-04 21:17:10 +01:00
a0efefad3f Suppression template inutile
Les herbes de soins sont mieux gérées
2023-01-04 00:25:23 +01:00
8e0825b6b9 Fix: vente depuis un commerce
La quantité proposée est limitée à la quantité disponible
ou illimité si le commerce est illimité
2023-01-03 23:46:08 +01:00
39d14c8496 Fix: boutons des commerces
- pas de vente des "étagères"

Les contenants groupes dans les commerces ne sont plus
montrables/vendables. Le MJ peut les éditer (pour changer le nom
et l'image, principalement), et c'est tout.

- le MJ peut acheter un objet de quantité 0 dans une boutique illimitée

le bouton n'était pas affiché...
2023-01-03 23:02:07 +01:00
89442ea6c6 Merge permissions fix 2023-01-03 16:12:23 +01:00
a66fe122c4 Merge pull request 'Le GR a toujours le droit de voir les acteurs' (#601) from VincentVk/foundryvtt-reve-de-dragon:v10 into v10
Reviewed-on: public/foundryvtt-reve-de-dragon#601
2023-01-03 16:11:34 +01:00
2e0abaa284 Les services sont inquantifiables
Ne pas décrémenter leur quantité, et leur quantite disponible est
undefined (ie: infinie)
2023-01-03 13:38:04 +01:00
5bddc548de Le GR a toujours le droit de voir
Change-Id: I3b58fddc3ce6765e6dcf59dc20d81cdadf381761
2023-01-03 13:26:44 +01:00
431 changed files with 13719 additions and 8057 deletions

9
.gitignore vendored
View File

@ -1,5 +1,14 @@
.vscode/settings.json
.idea
.history
todo.md
/.vscode
/ignored/
/node_modules/
/jsconfig.json
/package.json
/package-lock.json
/packs/*/
/packs/*/CURRENT
/packs/*/LOG
/packs/*/LOCK

View File

@ -1,10 +1,242 @@
==================================================================
v0.9.2 - 05/09/2020
# 11.2
## 11.2.11 - Le miroir d'Akarlikarlikar
- Changement des images de compétence de créatures morsure/pinces pour être dans le thème
- Suppression de la bordure autour des portraits d'acteurs, remplacés par un légèr éclaircissement du fond
- Fix: le refoulement ajoute correctement un souffle et revient à 0 en cas d'échec
Erreur de calcul sur points de vie
Gestion différente des compétences "troncs"
## 11.2.10 - Les expériences d'Akarlikarlikar
- En cas d'expérience des caractéristiques dérivées,
- si plusieurs caractéristiques pourraient recevoir l'expérience, une fenêtre demande au joueur
- si une seule caractéristique peut recevoir de l'expérience, c'est attribué automatiquement
- Si la force est au maximum pour la taille personnage, on ne peut plus gagner d'expérience
==================================================================
v0.9.1 - 03/09/2020
## 11.2.9 - La barbe d'Akarlikarlikar
- Amélioration des textes de tooltips
- Les tooltips sont plus dans le thème de couleur du système Rêve de Dragon
- Ajouts d'icones pour les attaque/initiative/soins dans les raccourcis sur les tokens (HUD)
- Ajout d'une icône et transformation en bouton du lien pour accéder à l'astrologie et aux chiffres astraux
- Suppression de message de log inutile sur chaque point de coeur
- On peut désactiver l'ajustement astrologique sur les jets de chance (pour des jts de chances non liés à une heure)- Fix: suppression de quelques cas d'erreur lors de l'ouverture des TMR
- Fix: suppression du warning de depréciation effects flags.core.statusId
- Les sorts en réserve en fleuve sont indiqués sur toutes les cases fleuve
- Changement de l'icône d'état d'empoignade pour suivre les couleurs des autres icônes d'état
## 11.2.8 - L'éclairage d'Akarlikarlikar
- l'ajustement de la lumière jour/nuit s'étale sur moins de temps (vaisseau et Lyre)
- les nouveaux tooltips ne masquent plus l'information d'expérience
- les jets de dés pour maîtriser les rencontres fonctionnent de nouveau
## 11.2.7 - Les explications d'Akarlikarlikar
- Ajout de tooltips sur la plupart des boutons, liens clickables, objets, tâches, ...
- Fix: on peut de nouveau regarder l'inventaire avec les droits limités/observateur
## 11.2.6 - Les réveils difficiles d'Akarlikarlikar
- Les changements de points de Cœur sont temporaires jusqu'à fin Château Dormant
- Fix: tous les petits fixes (feuille qui s'ouvre plus, compagnons animaux, potions qui bloquent Château Dormant, ...)
## 11.2.2 - Les tendres moments d'Akarlikarlikar
- On peut maintenant avoir des points de Cœur pour des suivants/compagnons
- diminuer les points de coeurs fait perdre du moral
- on peut proposer un tendre moment
- les jets de volonté peuvent être ajustés selon les points de Cœur
- Fixes
- La résistance est de 1 par défaut pour les équipements
- Les armes de créatures sont de nouveau utilisables depuis les tokens
- Pas de notifications de signe draconique quand on regarde les TMR sans monter
- Correction d'un problème de contextes WebGL causé par des ouvertures/fermetures de TMRs
- On peut maintenant prendre un objet d'un acteur-token pour l'ajouter à un autre acteur
- On ne peut plus donner d'objets d'un acteur à un acteur-token
- L'état général est correctement calculé, affiché, et utilisé pour les animaux
- On peut ajouter des blessures manuellement aux animaux
- Le texte de la carte de Tarot "Le Gibet" est corrigé
- Sur Firefox, le calendrier est correctement initialisé, les ajustements astrologiques
ne bloquent plus les jets de dés
## v11.2.1 - La technique d'Akarlikarlikar
- On peut créer des armes pour Corps à corps et Esquive. Barreaux de chaise, armes improvisées, techniques d'art martiaux, pas de côté pour faire trébucher l'adversaire... A vous de voir comment imaginer de nouvelles "armes".
- Les armes avec une résistance de 0 ne peuvent pas être utilisées, une image et un rappel indiquent qu'elles sont cassées
Vu qu'elles ne peuvent pas être utilisées, permet de savoir pourquoi
## v11.2.0 - Les Terres médianes d'Akarlikarlikar
- Les TMRs sont redimensionables
- Nouveaux graphismes plus lisibles dans les TMRs
- Nouveau code couleur des icônes dans les TMR:
- noir: case innaccessible
- rouge: empêche l'usage du haut-rêve
- vert: bonus de tête de dragon permanent
- bleu: la case doit être vaincue
- blanc: effet temporaire (sort en réserve, présent des cités)
- Fix: les déplacements aléatoires prennent bien compte des colonnes paires/impaires
- Fix: Le Tricollet prend deux "L"
- Fix: Les jets d'encaissement forcés par le gardien à un résultat inférieur à 11 ne peuvent plus donner un deuxième d10 négatif
# v11.1
## v11.1.6 - Les dissections de Werther de Zloth
- Fix: on peut de nouveau donner des compétences aux créatures
- Fix: le délai de guérison d'une blessure rétrogradée est correctement appliqué
- Fix: l'encaissement à valider par le MJ fonctionne de nouveau
## v11.1.5 - Werther de Zloth l'Onirique
- Fixes:
- la demande de défense ne marchait plus
- la tête réserve extensible crée bien une case de réserve extensible (à modifier)
- le souffle trou noir ajoute bien une case de trou noir
- la queue urgence draconique ne se transforme plus en idée fixe s'il y a des sorts en réserve
- l'ajout d'une nouvelle queue ne supprime plus l'insomnie
- Amélioration des jets de vie
- un 1 sur le jet de vie est une réussite même si le personnage est dans le coma
- le temps avant le prochain jet est calculé et affiché
- un 20 sur le jet de vie signifie la mort immédiate
- si on dépasse le S.Const, le personnage est bien indiqué comme mort
- pas de jets de vie pour les morts
## v11.1.4 - Werther de Zloth l'Onirique
- Ajout du facteur de significative à côté du pourcentage dans le résultat des jets de dés pour rappeler que le pourcentage n'est pas diviasé
- Fix: dans les TMRs, les tooltips affichent bien les informations de tous les effets sur la case
- Fix: la fatigue et l'éthylisme sont de nouveau pris en compte dans le calcul de l'éthylisme
- Fix: Le MJ peut correctement masquer les points de tâche requis
- Fix: le jet d'appréciation n'utilise pas la compétence
- Fix: la qualité négative n'est pas exotique, elle est juste mauvaise: on n'utilise pas la cuisine pour se retenir de jeter l'assiette
- Esthétique: ne pas afficher "+0" pour les ajustements de jets/encaissement
## v11.1.2 - Les vertèbres de Werther de Zloth
- Fix: les jets d'encaissement fonctionnent de nouveau normalement
- Macro "Mon personnage" permettant au joueur d'accéder à sa feuille de personnage depuis la barre de macros
## v11.1.1 - Les fumebols de Werther de Zloth
- Fix: on peut de nouveau afficher les vues détaillées
- Fix: on peut ouvrir les sacs et contenants portés par les véhicules et créatures
- Fix: cuisiner du gibier prend maintenant bien les proportaions en compte
## v11.1.0 - Les choix de Werther de Zloth
- Les options suivantes peuvent être désactivées:
- La transformation de stress à Château Dormant
- La récuperation de chance à Château Dormant
- La récupération d'éthylisme
- La récupération de rêve (y compris fleurs de rêve et Rêves de Dragon: la rencontre a lieu, mais ne donne pas de rêve)
- Le jet de moral de Château Dormant
- Séparation des véhicules dans leur propre acteur
- Séparation des entités dans leur propre acteur
- Séparation des créatures dans leur propre acteur
- La fenêtre de signes draconiques ne sélectionne plus tout les haut-rêvants par défaut
- Un nouveau personnage a automatiquement son token relié
- corrections de bugs
- si on n'utilise pas les règles de fatigues, un reflet de rêve pouvait garder le Haut-rêvant dans les TMRs pour toujours
- certaines macros ne marchaient pas pour les créatures/entités/véhicules/commerces
- en cas de charge, les particulières sont toujours en force (p125)
# v11.0
## v11.0.28 - les fractures de Khrachtchoum
- La gravité de la blessure est affichée dans le résumé de l'encaissement
- Lors du changement d'acteur pendant le round
- le message annonçant le joueur dont c'est le tour ne contient plus d'informations de santé
- un message avec les informations de santé est envoyé au Gardienn et au propriétaire du token.acteur
- le jet de vie est bien fait par le token si besoin
- seul les propriétaires peuvent faire les jets de vie
- Amélioration de la fenêtre de jets
- le type de dégâts pour les attaques est toujours affiché
- le moral est indiqué avant l'icone d'appel au moral
## v11.0.27 - Khrachtchoum le méticuleux
- le tooltip dans les TMR reste visible si on ne bouge pas la souris
- le surencombrement n'affecte QUE les actions physiques
- on peut de nouveau fabriquer une potion depuis la fenêtre d'édition de l'herbe
- si les TMR sont minimisées alors qu'une action est requise, elles sont bien réaffichées lorsque l'action est faite
## v11.0.26 - le crépuscule de Khrachtchoum
- gestion correcte des TMRs
- les TMRs ne sont jamais minimisées (par le système) quand le haut-rêvant est en demi-rêve
- lorsqu'une fenêtre liée aux demi-rêve est affichée, cliquer sur les TMRs n'a pas d'effet
- les lancers de sorts et lectures de signes sont affichées en premier plan
- Les effets qui ouvrent une fenêtre sont bien affichés en premier plan
- en cas de rencontre suivie de maîtrises/conquêtes, les fenêtres s'enchaînent
- Le drag&drop vers la barre de macro est corrigé
- pour les créatures, possibilités d'avoir les attaques ou autres compétences
- pour les personnages, les macros sont créées:
- pour les compétences
- pour le corps à corps, trois macros sont créées: compétence, pugilat, empoignade
- pour les armes
- deux macros sont créées pour les armes à 1/2 mains
- deux macros sont créées pour les armes de mélée et lancer
- 4 macros si votre arbalête se lance, tire, et se manie à 1 ou 2 mains...
- les jets de compétences d'attaque des créatures fonctionnent de nouveau
## v11.0.25 - la vision du rêve de Khrachtchoum
- Les TMRs restent affichées tant que le Haut-rêvant est en demi-rêve
## v11.0.24 - les couleurs de Khrachtchoum
- nouvelle carte des TMRs
## v11.0.23 - la lumière de Khrachtchoum
- ajustement automatique de la luminosité selon l'heure pour les scènes:
- avec une vision des tokens (sinon: ce n'est pas une scène de carte pour tokens)
- avec illumination globale (correspondant à une illumination extérieure)
- quand lampe "allumée" dans la fenêtre du calendrier
## v11.0.22 - les automatismes de Khrachtchoum le Problémeux
- Macro pour attaquer avec les compétences de créatures
## v11.0.20
- Macro pour attaquer avec les armes des personnages
## v11.0.17
- Fix: les actions de commerce ne s'appliquait pas bien aux personnages des tokens non liés
## v11.0.15 - L'apprentissage de Khrachtchoum
- Fix: l'expérience ne s'appliquait plus sur certaines réussites particulières (régression depuis la 11.0.7)
## v11.0.14 - Les pincettes de Khrachtchoum le Problémeux
- Correction du calcul de la place restante lors de l'ajout dans un conteneur
## v11.0.13 - La multiplication de l'eau de Khrachtchoum le Problémeux
- Correction de la vente depuis un commerce ayant des quantités illimitées
## v11.0.12 - Les poids de la mesure de Khrachtchoum le Problémeux
- Correction des malus de surencombrement
- Le malus armure est correctement affiché dans l'onglet des caractéristiques
- Correction d'orthographe et amélioration des messages des oeuvres d'art
## v11.0.11 - Les bleus de Khrachtchoum le Problémeux
- si le gardien configure le sommeil, les joueurs sont notifiés que chateau dormant vient de passer
- possibilité de créer des armes et des compétences de créatures non-mortelles.
## v11.0.10 - Les Songes de Khrachtchoum le Problémeux
- on peut de nouveau se déplacer dans les TMRs d'un clic sur la case à atteindre
- Lire un livre depuis l'inventaire permet de nouveau de faire un jet de la tâche
créée au lieu de créer toujours une nouvelle tâche
- La sélection des TMR pour la création de signes draconiques ne cause plus d'erreurs
- la récupération d'endurance en cas d'insomnie est limitée à la moitié
- le résultat du sommeil lors d'un rêve de dragon à la première heure s'affiche normalement
- lorsque le gardien gère la durée des nuits, en cas de rêve de dragon,
les heures dormies sont déduites des heures restant à dormir
## v11.0.9 - Les Souvenirs de Khrachtchoum le Problémeux
- mode de saisie de l'archétype en vue détaillée
- création une nouvelle incarnation depuis l'archétype
- réorganisation de la fenêtre de sélection des règles optionnelles
- correction de l'affichage du type dans les fenêtres d'objets
## v11.0.8 - la poigne de Sémolosse
- lien vers le changelog
- organisation des compendiums du système
- correction de l'empoignade
- les items d'empoignade sont ajoutés par le MJ quand nécessaire
- seul le joueur propriétaire du personnage peut effectuer ses choix et actions d'empoignade
- les caractéristiques du défenseur sont utilisées pour la défense
- la difficulté d'attaque est imposée au défenseur
- les attaques particulières sont en finesse (p133)
- on peut entraîner au sol dès 2 points d'empoignade
- les actions liée à l'immobilisation sont proposées en fin de round
# v11.0.7
- les créatures ont maintenant le droit d'avoir des compétences de tir, lancer, mêlée, armes naturelles, parade.
- les créatures armées utilisent la bonne phase d'initiative
- correction des possessions
- la difficulté de la défense est imposée par l'attaque
- une attaque particulière de possession est en finesse
- le rêve actuel des personnages est bien utilisé
- correction des achats par le MJ sans acteur sélectionné
Cf branche v10 pour l'historique des versions 10
Initial official release

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/empoignade.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
icons/sante/blessure.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
icons/sante/eraflure.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

BIN
icons/sante/mort.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

1
icons/tmr/attache.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-3" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M90.53 23c-18.345 0-36.688 7.002-50.686 21-27.996 27.996-27.994 73.38 0 101.375 21.776 21.776 54.08 26.603 80.53 14.5l53.69 53.688c-21.425 19.696-44 38.257-67.44 55.937l30.126 30.125c18.734-22.545 37.953-44.474 57.844-65.53l169.594 169.593c-51.845 40.444-120.866 53.838-192.813 42.562L173 424.906 72.47 404.47l95.405 88.405 1.97-26c86.593 36.97 177.603 34.61 241.343-11.75l63.062 21.313-21.47-63.594c44.61-63.62 46.408-153.412 9.908-238.875l26.03-1.97-88.406-95.375 20.438 100.53 21.344-1.624c11.278 71.983-2.168 141.017-42.656 192.876l-169.782-169.75c21.075-20.34 42.93-39.665 65.78-57.72l-30.123-30.124c-17.015 24.154-35.673 46.66-55.688 67.813l-53.97-53.97C167.834 98.183 163.032 65.814 141.22 44c-14-13.998-32.343-21-50.69-21zm0 27.03c11.434.002 22.872 4.34 31.595 13.064 17.447 17.447 17.446 45.742 0 63.187-17.446 17.447-45.71 17.447-63.156 0-17.447-17.444-17.448-45.74 0-63.186C67.69 54.37 79.097 50.03 90.53 50.03z" fill="#8eff09" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

1
icons/tmr/conquete.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M27.084 18.248C-17.903 146.478 143.15 277.92 314.496 381.074c-4.645 13.767-5.585 27.628-3.394 40.635 4.44 26.355 20.974 48.997 42.86 62.425 21.884 13.428 49.776 17.57 75.645 5.765 25.87-11.804 48.69-38.923 62.737-84.654l-17.865-5.488c-13 42.318-32.806 64.094-52.63 73.14-19.825 9.047-40.69 5.998-58.116-4.693-17.425-10.69-30.75-29.095-34.205-49.6-3.455-20.507 2.232-43.318 24.677-65.218 20.743-20.24 32.068-41.615 30.434-61.24l-18.622 1.552c.74 8.89-4.35 22.76-16.684 37.486C222.057 230.8 73.838 128.622 27.084 18.248zm458.05 0C451.34 98.03 364.527 173.53 270.93 247.166c19.492 15.878 39.56 31.622 59.195 45.012 110.756-84.836 187.878-180.243 155.01-273.93zM127.58 292.146c-1.634 19.626 9.69 41 30.434 61.24 22.445 21.9 28.132 44.712 24.677 65.218-3.455 20.506-16.78 38.91-34.206 49.6-17.425 10.692-38.29 13.74-58.115 4.694-19.825-9.046-39.632-30.822-52.63-73.14l-17.865 5.488c14.046 45.73 36.867 72.85 62.736 84.654 25.87 11.805 53.763 7.663 75.648-5.765 21.885-13.428 38.42-36.07 42.86-62.426 2.19-13.005 1.25-26.863-3.393-40.628 13.986-8.42 27.905-17.022 41.648-25.803l-56.967-39.387c-6.55 5.103-13.063 10.2-19.52 15.293C150.55 316.46 145.46 302.59 146.2 293.7l-18.622-1.554zm18.1 73.614c-26.1 8.6-62.087 36.255-77.104 60.324 4.948 8.63 10.393 15.223 16.05 20.14 25.846-8.953 59.85-37.406 74.733-60.257-3.007-6.6-7.454-13.386-13.68-20.207zm220.863 0c-6.225 6.822-10.67 13.61-13.68 20.21 14.886 22.85 48.89 51.3 74.736 60.255 5.656-4.918 11.1-11.51 16.05-20.14-15.018-24.07-51.004-51.724-77.105-60.325z" fill="#b41e00" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="10" result="blur"></feGaussianBlur><feOffset dx="0" dy="10" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-3" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M400.9 104.8c-12 30-41 47.9-99.7 43.9-13.7-1.8-27.6-4.1-41.6-6.7-119.1-37.2-236.24-37.2-236.24 37.2 33.48-37.2 117.74-30.8 225.04-4 116.8 29.2 241.8 41.2 241.8-51.8-18.4 19.3-53.4 28.6-96.6 30.4 10-10.4 12.5-26.7 7.3-49zM147 187.5c-70.75-.3-123.64 16.1-123.64 66.1 33.48-37.2 117.74-34.8 225.04-8 116.8 29.2 241.8 45.2 241.8-47.8-35.4 37.2-130.2 39.6-230.6 8-37.7-11.9-78-18.2-112.6-18.3zm-23.9 69.6c-58.44-.2-99.74 15.6-99.74 70.9 33.48-37.2 122.34-44.3 225.04-18.6 121 30.2 241.8 37.2 241.8-37.2-35.4 37.2-132.1 22.6-230.6 4-48.4-7.5-96.5-19.1-136.5-19.1zm0 74.3c-58.44-.1-99.74 15.8-99.74 71 19.03-21.1 55.52-30.3 102.54-30.8-10.4 10.4-12.9 26.9-7.7 49.4 13.9-34.8 52-51.8 130.3-37.2 122.6 22.8 241.7 37.2 241.7-37.2-35.4 37.2-132.1 18.6-230.6 0-48.4-7.6-96.5-15.1-136.5-15.2z" fill="#48baff" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

124
icons/tmr/demi-reve.svg Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 512px; width: 512px;"
version="1.1"
id="svg30"
sodipodi:docname="demi-reve.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata34">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2014"
inkscape:window-height="1404"
id="namedview32"
showgrid="false"
inkscape:zoom="2.2094112"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg30" />
<defs
id="defs24">
<filter
id="shadow-6"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood2" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite4" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur6" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset8" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite10" />
</filter>
<filter
id="shadow-7"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood13" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite15" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur17" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset19" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite21" />
</filter>
</defs>
<g
class=""
transform="translate(-2.1627108,-0.3)"
id="g28">
<path
d="m 342.5,17.9 c -3.1,11.63 -2.2,21.56 -23.8,25.11 20.3,-2.7 22.3,9.58 24.8,21.49 -2.8,1.94 -5.5,4.11 -8.1,6.49 -21.9,20.84 -33,41.11 -49,61.61 -6.3,1.2 5.3,-53.52 31.1,-79.87 C 225.1,40.92 207.6,268.4 236.4,275 184.7,293.4 163.8,176.7 177,117.7 c -37.1,3.9 -62,39.8 -67.9,60 2.8,27.1 6.1,55.1 38.7,80.9 -32.1,3.6 -42,-27.8 -55.31,-54 -78.59,104.9 105.91,106.8 136.01,94.5 -93,70.5 -149.62,52.3 -196.77,39 -40.48,85.1 61.46,56 107.57,35.7 -18.4,30.7 -72.25,37.6 -88.92,41 61.62,51.3 174.42,-67 200.02,-106.5 2.5,65.7 -74.3,134.4 -122.8,171.7 43.6,2.2 83.2,-17.9 102.4,-55.5 0,10.1 -4.1,22.6 -9.6,35.8 15,-2.1 39.6,-6.2 48.8,-24.2 25,-54.1 37.8,-93.1 15.3,-138.2 29.9,33.5 63.6,65.3 58.4,114.5 26.9,-15.6 48.8,-33.6 24.7,-60.1 14.1,1.4 23.6,7.7 32.8,13.7 13.9,-2.8 34.4,-19.9 33.7,-33 -31.6,-29.8 -83.4,-43.7 -133.8,-55.9 72.1,-19.8 136.9,-10.1 175.6,5.6 5,-11.7 9.4,-29.6 5.9,-41.9 -16.4,-9.7 -62.7,-7.8 -83.3,-5.6 17.7,-15.7 56.8,-21.1 81.3,-21.2 -2,-67.7 -162.6,27.8 -182.2,42.8 32.7,-59.1 123.2,-112.7 178.7,-121.1 -13.2,-31.1 -37.2,-34 -64.3,-22.4 2.4,-9.5 6.7,-17.49 23.4,-15.29 -21.6,-3.51 -20.7,-13.44 -23.8,-25.07 -2.4,13.55 -4.1,17.11 -19.4,26.67 14.3,-2.17 16.4,6.69 17.4,14.69 -53.5,24.4 -117.8,102.8 -135.1,132.5 -22.1,-24 51,-121.5 107.7,-187.46 -3.1,-9.48 -21.8,-6.31 -38.2,4.81 1.1,-8.63 0.7,-22.16 17.9,-19.54 -15.3,-9.6 -17,-13.16 -19.4,-26.71 z m -166.3,0.3 c 5.4,10.73 12.7,17.53 -1,34.56 13.8,-16.07 23.7,-7.13 33.9,0.22 -4.6,-7.19 -16.3,-17.67 -0.7,-27.86 -17.8,3.09 -21.4,1.57 -32.2,-6.92 z M 47.71,26.61 C 44.63,38.24 45.58,48.17 23.95,51.66 44.97,48.92 46.34,62.21 49.01,74.47 50.44,66.04 48.73,50.5 67.15,53.31 51.88,43.72 50.17,40.16 47.71,26.61 Z m 419.39,5.5 c 1.6,10.83 1.3,13.93 -7.8,25.07 13.1,-6.8 15.9,5.39 19.1,11.38 C 477.2,58.59 475,48.2 491.5,44.92 474.3,47.79 472.4,40.07 467.1,32.11 Z M 125.3,84.28 c -0.6,18.02 -12,17.32 -22.7,17.92 7,2.4 20.3,3 15.3,18.2 10.2,-11.6 13.3,-12.5 25.2,-12.6 -9.4,-4.3 -17.8,-4.9 -17.8,-23.52 z M 71.21,153.9 c -8.61,8.5 -12.85,17.5 -33.24,9.6 19.47,8.3 13.98,20.4 10.08,32.4 5.46,-6.6 11.9,-20.9 26.35,-9.1 -8.38,-16 -8.02,-19.9 -3.19,-32.9 z M 453.9,282.7 c -2.4,8.9 -1.7,16.5 -18.2,19.2 16,-2.1 17.1,8.1 19.2,17.5 1.1,-6.5 -0.2,-18.4 13.8,-16.3 -11.7,-7.3 -13,-10 -14.8,-20.4 z M 69.25,293.8 c -12.82,12.7 -16.72,13.5 -30.41,12.7 10.55,5.7 20.39,7.1 18.72,29 2.3,-21.1 15.46,-19.4 28.05,-19.1 -7.83,-3.3 -23.4,-5.3 -16.36,-22.6 z m 394.55,50.7 c 3.1,11.6 8.9,19.7 -8,33.6 16.8,-12.9 24.6,-2.2 33.2,7.1 -3.1,-8 -12.4,-20.6 4.9,-27.4 -18,-0.5 -21.3,-2.8 -30.1,-13.3 z m -139.2,72.1 c -2.7,12.3 -4.1,25.5 -25.1,22.8 21.6,3.5 20.7,13.4 23.8,25 2.4,-13.5 4.1,-17.1 19.4,-26.6 C 324.3,440.6 326,425 324.6,416.6 Z M 83.9,438.2 c -2.83,16 -4.84,20.2 -22.86,31.5 21.68,-3.3 19.67,15.1 21.33,25 3.19,-14.5 4.84,-30.1 29.63,-26.9 -25.5,-4.2 -24.43,-15.9 -28.1,-29.6 z m 366.2,11.4 c -7.3,9.6 -10.2,19.1 -31.5,14.2 20.4,5.4 16.8,18.1 14.6,30.6 4.5,-7.3 8.8,-22.4 24.8,-12.8 -10.6,-14.6 -10.8,-18.6 -7.9,-32 z"
fill="#ffffff"
fill-opacity="1"
id="path26" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 512px; width: 512px;"
version="1.1"
id="svg6"
sodipodi:docname="desorientation.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1599"
inkscape:window-height="932"
id="namedview8"
showgrid="false"
inkscape:zoom="1.3119567"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg6" />
<path
d="m 203.97,23 -18.032,4.844 11.656,43.468 c -25.837,8.076 -50.32,21.653 -71.594,40.75 l -31.47,-31.468 -13.218,13.22 31.376,31.374 c -19.467,21.125 -33.414,45.53 -41.813,71.343 l -42.313,-11.343 -4.843,18.063 42.25,11.313 c -6.057,27.3 -6.157,55.656 -0.345,83 l -41.904,11.216 4.843,18.064 41.812,-11.22 c 6.693,21.225 17.114,41.525 31.25,59.876 l -29.97,52.688 -16.81,29.593 29.56,-16.842 52.657,-29.97 c 18.41,14.216 38.784,24.69 60.094,31.407 l -11.22,41.844 18.033,4.81 11.218,-41.905 c 27.345,5.808 55.698,5.686 83,-0.375 l 11.312,42.28 18.063,-4.81 -11.344,-42.376 c 25.812,-8.4 50.217,-22.315 71.342,-41.78 l 31.375,31.373 13.22,-13.218 -31.47,-31.47 c 19.09,-21.266 32.643,-45.738 40.72,-71.563 l 43.53,11.657 4.813,-18.063 -43.625,-11.686 c 5.68,-27.044 5.576,-55.06 -0.344,-82.063 l 43.97,-11.78 -4.813,-18.063 L 440.908,197 c -6.73,-20.866 -17.08,-40.79 -31.032,-58.844 l 29.97,-52.656 16.842,-29.563 -29.593,16.844 -52.656,29.97 C 356.441,88.876 336.565,78.553 315.782,71.845 l 11.783,-44 L 309.5,23 297.72,66.97 c -27,-5.925 -55.02,-6.05 -82.064,-0.376 z m 201.56,85 -108.28,190.313 -0.75,0.437 -40.844,-40.875 -148.72,148.72 -2.186,1.25 109.125,-191.75 41.78,41.78 L 405.532,108 Z m -149.686,10.594 c 21.858,0 43.717,5.166 63.594,15.47 l -116.625,66.342 -2.22,1.28 -1.28,2.22 -66.25,116.406 c -26.942,-52.04 -18.616,-117.603 25.03,-161.25 26.99,-26.988 62.38,-40.468 97.75,-40.468 z m 122.72,74.594 c 26.994,52.054 18.67,117.672 -25.002,161.343 -43.66,43.662 -109.263,52.005 -161.312,25.033 l 116.438,-66.282 2.25,-1.25 1.25,-2.25 66.375,-116.592 z"
fill="#d0021b"
fill-opacity="1"
id="path2"
style="fill:#401060;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

190
icons/tmr/fermeture.svg Normal file
View File

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 512px; width: 512px;"
version="1.1"
id="svg52"
sodipodi:docname="fermeture.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata56">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="1083"
id="namedview54"
showgrid="false"
inkscape:zoom="1.5990661"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg52" />
<defs
id="defs46">
<filter
id="shadow-1"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(248, 231, 28, 1)"
result="flood"
id="feFlood2" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite4" />
<feGaussianBlur
in="composite"
stdDeviation="40"
result="blur"
id="feGaussianBlur6" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset8" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite10" />
</filter>
<filter
id="shadow-3"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(248, 231, 28, 1)"
result="flood"
id="feFlood13" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite15" />
<feGaussianBlur
in="composite"
stdDeviation="40"
result="blur"
id="feGaussianBlur17" />
<feOffset
dx="0"
dy="0"
result="offset"
id="feOffset19" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite21" />
</filter>
<filter
id="shadow-6"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood24" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite26" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur28" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset30" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite32" />
</filter>
<filter
id="shadow-7"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood35" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite37" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur39" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset41" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite43" />
</filter>
</defs>
<g
class=""
id="g50"
transform="matrix(1.1287777,0,0,1.1287777,-32.967091,-40.026839)">
<path
d="M 72.877,31.904 C 71.887,31.89 70.919,31.91 69.889,32.002 43.67,35.408 22.545,61.005 18,93.775 v 26.15 c 2.296,16.266 8.804,30.665 17.848,41.565 -6.58,1.237 -12.504,3.53 -17.848,6.717 v 23.813 c 22.983,0.386 43.265,14.03 57.31,34.318 C 89.56,246.92 98,274.598 98,305 98,335.402 89.56,363.08 75.31,383.662 61.266,403.95 40.984,417.592 18,417.98 v 8.577 L 23.03,494 H 30.7 L 138.904,332.176 140,304 c 0.732,-41.132 16.536,-59.598 32,-48 4.26,3.195 8.3,6.024 12.135,8.533 l 23.574,-35.258 c -21.607,-17.4 -59.103,-43.23 -90.68,-68.658 10.89,-13.647 17.894,-32.612 17.894,-53.627 C 134.924,65.494 108.478,32 76,32 74.88,31.964 73.867,31.918 72.877,31.904 Z m 366.246,0 c -0.99,0.014 -2.002,0.06 -3.123,0.096 -32.478,0 -58.924,33.494 -58.924,74.99 0,21.015 7.005,39.98 17.895,53.627 -31.577,25.43 -69.073,51.26 -90.68,68.658 l 23.577,35.258 A 232.03,232.03 0 0 0 340,256 c 15.464,-11.598 31.268,6.868 32,48 l 1.096,28.174 L 481.3,494 h 7.67 L 494,426.557 v -8.578 C 471.017,417.591 450.735,403.949 436.69,383.661 422.44,363.08 414,335.402 414,305 c 0,-30.402 8.44,-58.08 22.69,-78.662 14.045,-20.288 34.327,-33.932 57.31,-34.318 v -23.813 c -5.344,-3.187 -11.27,-5.48 -17.848,-6.717 9.044,-10.9 15.552,-25.3 17.848,-41.566 V 93.774 C 489.454,61.004 468.33,35.408 442.11,32.002 a 28.52,28.52 0 0 0 -2.987,-0.098 z m -290.365,14.854 40.068,110.215 47.34,-31.653 z m 214.484,0 -87.408,78.562 47.34,31.653 z M 230.25,150.93 213.625,162.047 435.588,494 h 24.057 z m 51.5,0 -14.922,22.316 12.03,17.99 19.517,-29.19 z M 18,210.018 v 189.964 c 15.993,-0.38 30.943,-9.855 42.512,-26.566 C 72.322,356.356 80,332.036 80,305 80,277.965 72.322,253.643 60.512,236.584 48.942,219.874 33.992,210.398 18,210.018 Z m 476,0 c -15.993,0.38 -30.943,9.855 -42.512,26.566 C 439.678,253.644 432,277.964 432,305 c 0,27.035 7.678,51.357 19.488,68.416 11.57,16.71 26.52,26.186 42.512,26.566 z M 233.145,223.62 52.355,494 H 76.412 L 245.174,241.61 Z M 134.748,439.14 98.066,494 h 34.55 z m 242.504,0 2.13,54.86 h 34.552 z"
fill="#003fb2"
fill-opacity="1"
transform="matrix(0.9,0,0,0.9,25.6,25.6)"
filter="url(#shadow-1)"
id="path48" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

1
icons/tmr/maitrisee.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-3" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><g transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"><path d="M256 20C198.562 20 152 66.562 152 124C152 181.438 198.562 228 256 228C313.438 228 360 181.438 360 124C360 66.562 313.438 20 256 20Z" class="" fill="#087505" fill-opacity="0"></path><path d="M16 256L16 496L64 496C128 336 384 336 448 496L496 496L496 256L448 256L448 320L388 320L388 256L340 256L340 320L280 320L280 256L232 256L232 320L172 320L172 256L124 256L124 320L64 320L64 256L16 256Z" class="selected" fill="#087505" fill-opacity="1" filter="url(#shadow-3)"></path></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

1
icons/tmr/pelerinage.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M259.844 73.406l1.625 214.47-18.69.155-1.655-214.342C206.358 75.24 172.012 82.588 141 95.78c36.116 61.6 59.493 126.474 75.813 196.5l-18.22 4.25C182.46 227.29 159.504 163.924 124 103.78c-37.016 19.19-67.986 47.49-87.156 84.97 57.884 24.66 105.126 67.86 140.937 118.688l-15.28 10.75c-34.284-48.66-79.092-89.328-133.28-112.344-8.57 22.082-13.345 46.943-13.345 74.594 95.028 17.855 145.516 75.937 151.406 92 3.752 10.228-27.905 21.074-27.905 38.156 0 12.34 25.52 20.537 59.668 24.67-3.846-4.94-7.694-10.374-11.59-16.31l15.625-10.255c9.802 14.937 18.996 25.865 27.354 32.73 8.358 6.864 15.493 9.632 22.423 9.68 13.862.094 31.592-12.316 53.723-42.776l15.12 10.984c-4.31 5.93-8.553 11.385-12.76 16.35 36.362-4.006 64.125-12.375 64.125-25.074 0-17.92-35.487-28.412-33.72-39.97 2.31-15.09 55.528-74.91 156.626-90.187 0-28.807-5.284-54.622-14.72-77.437-57.322 22.41-104.478 64.46-140.22 115.188l-15.28-10.75c37.145-52.72 86.607-97.216 147.47-121.344-20.457-37.87-53.207-66.233-92.064-85.03-36.426 60.947-59.84 125.186-76.22 195.467l-18.186-4.25c16.523-70.893 40.278-136.5 77.156-198.78-32.42-12.835-68.166-19.55-104.062-20.094z" fill="#b41e00" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

1
icons/tmr/periple.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-3" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M149.9 27.2L34.25 56.74v76.76L157.8 93.85l46.7-44.67-54.6-21.98zm132.8 57c-7.4.18-10.1 1.88.9 7.13C346.9 121.6 441.7 206.8 391.3 216.9 232.2 249 130.4 292.3 48.51 390.8 25.42 418.6 18 494.8 18 494.8h432.6s-139-21.1-147.8-75.7c-14.9-92.2 194.5-102.7 196.5-199.9.9-43.2-88.3-124.99-184.4-132.52-5.6-.44-22.7-2.71-32.2-2.48zm-163.5 40.9l-32.69 10.5v122.2l35.99-10-3.3-122.7z" fill="#b41e00" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

1
icons/tmr/present.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><path d="M0 0h512v512H0z" fill="#4a4a4a" fill-opacity="0.5"></path><g class="" transform="translate(1,-1)" style=""><path d="M149.518 78.38c-6.55.117-12.45 1.736-17.35 4.91-7.465 4.84-11.765 12.904-13.063 21.34-2.595 16.874 4.747 36.355 19.862 52.31C154.08 172.893 177.643 185 208 185h2.438l-9.118-18.234c-22.194-1.554-38.46-10.777-49.287-22.205-11.885-12.545-16.543-28.064-15.138-37.19.702-4.564 2.402-7.25 5.062-8.974 2.66-1.724 7.113-2.875 14.756-1.326 13.078 2.65 34.233 13.948 62.205 39.284L220.27 135h23.408c-35.31-34.8-62.215-51.278-83.39-55.57-2.715-.55-5.363-.887-7.925-1.006-.96-.045-1.91-.06-2.845-.043zm212.964 0c-.935-.016-1.885 0-2.845.044-2.562.12-5.21.455-7.924 1.006-21.176 4.292-48.082 20.77-83.39 55.57h23.406l1.352 1.354c27.972-25.336 49.127-36.633 62.205-39.284 7.643-1.55 12.096-.398 14.756 1.326 2.66 1.725 4.36 4.41 5.062 8.973 1.405 9.126-3.253 24.645-15.138 37.19-10.827 11.43-27.093 20.652-49.287 22.206L301.562 185H304c30.357 0 53.92-12.106 69.033-28.06 15.115-15.955 22.457-35.436 19.862-52.31-1.298-8.436-5.598-16.5-13.063-21.34-4.9-3.174-10.8-4.793-17.35-4.91zM227.73 153l-8.78 8.777L229.564 183h52.875l10.61-21.223-8.777-8.777h-56.54zM73 201v46h142v-46H73zm160 0v270h46V201h-46zm64 0v46h142v-46H297zm-192 64v206h110V265H105zm192 0v206h110V265H297z" fill="#ffffff" fill-opacity="1"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

1
icons/tmr/rencontre.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M324.97 17.54c.03.034.057.07.087.106l-34.924 32.428 36.904-3.752-15.396 30.12 38.048-16.075c26.147 69.965.623 154.277-52.555 166.262-6.554-25.37-34.13-37.945-36.055-57.382.303.093.604.187.912.27 4.833 1.295 9.736 1.183 14.274-.07l25.138 22.89 20.653-16.377c-7.363 2.836-28.588-1.402-33.25-13.923 3.154-3.24 5.55-7.284 6.793-11.922.485-1.813.757-3.635.86-5.445l11.524 22.777 5.22-16.94c7.625 5.575 12.474 13.605 11.49 21.136l16.673-29.4-72.14-29.56-58.057-48.03 17.1 31.25-48.206-19.753 35.14 31.237c-40.602 28.158-22.085 85.04-1.796 119.29-57.5-9.685-103.128-77.435-95.763-145.03l49.21-21.366-31.08-5.14 29.207-33.417-32.015 11.54c.037-.067.07-.135.107-.202-168.36 66.33-116.413 367-63.728 417.99-.19-1.317-.364-2.58-.54-3.855-14.922-56.244-20.375-125.624-17.5-190.53 3.02-68.237 14.834-131.16 36.794-169.522l16.22 9.283c-18.894 33.008-31.4 94.563-34.345 161.064-1.942 43.86.106 90.022 6.275 132.082 6.124 1.892 15.046 9.615 27.295 23.24-4.818-13.35-6.78-26.5-6.482-38.28 20.286 41.665 67.34 69.234 104.633 62.308 22.444-4.17 41.803-12.73 57.81-24.475l7.31 15.418c-20.068 5.036-22.807 32.635-14.737 55.112 1.748-19.882 11.36-29.794 21.73-32.303-6.598 15.867-4.698 30.623-3.117 44.158 10.15-12.147 21.47-23.793 23.628-39.354 8.738 7.332 12.317 21.49 1.194 39.057 26.32-15.473 31.565-41.994 7.978-57.685l-32.07-34.297c5.918-5.55 11.24-11.6 15.947-18.066l39.28 15.776c-3.942 13.69 5.833 31.512 19.77 43.31-8.055-17.288-4.826-30.08 2.562-37.103 1.63 17.39 10.64 29.193 18.733 40.064 2.73-15.665 6.79-31.493-.213-45.987 11.016 1.56 21.2 11.568 20.338 31.877 14.362-25.313 6.11-49.702-20.742-51.52l-71.135-9.892c12.757-22.982 18.676-49.823 17.015-77.475 14.188-34.708 50.058-11.816 54.523 49.16C394.924 262.27 434.58 304 426.324 367.13c11.808-23.38 21.835-35.013 29.862-36.247-10.772-91.925-40.458-191.57-77.637-250.748l15.823-9.942c50.328 80.106 85.112 220.65 84.88 331.547 42.403-115.912-2.347-356.61-154.282-384.2zm-29.458 476.913l-.026.016-.015.05c.015-.02.027-.044.042-.067zm26.543-318.492h.01v-.007l-.01.008zm-53.348-41.716c.866-.027 1.757.073 2.652.313 4.774 1.28 7.467 5.945 6.187 10.72-1.28 4.776-5.943 7.47-10.72 6.19-4.775-1.28-7.468-5.943-6.188-10.72.96-3.584 3.823-5.993 7.21-6.435.282-.036.568-.06.857-.068zM204.904 297.13c11.878-.2 22.637 6.756 26.172 22.487-.008 35.88-9.557 68.823-42.137 77.412-27.624 7.283-69.725-11.398-84.12-53.663 12.28-21.078 37.362-21.986 62.838 22.592-12.583-41.596 14.386-68.444 37.246-68.83z" fill="#003fb2" fill-opacity="1" filter="url(#shadow-1)" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)"></path></g></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

1
icons/tmr/reserve.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M149.688 85.625c-1.234.005-2.465.033-3.72.063-33.913.806-75.48 10.704-127.25 33.718V362.78c60.77-28.82 106.718-37.067 144.22-33.092 33.502 3.55 59.685 16.66 83.562 31.187v-242.97c-23.217-17.744-50.195-30.04-85.97-32-3.52-.192-7.142-.296-10.843-.28zm211.968 0c-3.7-.016-7.322.088-10.844.28-35.773 1.96-62.75 14.256-85.968 32v242.97c23.876-14.527 50.06-27.637 83.562-31.188 37.502-3.974 83.45 4.272 144.22 33.094V119.407c-51.77-23.014-93.337-32.912-127.25-33.72-1.255-.028-2.486-.056-3.72-.06zm5.72 261.78c-1.038-.002-2.074.017-3.095.033-4.808.075-9.43.37-13.905.843-33.932 3.597-59.603 17.976-85.53 34.44v.28c-6.554-1.99-13.02-2.37-19.408-.97-25.566-16.177-51.003-30.202-84.468-33.75-5.595-.592-11.44-.883-17.564-.842-32.04.213-71.833 9.778-124.687 35.937v42.53c60.77-28.823 106.714-37.067 144.218-33.092 18.545 1.965 34.837 6.845 49.75 13.28-4.682 6.064-9.308 13.268-13.875 21.688h117.156c-5.93-8.22-11.798-15.414-17.626-21.56 14.996-6.503 31.39-11.43 50.062-13.408 37.503-3.974 83.448 4.27 144.22 33.094v-42.53c-53.16-26.31-93.115-35.863-125.25-35.97z" fill="#087505" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 256px; width: 256px;"
version="1.1"
id="svg24"
sodipodi:docname="sort-reserve-humide3.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata30">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs28" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2794"
inkscape:window-height="1756"
id="namedview26"
showgrid="false"
inkscape:zoom="2.8786993"
inkscape:cx="323.66586"
inkscape:cy="227.70764"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg24" />
<g
id="g881"
transform="translate(2.1482304,2.80716)">
<path
d="m 243.94189,104.37921 -82.23331,178.13543 82.23331,27.44784 z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path2"
style="stroke-width:1.10232" />
<path
d="m 263.7837,104.37921 v 205.58327 l 82.23331,-27.44784 z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path4"
style="stroke-width:1.10232" />
<path
d="M 168.21228,221.005 18.274279,239.7445 141.75653,278.32581 Z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path6"
style="stroke-width:1.10232" />
<path
d="M 339.51331,221.005 365.96906,278.32581 489.5395,239.7445 Z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path8"
style="stroke-width:1.10232" />
<path
d="M -0.24475089,254.73609 114.97007,398.80973 230.27308,326.7178 Z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path10"
style="stroke-width:1.10232" />
<path
d="M 507.94829,254.73609 277.45251,326.7178 392.75552,398.80973 Z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path12"
style="stroke-width:1.10232" />
<path
d="M 253.8628,335.42615 147.37837,402.00647 H 360.34722 Z"
class=""
fill="#f4e3d7"
fill-opacity="1"
id="path14"
style="stroke-width:1.10232" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

132
icons/tmr/sort-reserve.svg Normal file
View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 512px; width: 512px;"
version="1.1"
id="svg32"
sodipodi:docname="sort-reserve.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata36">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2318"
inkscape:window-height="1268"
id="namedview34"
showgrid="false"
inkscape:zoom="1.9888504"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg32" />
<defs
id="defs24">
<filter
id="shadow-6"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood2" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite4" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur6" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset8" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite10" />
</filter>
<filter
id="shadow-7"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood13" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite15" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur17" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset19" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite21" />
</filter>
</defs>
<path
d="M 0,0 H 512 V 512 H 0 Z"
fill="#4a4a4a"
fill-opacity="0.5"
id="path26"
style="stroke-width:1;fill:#4a4a4a;fill-opacity:0.01" />
<g
class=""
transform="translate(1,-1)"
id="g30"
style="fill:#f4e3d7">
<path
d="m 373.563,18.406 c -15.616,-0.167 -27.91,4.622 -32.563,14.75 -22.778,49.605 -48.743,87.14 -79.094,117.28 3.047,1.015 6.046,2.29 8.938,3.783 12.987,6.708 25.268,17.78 35.312,30.843 10.044,13.062 17.85,28.114 20.78,43.5 0.746,3.908 1.16,7.885 1.158,11.843 38.97,-24.36 85.058,-41.223 140.875,-51.312 14.91,-2.697 23.652,-28.632 21.405,-58.656 l -35.156,-1 30.56,-24.813 C 481.63,90.117 474.765,75.87 464.623,63.904 449.095,45.59 428.193,32.528 407.903,25.218 l -25.963,15.594 2.812,-21.5 c -3.875,-0.55 -7.61,-0.87 -11.188,-0.907 z M 246.938,166.562 c -1.063,0.052 -2.06,0.226 -3,0.47 -11.976,10.254 -24.61,19.597 -37.938,28.28 0.842,0.33 1.67,0.667 2.5,1.032 14.123,6.192 27.438,17.145 38.47,30.625 13.356,16.322 23.62,36.94 25.624,57.75 10.334,-10.367 21.24,-19.943 32.844,-28.72 4.096,-6.555 4.93,-14.468 3.125,-23.938 -2.184,-11.46 -8.642,-24.43 -17.25,-35.625 -8.61,-11.194 -19.38,-20.622 -29.063,-25.625 -6.052,-3.126 -11.154,-4.45 -15.313,-4.25 z m -61.907,43.282 c -1.385,0.053 -2.69,0.27 -3.968,0.562 -37,20.762 -79.088,37.985 -127.312,56 0.574,0.042 1.14,0.093 1.72,0.156 10.627,1.156 21.076,5.008 31.155,10.875 L 124.313,261 108.5,293.72 c 5.995,5.432 11.803,11.477 17.344,18 20.76,24.434 37.964,55.865 47.094,88.092 0.002,0.01 -0.003,0.022 0,0.032 2.98,10.508 5.11,20.916 6.312,31 20.99,-48.438 44.38,-89.26 72.344,-123 7.3,-21.48 -2.186,-48.408 -19.063,-69.03 -9.44,-11.538 -20.976,-20.718 -31.53,-25.345 -5.936,-2.604 -11.27,-3.808 -15.97,-3.626 z m 141.626,54.844 c -7.31,5.05 -14.462,10.51 -21.437,16.312 39.16,9.26 60.953,35.722 80.655,62.156 10.464,14.04 20.598,28.11 33.125,40.688 24.19,9.147 43.17,6.38 63.906,-14.938 -92.165,-27.78 -96.11,-92.61 -156.25,-104.22 z M 48.594,284.906 c -10.873,0.225 -18.26,5.755 -23.344,16.594 -5.81,12.387 -7.114,32.47 0.438,57.063 5.75,18.73 16.52,37.718 28.75,51.625 12.23,13.906 25.9,22.076 35.374,22.406 h 0.032 c 3.717,0.13 6.553,-0.682 8.812,-2.75 l -0.187,-0.188 2.093,-2.094 c 0.793,-1.168 1.52,-2.548 2.187,-4.187 2.81,-6.9 3.28,-18.552 -1.844,-33 -6.885,-19.417 -19.12,-31.932 -33.375,-34.78 l -22.968,-4.564 19.813,-12.5 38.47,-24.186 c -16.65,-16.822 -34.55,-27.607 -49.376,-29.22 -1.7,-0.184 -3.323,-0.25 -4.876,-0.218 z m 236.25,5.406 -24.53,25.375 c 100.442,17.878 55.45,141.005 159.31,176.188 l -24.78,-57.28 c 32.766,16.15 67.39,22.623 97.72,12.03 -135.77,-41.948 -96.32,-126.983 -207.72,-156.313 z m -169.47,38.22 -25.968,16.343 c 13.18,8.5 23.21,22.565 29.125,39.25 2.57,7.244 4.133,14.205 4.75,20.78 l 23.44,-23.374 c -8.08,-19.19 -19.035,-37.566 -31.345,-53 z m 38.376,72.374 -42.063,42 -0.156,-0.156 c -4.255,3.942 -9.456,6.765 -15.186,7.938 23.268,14.873 44.644,19.346 56.812,9.562 4.26,-3.426 7.043,-8.36 8.47,-14.406 -0.41,-12.684 -2.602,-26.615 -6.657,-40.906 -0.382,-1.346 -0.806,-2.686 -1.22,-4.032 z"
fill="#ffffff"
fill-opacity="1"
id="path28"
style="fill:#f4e3d7" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

126
icons/tmr/trounoir.svg Normal file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 512 512"
style="height: 512px; width: 512px;"
version="1.1"
id="svg32"
sodipodi:docname="trounoir.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata36">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1553"
inkscape:window-height="1145"
id="namedview34"
showgrid="false"
inkscape:zoom="1.4374483"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg32" />
<defs
id="defs24">
<filter
id="shadow-6"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood2" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite4" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur6" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset8" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite10" />
</filter>
<filter
id="shadow-7"
height="300%"
width="300%"
x="-100%"
y="-100%">
<feFlood
flood-color="rgba(72, 186, 255, 1)"
result="flood"
id="feFlood13" />
<feComposite
in="flood"
in2="SourceGraphic"
operator="atop"
result="composite"
id="feComposite15" />
<feGaussianBlur
in="composite"
stdDeviation="8"
result="blur"
id="feGaussianBlur17" />
<feOffset
dx="5"
dy="15"
result="offset"
id="feOffset19" />
<feComposite
in="SourceGraphic"
in2="offset"
operator="over"
id="feComposite21" />
</filter>
</defs>
<path
d="M0 0h512v512H0z"
fill="#4a4a4a"
fill-opacity="0.5"
id="path26"
style="fill:#333333;fill-opacity:0.69999999" />
<path
d="m 329.547,18.115 c -30.61,99.22 -47.583,151.205 -86.88,156.778 -18.626,2.642 -42.988,-19.225 -70.16,-50.29 15.47,30.702 21.275,55.265 10.845,61.348 -15.787,9.21 -51.095,-6.94 -106.815,-30.837 31.653,20.827 83.667,50.18 77.358,58.63 -8.074,10.81 -77.23,-4.706 -130.866,-13.163 89.224,25.398 137.61,55.572 137.61,82.387 0,18.423 -48.845,62.18 -71.888,83.928 19.558,-11.397 64.736,-24.44 76.777,-2.99 13.335,23.758 -6.577,61.6 -28.5,128.027 31.39,-46.19 73.363,-108.122 90.734,-106.49 12.248,1.15 -4.805,60.692 -10.47,98.71 21.547,-80.082 46.534,-132.5 90.153,-131.015 29.665,1.01 58.022,30.762 88.99,52.047 -16.188,-19.81 -45.975,-47.99 -39.55,-53.243 8.9,-7.276 56.48,12.547 94.224,25.726 -24.982,-17.962 -68.644,-43.88 -61.653,-50.852 10.417,-10.387 72.436,1.332 117.49,7.178 C 419.2,303.266 370.1,289.807 359.616,255.461 c -5.283,-17.31 10.853,-40.3 40.89,-68.038 -31.377,17.197 -54.588,28.694 -63.737,12.392 -11.576,-20.622 11.374,-65.883 35.238,-126.06 -21.135,32.47 -48.532,83.487 -55.254,77.174 -8.972,-8.425 5.598,-77.597 12.795,-132.813 h -0.003 z M 21.45,18.27 V 41.63 C 69.97,69.067 116.703,104.02 162.783,144.416 129.015,102.731 95.443,60.626 68.758,18.27 Z m 175.79,0 c 18.465,37.356 34.503,76.96 48.475,117.97 -5.007,-39.79 -9.898,-79.367 -12.264,-117.97 h -36.21 z m 160.022,0 c -7.18,26.672 -15.416,53.437 -25.116,80.593 15.405,-27.34 30.698,-54.514 46.723,-80.593 H 357.26 Z m 105.123,0 c -27.895,50.718 -63.73,99.873 -105.707,147.755 46.514,-37.68 92.9,-75.343 140.164,-103.37 V 18.27 Z m 34.455,160.02 c -36.077,17.98 -74.843,34.036 -115.635,47.89 38.908,-6.17 77.882,-12.105 115.635,-15.77 z m -206.266,42.868 c 9.35,0 16.93,7.58 16.93,16.932 0,9.35 -7.58,16.93 -16.93,16.93 -9.35,0 -16.93,-7.58 -16.93,-16.93 0,-9.35 7.58,-16.932 16.93,-16.932 z m -52.06,1.598 c 15.508,0 28.082,12.57 28.082,28.08 0,9.718 -4.938,18.28 -12.44,23.322 3.614,3.843 5.842,9.002 5.842,14.694 0,11.86 -9.613,21.474 -21.473,21.474 -11.86,0 -21.474,-9.615 -21.474,-21.474 0,-5.687 2.228,-10.842 5.837,-14.684 -7.51,-5.04 -12.453,-13.608 -12.453,-23.332 0,-15.51 12.57,-28.08 28.08,-28.08 z M 21.45,234.078 v 38.547 c 31.87,-4.584 64.46,-5.693 97.532,-4.09 -33.727,-10.19 -67.407,-20.35 -97.53,-34.457 z m 265.82,28.377 c 9.35,0 16.93,7.58 16.93,16.932 0,9.35 -7.58,16.93 -16.93,16.93 -9.35,0 -16.932,-7.58 -16.932,-16.93 0,-9.35 7.58,-16.932 16.932,-16.932 z M 129.494,294.05 c -36.153,11.99 -72.24,20.293 -108.043,24.313 v 51.393 c 30.994,-28.64 69.426,-52.264 108.044,-75.703 v -0.002 z m 5.84,88.645 c -37.923,30.72 -75.607,61.482 -113.885,87.02 v 23.943 h 29.784 c 24.02,-37.76 52.365,-74.765 84.1,-110.963 z m 202.07,11.096 c 26.807,33.093 53.226,66.414 76.508,99.87 h 59.568 c -46.586,-27.078 -91.877,-61.12 -136.074,-99.87 z m -52.562,9.93 c -3.175,30.26 -6.39,60.5 -10.512,89.94 h 20.44 c -4.51,-29.083 -7.904,-59.17 -9.926,-89.94 z m 26.865,13.432 c 11.346,25.473 22.374,51.18 32.705,76.508 h 23.36 c -19.395,-23.9 -38.105,-49.64 -56.065,-76.508 z"
fill="#602000"
fill-opacity="1"
id="path28"
style="fill:#401060;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB

1
icons/tmr/urgence.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(248, 231, 28, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="40" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-6" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter><filter id="shadow-7" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(72, 186, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="8" result="blur"></feGaussianBlur><feOffset dx="5" dy="15" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" transform="translate(0,0)" style=""><path d="M103.432 17.844c-1.118.005-2.234.032-3.348.08-2.547.11-5.083.334-7.604.678-20.167 2.747-39.158 13.667-52.324 33.67-24.613 37.4 2.194 98.025 56.625 98.025.536 0 1.058-.012 1.583-.022v.704h60.565c-10.758 31.994-30.298 66.596-52.448 101.43-2.162 3.4-4.254 6.878-6.29 10.406l34.878 35.733-56.263 9.423c-32.728 85.966-27.42 182.074 48.277 182.074v-.002l9.31.066c23.83-.57 46.732-4.298 61.325-12.887 4.174-2.458 7.63-5.237 10.467-8.42h-32.446c-20.33 5.95-40.8-6.94-47.396-25.922-8.956-25.77 7.52-52.36 31.867-60.452 5.803-1.93 11.723-2.834 17.565-2.834v-.406h178.33c-.57-44.403 16.35-90.125 49.184-126 23.955-26.176 42.03-60.624 51.3-94.846l-41.225-24.932 38.272-6.906-43.37-25.807h-.005l.002-.002.002.002 52.127-8.85c-5.232-39.134-28.84-68.113-77.37-68.113C341.14 32.26 222.11 35.29 149.34 28.496c-14.888-6.763-30.547-10.723-45.908-10.652zm.464 18.703c13.137.043 27.407 3.804 41.247 10.63l.033-.07c4.667 4.735 8.542 9.737 11.68 14.985H82.92l10.574 14.78c10.608 14.83 19.803 31.99 21.09 42.024.643 5.017-.11 7.167-1.814 8.836-1.705 1.67-6.228 3.875-15.99 3.875-40.587 0-56.878-44.952-41.012-69.06C66.238 46.64 79.582 39.22 95.002 37.12c2.89-.395 5.863-.583 8.894-.573zM118.5 80.78h46.28c4.275 15.734 3.656 33.07-.544 51.51H131.52c1.9-5.027 2.268-10.574 1.6-15.77-1.527-11.913-7.405-24.065-14.62-35.74zm101.553 317.095c6.44 6.84 11.192 15.31 13.37 24.914 3.797 16.736 3.092 31.208-1.767 43.204-4.526 11.175-12.576 19.79-22.29 26h237.19c14.448 0 24.887-5.678 32.2-14.318 7.312-8.64 11.2-20.514 10.705-32.352-.186-4.473-.978-8.913-2.407-13.18l-69.91-8.205 42.017-20.528c-8.32-3.442-18.64-5.537-31.375-5.537H220.053zm-42.668.506c-1.152-.003-2.306.048-3.457.153-2.633.242-5.256.775-7.824 1.63-15.11 5.02-25.338 21.54-20.11 36.583 3.673 10.57 15.347 17.71 25.654 13.938l1.555-.57h43.354c.946-6.36.754-13.882-1.358-23.192-3.71-16.358-20.543-28.483-37.815-28.54z" fill="#b41e00" fill-opacity="1" transform="translate(25.6, 25.6) scale(0.9, 0.9) rotate(0, 256, 256) skewX(0) skewY(0)" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@ -1,52 +1,56 @@
{
"ACTOR": {
"TypePersonnage": "Personnage",
"TypeCreature": "Créature",
"TypeEntite": "Entité de cauchemar",
"TypeCommerce": "Commerce",
"TypeVehicule": "Véhicule"
},
"ITEM": {
"TypeObjet": "Objet",
"TypeGemme": "Gemme",
"TypeCompetence": "Compétence",
"TypeCompetencecreature": "Compétence de créature",
"TypeMaladie": "Maladie",
"TypePoison": "Poison",
"TypeNombreastral": "Nombre astral",
"TypeTarot": "Carte de tarot",
"TypeCasetmr": "TMR spéciale",
"TypeRencontre": "Rencontre TMR",
"TypeMunition": "Munition",
"TypeMonnaie": "Monnaie",
"TypeHerbe": "Herbe ou plante",
"TypeIngredient": "Ingrédient",
"TypeFaune": "Faune",
"TypeLivre": "Livre",
"TypePotion": "Potion",
"TypeArme": "Arme",
"TypeArmure": "Armure",
"TypeConteneur": "Conteneur",
"TypeNourritureboisson": "Nourriture & boisson",
"TypeService": "Service",
"TypeChant": "Chant",
"TypeDanse": "Danse",
"TypeMusique": "Musique",
"TypeOeuvre": "Oeuvre",
"TypeTache": "Tâche",
"TypeJeu": "Jeu",
"TypeRecettealchimique": "Recette alchimique",
"TypeRecettecuisine": "Recette de cuisine",
"TypeSort": "Sort",
"TypeMeditation": "Méditation",
"TypeSignedraconique": "Signe draconique",
"TypeQueue": "Queue de Dragon",
"TypeOmbre": "Ombre de Thanatos",
"TypeSouffle": "Souffle de Dragon",
"TypeTete": "Tête de Dragon",
"TypePossession": "Possession",
"TypeSortreserve": "Sort en réserve",
"TypeExtraitpoetique": "Extrait poetique"
"TYPES": {
"Actor": {
"Personnage": "Personnage",
"Creature": "Créature",
"Entite": "Entité de cauchemar",
"Commerce": "Commerce",
"Vehicule": "Véhicule"
},
"Item": {
"Arme": "Arme",
"Armure": "Armure",
"Blessure": "Blessure",
"Casetmr": "TMR spéciale",
"Chant": "Chant",
"Competence": "Compétence",
"Competencecreature": "Compétence de créature",
"Conteneur": "Conteneur",
"Danse": "Danse",
"Extraitpoetique": "Extrait poetique",
"Faune": "Faune",
"Gemme": "Gemme",
"Herbe": "Herbe",
"Ingredient": "Ingrédient",
"Jeu": "Jeu",
"Livre": "Livre",
"Maladie": "Maladie",
"Meditation": "Méditation",
"Monnaie": "Monnaie",
"Munition": "Munition",
"Musique": "Musique",
"Nombreastral": "Nombre astral",
"Nourritureboisson": "Nourriture & boisson",
"Objet": "Objet",
"Oeuvre": "Oeuvre",
"Ombre": "Ombre de Thanatos",
"Plante": "Plante",
"Poison": "Poison",
"Possession": "Possession",
"Potion": "Potion",
"Queue": "Queue de Dragon",
"Recettealchimique": "Recette alchimique",
"Recettecuisine": "Recette de cuisine",
"Rencontre": "Rencontre TMR",
"Service": "Service",
"Signedraconique": "Signe draconique",
"Sort": "Sort",
"Sortreserve": "Sort en réserve",
"Souffle": "Souffle de Dragon",
"Tache": "Tâche",
"Tarot": "Carte de tarot",
"Tete": "Tête de Dragon"
}
},
"EFFECT": {
"StatusStunned": "Sonné",

View File

@ -1,40 +0,0 @@
import { RdDActorSheet } from "./actor-sheet.js";
export class RdDActorEntiteSheet extends RdDActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
width: 640,
height: 720,
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}],
dragDrop: [{dragSelector: ".item-list .item", dropSelector: undefined}]
});
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// On competence change
this.html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) );
} );
this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) );
} );
this.html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) );
} );
}
}

View File

@ -7,31 +7,32 @@ import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { STATUSES } from "./settings/status-effects.js";
import { MAINS_DIRECTRICES } from "./actor.js";
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
import { RdDBaseActorReveSheet } from "./actor/base-actor-reve-sheet.js";
import { RdDItem } from "./item.js";
import { RdDItemBlessure } from "./item/blessure.js";
import { RdDEmpoignade } from "./rdd-empoignade.js";
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
import { ChatUtility } from "./chat-utility.js";
import { RdDCoeur } from "./coeur/rdd-coeur.js";
/* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorSheet extends RdDBaseActorSheet {
export class RdDActorSheet extends RdDBaseActorSangSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
return mergeObject(RdDBaseActorReveSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
width: 550,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
showCompNiveauBase: false,
vueDetaillee: false
vueArchetype: false,
});
}
@ -53,7 +54,8 @@ export class RdDActorSheet extends RdDBaseActorSheet {
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
caracTotal: RdDCarac.computeTotal(this.actor.system.carac, this.actor.system.beaute),
surEncombrementMessage: this.actor.getMessageSurEncombrement(),
surEncombrementMessage: this.actor.isSurenc() ? "Sur-Encombrement!" : "",
malusArmure: this.actor.getMalusArmure()
})
this.timerRecherche = undefined;
@ -66,9 +68,9 @@ export class RdDActorSheet extends RdDBaseActorSheet {
formData.calc.fatigue = RdDUtility.calculFatigueHtml(formData.system.sante.fatigue.value, formData.system.sante.endurance.max);
formData.competences.forEach(item => {
item.system.isVisible = this.options.recherche
? RdDItemCompetence.nomContientTexte(item, this.options.recherche.text)
: (!this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item));
item.system.isHidden = this.options.recherche
? !item.isNomLike(this.options.recherche.text)
: (this.options.showCompNiveauBase && RdDItemCompetence.isNiveauBase(item));
RdDItemCompetence.levelUp(item, formData.system.compteurs.experience.value);
});
@ -77,11 +79,15 @@ export class RdDActorSheet extends RdDBaseActorSheet {
});
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
formData.combat = duplicate(formData.armes ?? []);
const actor = this.actor;
formData.combat = duplicate(formData.armes);
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
formData.combat.push(RdDItemArme.mainsNues(actor));
formData.combat.push(RdDItemArme.empoignade(actor));
formData.esquives = this.actor.getCompetences("Esquive");
formData.combat = RdDCombatManager.listActionsArmes(formData.combat, formData.competences, formData.system.carac);
formData.empoignades = this.actor.getEmpoignades();
this.armesList = formData.combat;
@ -107,156 +113,116 @@ export class RdDActorSheet extends RdDBaseActorSheet {
return formData;
}
/* -------------------------------------------- */ /** @override */
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
this.html.find('.subacteur-open').click(async event => {
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id');
this.openSubActeur(subActorId);
})
this.html.find('.show-hide-competences').click(async event => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true);
});
this.html.find('.visu-tmr').click(async event => this.actor.displayTMR("visu"))
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor));
this.html.find('.subacteur-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id");
if (actorId) {
const subActor = game.actors.get(actorId);
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li);
}
});
this.html.find('.experiencelog-delete').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(key, 1);
});
this.html.find('.experiencelog-delete-previous').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(0, key + 1);
});
this.html.find('.encaisser-direct').click(async event => {
this.actor.encaisser();
})
this.html.find('.sheet-possession-attack').click(async event => {
const poss = RdDSheetUtility.getItem(event, this.actor)
this.actor.conjurerPossession(poss)
})
this.html.find('.remise-a-neuf').click(async event => {
if (game.user.isGM) {
this.actor.remiseANeuf();
}
this.html.find('.subacteur-coeur-toggle a').click(async event => {
const subActorIdactorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
const coeurNombre = $(event.currentTarget).data('numero-coeur')
RdDCoeur.toggleSubActeurCoeur(this.actor.id, subActorIdactorId, coeurNombre)
})
this.html.find('.subacteur-tendre-moment').click(async event => {
const subActorId = RdDSheetUtility.getEventItemData(event, 'subactor-id')
RdDCoeur.startSubActeurTendreMoment(this.actor.id, subActorId)
})
this.html.find('.subacteur-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const subActorId = li.data("subactor-id");
this.deleteSubActeur(subActorId, li);
})
this.html.find("input.derivee-value[name='system.compteurs.stress.value']").change(async event => {
this.actor.updateCompteurValue("stress", parseInt(event.target.value));
});
this.html.find('.creer-tache').click(async event => {
this.createEmptyTache();
});
this.html.find('.creer-une-oeuvre').click(async event => {
this.selectTypeOeuvreToCreate();
this.html.find("input.derivee-value[name='system.compteurs.experience.value']").change(async event => {
this.actor.updateCompteurValue("experience", parseInt(event.target.value));
});
// Blessure control
this.html.find('.blessure-control').click(async event => {
const tr = this.html.find(event.currentTarget).parents(".item");
let btype = tr.data("blessure-type");
let index = tr.data('blessure-index');
let active = this.html.find(event.currentTarget).data('blessure-active');
//console.log(btype, index, active);
await this.actor.manageBlessureFromSheet(btype, index, active);
});
this.html.find('.creer-tache').click(async event => this.createEmptyTache());
this.html.find('.creer-une-oeuvre').click(async event => this.selectTypeOeuvreToCreate());
this.html.find('.creer-tache-blessure-legere').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 2));
this.html.find('.creer-tache-blessure-grave').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 4));
this.html.find('.creer-tache-blessure-critique').click(async event => RdDItemBlessure.createTacheSoinBlessure(this.actor, 6));
// Blessure data
this.html.find('.blessure-soins').change(async event => {
const tr = this.html.find(event.currentTarget).parents(".item");
let btype = tr.data('blessure-type');
let index = tr.data('blessure-index');
let psoins = tr.find('.blessure-premiers_soins').val();
let pcomplets = tr.find('.blessure-soins_complets').val();
let jours = tr.find('.blessure-jours').val();
let loc = tr.find('.blessure-localisation').val();
let psdone = tr.find('.blessure-psdone:checked').val();
let scdone = tr.find('.blessure-scdone:checked').val();
console.log(btype, index, psoins, pcomplets, jours, loc, psdone, scdone);
await this.actor.setDataBlessureFromSheet(btype, index, psoins, pcomplets, jours, loc, psdone, scdone);
this.html.find('.blessure-premierssoins-done').change(async event => {
const blessure = this.getBlessure(event);
await blessure?.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
});
this.html.find('.blessure-soinscomplets-done').change(async event => {
const blessure = this.getBlessure(event);
await blessure?.setSoinsBlessure({ soinscomplets: { done: event.currentTarget.checked } })
});
this.html.find('.blessure-premierssoins-bonus').change(async event => {
const blessure = this.getBlessure(event);
await blessure?.setSoinsBlessure({ premierssoins: { bonus: Number(event.currentTarget.value) } })
});
this.html.find('.blessure-soinscomplets-bonus').change(async event => {
const blessure = this.getBlessure(event);
await blessure?.setSoinsBlessure({ soinscomplets: { bonus: Number(event.currentTarget.value) } })
});
// Equip Inventory Item
this.html.find('.item-equip').click(async event => {
this.actor.equiperObjet(RdDSheetUtility.getItemId(event));
});
this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event)))
this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
// Roll Carac
this.html.find('.carac-label a').click(async event => {
let caracName = event.currentTarget.attributes.name.value;
this.actor.rollCarac(caracName.toLowerCase());
});
this.html.find('.chance-appel').click(async event => this.actor.rollAppelChance())
this.html.find('.chance-actuelle').click(async event => {
this.actor.rollCarac('chance-actuelle');
});
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
this.html.find('.meditation-label a').click(async event => this.actor.rollMeditation(RdDSheetUtility.getItemId(event)))
this.html.find('.chance-appel').click(async event => {
this.actor.rollAppelChance();
});
this.html.find('.chant-label a').click(async event => this.actor.rollChant(RdDSheetUtility.getItemId(event)))
this.html.find('.danse-label a').click(async event => this.actor.rollDanse(RdDSheetUtility.getItemId(event)))
this.html.find('.musique-label a').click(async event => this.actor.rollMusique(RdDSheetUtility.getItemId(event)))
this.html.find('.oeuvre-label a').click(async event => this.actor.rollOeuvre(RdDSheetUtility.getItemId(event)))
this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
this.html.find('[name="jet-astrologie"]').click(async event => {
this.actor.astrologieNombresAstraux();
});
// Roll Skill
this.html.find('a.competence-label').click(async event => {
this.actor.rollCompetence(RdDSheetUtility.getItemId(event));
});
this.html.find('.tache-label a').click(async event => {
this.actor.rollTache(RdDSheetUtility.getItemId(event));
});
this.html.find('.meditation-label a').click(async event => {
this.actor.rollMeditation(RdDSheetUtility.getItemId(event));
});
this.html.find('.chant-label a').click(async event => {
this.actor.rollChant(RdDSheetUtility.getItemId(event));
});
this.html.find('.danse-label a').click(async event => {
this.actor.rollDanse(RdDSheetUtility.getItemId(event));
});
this.html.find('.musique-label a').click(async event => {
this.actor.rollMusique(RdDSheetUtility.getItemId(event));
});
this.html.find('.oeuvre-label a').click(async event => {
this.actor.rollOeuvre(RdDSheetUtility.getItemId(event));
});
this.html.find('.jeu-label a').click(async event => {
this.actor.rollJeu(RdDSheetUtility.getItemId(event));
});
this.html.find('.recettecuisine-label a').click(async event => {
this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event));
});
this.html.find('.subacteur-label a').click(async event => {
let actorId = RdDSheetUtility.getEventItemData(event, 'actor-id');
let actor = game.actors.get(actorId);
if (actor) {
actor.sheet.render(true);
}
});
// Boutons spéciaux MJs
this.html.find('.forcer-tmr-aleatoire').click(async event => {
this.actor.reinsertionAleatoire("Action MJ");
});
this.html.find('.afficher-tmr').click(async event => {
this.actor.changeTMRVisible();
});
if (game.user.isGM) {
// experience log
this.html.find('.experiencelog-delete').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(key, 1);
});
this.html.find('.experiencelog-delete-previous').click(async event => {
const li = this.html.find(event.currentTarget)?.parents(".experiencelog");
const key = Number(li.data("key") ?? -1);
await this.actor.deleteExperienceLog(0, key + 1);
});
// Boutons spéciaux MJs
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
}
// Points de reve actuel
this.html.find('.ptreve-actuel a').click(async event => {
this.actor.rollCarac('reve-actuel');
});
this.html.find('.ptreve-actuel a').click(async event => this.actor.rollCarac('reve-actuel', true))
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
this.html.find('.arme-label a').click(async event => this.actor.rollArme(duplicate(this._getEventArmeCombat(event))))
// Roll Weapon1
this.html.find('.arme-label a').click(async event => {
let arme = this._getEventArmeCombat(event);
this.actor.rollArme(duplicate(arme));
});
// Initiative pour l'arme
this.html.find('.arme-initiative a').click(async event => {
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id);
@ -267,177 +233,64 @@ export class RdDActorSheet extends RdDBaseActorSheet {
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
}
});
// Display TMR, visualisation
this.html.find('.visu-tmr').click(async event => {
this.actor.displayTMR("visu");
});
// Display TMR
// Display TMR, normal
this.html.find('.monte-tmr').click(async event => {
this.actor.displayTMR("normal");
});
this.html.find('.monte-tmr').click(async event => this.actor.displayTMR("normal"))
this.html.find('.monte-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
// Display TMR, fast
this.html.find('.monte-tmr-rapide').click(async event => {
this.actor.displayTMR("rapide");
});
this.html.find('.repos').click(async event => await this.actor.repos())
this.html.find('.repos').click(async event => {
await this.actor.repos();
});
this.html.find('.delete-active-effect').click(async event => {
if (game.user.isGM) {
let effect = this.html.find(event.currentTarget).parents(".active-effect").data('effect');
this.actor.removeEffect(effect);
}
});
this.html.find('.enlever-tous-effets').click(async event => {
if (game.user.isGM) {
await this.actor.removeEffects();
}
});
this.html.find('.carac-xp-augmenter').click(async event => {
let caracName = event.currentTarget.name.replace("augmenter.", "");
this.actor.updateCaracXPAuto(caracName);
});
this.html.find('.competence-xp-augmenter').click(async event => {
this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event));
});
this.html.find('.competence-stress-augmenter').click(async event => {
this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event));
});
this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
this.html.find('.competence-stress-augmenter').click(async event => this.actor.updateCompetenceStress(RdDSheetUtility.getItemId(event)))
if (this.options.vueDetaillee) {
// On carac change
this.html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
this.actor.updateCarac(caracName, parseInt(event.target.value));
});
this.html.find('input.carac-xp').change(async event => {
let caracName = event.currentTarget.name.replace(".xp", "").replace("system.carac.", "");
this.actor.updateCaracXP(caracName, parseInt(event.target.value));
});
// On competence change
this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value));
});
// On competence xp change
this.html.find('input.competence-xp').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
});
// On competence xp change
this.html.find('input.competence-xp-sort').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
});
this.html.find('.toggle-archetype').click(async event => {
this.options.vueArchetype = !this.options.vueArchetype;
this.render(true);
});
// On competence archetype change
this.html.find('.competence-archetype').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
});
this.html.find('.nouvelle-incarnation').click(async event => this.actor.nouvelleIncarnation())
}
this.html.find('.show-hide-competences').click(async event => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true);
});
this.html.find('.recherche')
.each((index, field) => {
if (this.options.recherche) {
field.focus();
field.setSelectionRange(this.options.recherche.start, this.options.recherche.end);
}
})
.keyup(async event => {
const nouvelleRecherche = this._optionRecherche(event.currentTarget);
if (this.options.recherche?.text != nouvelleRecherche?.text) {
this.options.recherche = nouvelleRecherche;
if (this.timerRecherche) {
clearTimeout(this.timerRecherche);
}
this.timerRecherche = setTimeout(() => {
this.timerRecherche = undefined;
this.render(true);
}, 500);
}
})
.change(async event =>
this.options.recherche = this._optionRecherche(event.currentTarget)
);
this.html.find('.vue-detaillee').click(async event => {
this.options.vueDetaillee = !this.options.vueDetaillee;
this.render(true);
});
// On pts de reve change
this.html.find('.pointsreve-value').change(async event => {
let reveValue = event.currentTarget.value;
this.actor.update({ "system.reve.reve.value": reveValue });
});
this.html.find('.pointsreve-value').change(async event => this.actor.update({ "system.reve.reve.value": event.currentTarget.value }))
this.html.find('.seuil-reve-value').change(async event => this.actor.setPointsDeSeuil(event.currentTarget.value))
// On seuil de reve change
this.html.find('.seuil-reve-value').change(async event => {
console.log("seuil-reve-value", event.currentTarget)
this.actor.setPointsDeSeuil(event.currentTarget.value);
});
this.html.find('.stress-test').click(async event => this.actor.transformerStress())
this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse'))
this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre'))
this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse'))
this.html.find('.ethylisme-test').click(async event => this.actor.jetEthylisme())
// On stress change
this.html.find('.compteur-edit').change(async event => {
let fieldName = event.currentTarget.attributes.name.value;
this.actor.updateCompteurValue(fieldName, parseInt(event.target.value));
});
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))
this.html.find('.fatigue-plus').click(async event => this.actor.santeIncDec("fatigue", 1))
this.html.find('.fatigue-moins').click(async event => this.actor.santeIncDec("fatigue", -1))
}
this.html.find('.stress-test').click(async event => {
this.actor.transformerStress();
});
this.html.find('.moral-malheureux').click(async event => {
this.actor.jetDeMoral('malheureuse');
});
this.html.find('.moral-neutre').click(async event => {
this.actor.jetDeMoral('neutre');
});
this.html.find('.moral-heureux').click(async event => {
this.actor.jetDeMoral('heureuse');
});
this.html.find('.ethylisme-test').click(async event => {
this.actor.jetEthylisme();
});
this.html.find('.jet-vie').click(async event => {
this.actor.jetVie();
});
this.html.find('.jet-endurance').click(async event => {
this.actor.jetEndurance();
});
this.html.find('.vie-plus').click(async event => {
this.actor.santeIncDec("vie", 1);
});
this.html.find('.vie-moins').click(async event => {
this.actor.santeIncDec("vie", -1);
});
this.html.find('.endurance-plus').click(async event => {
this.actor.santeIncDec("endurance", 1);
});
this.html.find('.endurance-moins').click(async event => {
this.actor.santeIncDec("endurance", -1);
});
this.html.find('.ptreve-actuel-plus').click(async event => {
this.actor.reveActuelIncDec(1);
});
this.html.find('.ptreve-actuel-moins').click(async event => {
this.actor.reveActuelIncDec(-1);
});
this.html.find('.fatigue-plus').click(async event => {
this.actor.santeIncDec("fatigue", 1);
});
this.html.find('.fatigue-moins').click(async event => {
this.actor.santeIncDec("fatigue", -1);
});
getBlessure(event) {
const blessureId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
return this.actor.getItem(blessureId, 'blessure');
}
isCompetenceAffichable(competence) {
@ -451,11 +304,26 @@ export class RdDActorSheet extends RdDBaseActorSheet {
super._onDropActor(event, dragData);
}
openSubActeur(actorId) {
game.actors.get(actorId)?.sheet.render(true)
}
deleteSubActeur(actorId, li) {
if (actorId) {
const subActor = game.actors.get(actorId);
RdDUtility.confirmSubActeurDelete(this, subActor, li, () => {
console.log('Delete : ', subActor.id);
this.actor.deleteSubActeur(subActor.id);
RdDUtility.slideOnDelete(this, li);
});
}
}
/* -------------------------------------------- */
async selectTypeOeuvreToCreate() {
let typeObjets = RdDItem.getTypesOeuvres();
let types = RdDItem.getTypesOeuvres();
let content = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of typeObjets) {
for (let typeName of types) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';
@ -478,17 +346,6 @@ export class RdDActorSheet extends RdDBaseActorSheet {
await this.actor.createItem('tache', 'Nouvelle tache');
}
_optionRecherche(target) {
if (!target.value?.length) {
return undefined;
}
return {
text: target.value,
start: target.selectionStart,
end: target.selectionEnd,
};
}
_getEventArmeCombat(event) {
const li = this.html.find(event.currentTarget)?.parents(".item");
let armeName = li.data("arme-name");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
import { Grammar } from "../grammar.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
/* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(RdDBaseActorSheet.defaultOptions, {
width: 550
});
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.encaisser-direct').click(async event => this.actor.encaisser())
this.html.find('.carac-label a').click(async event => this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes.name.value)));
this.html.find('a.competence-label').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1));
this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1));
if (game.user.isGM) {
this.html.find('.remise-a-neuf').click(async event => this.actor.remiseANeuf())
this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect')));
this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects());
}
}
}

View File

@ -0,0 +1,512 @@
import { ChatUtility } from "../chat-utility.js";
import { DialogValidationEncaissement } from "../dialog-validation-encaissement.js";
import { Grammar } from "../grammar.js";
import { RdDItemCompetence } from "../item-competence.js";
import { Misc } from "../misc.js";
import { RdDEmpoignade } from "../rdd-empoignade.js";
import { RdDResolutionTable } from "../rdd-resolution-table.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
import { RdDRoll } from "../rdd-roll.js";
import { RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { RdDBaseActor } from "./base-actor.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
import { StatusEffects } from "../settings/status-effects.js";
import { TYPES } from "../item.js";
import { Targets } from "../targets.js";
import { RdDPossession } from "../rdd-possession.js";
import { RdDCombat } from "../rdd-combat.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
import { RdDItemArme } from "../item-arme.js";
const POSSESSION_SANS_DRACONIC = {
img: 'systems/foundryvtt-reve-de-dragon/icons/entites/possession.webp',
name: 'Sans draconic',
system: {
niveau: 0,
defaut_carac: "reve-actuel",
}
};
/**
* Classe de base pour les acteurs disposant de rêve (donc, pas des objets)
* - Entités de rêve
* - Créatures de "sang": créatures et humanoides
*/
export class RdDBaseActorReve extends RdDBaseActor {
getCaracChanceActuelle() {
return {
label: 'Chance actuelle',
value: this.getChanceActuel(),
type: "number"
};
}
getCaracReveActuel() {
return {
label: 'Rêve actuel',
value: this.getReveActuel(),
type: "number"
};
}
getReveActuel() { return this.getReve() }
getChanceActuel() { return this.getChance() }
getReve() { return Number(this.system.carac.reve?.value ?? 0) }
getForce() { return this.getReve() }
getTaille() { return Number(this.system.carac.taille?.value ?? 0) }
getAgilite() { return this.getForce() }
getChance() { return this.getReve() }
getMoralTotal() { return 0 }
getBonusDegat() { return Number(this.system.attributs?.plusdom?.value ?? 0) }
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
/* -------------------------------------------- */
getEncombrementMax() { return 0 }
isSurenc() { return false }
computeMalusSurEncombrement() { return 0 }
ajustementAstrologique() { return 0 }
getMalusArmure() { return 0 }
getEnduranceActuelle() {
return Number(this.system.sante?.endurance?.value ?? 0);
}
async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } }
isDead() { return false }
blessuresASoigner() { return [] }
getEtatGeneral(options = { ethylisme: false }) { return 0 }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
async santeIncDec(name, inc, isCritique = false) { }
async finDeRound(options = { terminer: false }) {
await this.$finDeRoundSuppressionEffetsTermines(options);
await this.finDeRoundBlessures();
await this.$finDeRoundSupprimerObsoletes();
await this.$finDeRoundEmpoignade();
}
async $finDeRoundSuppressionEffetsTermines(options) {
for (let effect of this.getEffects()) {
if (effect.duration.type !== 'none' && (effect.duration.remaining <= 0 || options.terminer)) {
await effect.delete();
ChatMessage.create({ content: `${this.name} n'est plus ${Misc.lowerFirst(game.i18n.localize(effect.system.label))} !` });
}
}
}
async finDeRoundBlessures() {
}
async $finDeRoundSupprimerObsoletes() {
const obsoletes = []
.concat(this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
.concat(this.itemTypes[TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
.map(it => it.id);
await this.deleteEmbeddedDocuments('Item', obsoletes);
}
async $finDeRoundEmpoignade() {
const immobilisations = this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
game.actors.get(emp.system.empoigneid),
emp
))
}
async setSonne(sonne = true) { }
/* -------------------------------------------- */
getCompetence(idOrName, options = {}) {
if (idOrName instanceof Item) {
return idOrName.isCompetence() ? idOrName : undefined
}
return RdDItemCompetence.findCompetence(this.items, idOrName, options)
}
getCompetences(name) {
return RdDItemCompetence.findCompetences(this.items, name)
}
getCompetenceCorpsACorps(options = {}) {
return this.getCompetence("Corps à corps", options)
}
getCompetencesEsquive() {
return this.getCompetences("esquive")
}
getArmeParade(armeParadeId) {
const item = armeParadeId ? this.getEmbeddedDocument('Item', armeParadeId) : undefined;
return RdDItemArme.getArme(item);
}
getDraconicOuPossession() {
return POSSESSION_SANS_DRACONIC
}
getPossession(possessionId) {
return this.itemTypes[TYPES.possession].find(it => it.system.possessionid == possessionId);
}
getPossessions() {
return this.itemTypes[TYPES.possession];
}
getEmpoignades() {
return this.itemTypes[TYPES.empoignade];
}
/* -------------------------------------------- */
async updateCreatureCompetence(idOrName, fieldName, value) {
let competence = this.getCompetence(idOrName);
if (competence) {
function getFieldPath(fieldName) {
switch (fieldName) {
case "niveau": return 'system.niveau';
case "dommages": return 'system.dommages';
case "carac_value": return 'system.carac_value';
}
return undefined
}
const path = getFieldPath(fieldName);
if (path) {
await competence.update({ [path]: value });
}
}
}
/* -------------------------------------------- */
isEffectAllowed(effectId) { return true }
getEffects(filter = e => true) {
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
}
getEffect(effectId) {
return this.getEmbeddedCollection("ActiveEffect").find(it => it.statuses?.has(effectId));
}
async setEffect(effectId, status) {
if (this.isEffectAllowed(effectId)) {
const effect = this.getEffect(effectId);
if (!status && effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]);
}
if (status && !effect) {
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(effectId)]);
}
}
}
async removeEffect(id) {
const effect = this.getEmbeddedCollection("ActiveEffect").find(it => it.id == id);
if (effect) {
await this.deleteEmbeddedDocuments('ActiveEffect', [id]);
}
}
async removeEffects(filter = e => true) {
if (game.user.isGM) {
const ids = this.getEffects(filter).map(it => it.id);
await this.deleteEmbeddedDocuments('ActiveEffect', ids);
}
}
/* -------------------------------------------- */
getSurprise(isCombat = undefined) {
let niveauSurprise = this.getEffects()
.map(effect => StatusEffects.valeurSurprise(effect, isCombat))
.reduce(Misc.sum(), 0);
if (niveauSurprise > 1) {
return 'totale';
}
if (niveauSurprise == 1) {
return 'demi';
}
return '';
}
/* -------------------------------------------- */
async computeEtatGeneral() {
// Par défaut, on ne calcule pas d'état général, seuls les personnages/créatures sont affectés
this.system.compteurs.etat.value = 0;
}
/* -------------------------------------------- */
async openRollDialog({ name, label, template, rollData, callbackAction }) {
const dialog = await RdDRoll.create(this, rollData,
{ html: template, close: async html => await this._onCloseRollDialog(html) },
{
name: name,
label: label,
callbacks: [
this.createCallbackExperience(),
this.createCallbackAppelAuMoral(),
{ action: callbackAction }
]
});
dialog.render(true);
return dialog
}
createEmptyCallback() {
return {
condition: r => false,
action: r => { }
};
}
createCallbackExperience() { return this.createEmptyCallback(); }
createCallbackAppelAuMoral() { return this.createEmptyCallback(); }
async _onCloseRollDialog(html) { }
/* -------------------------------------------- */
async roll() {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const carac = this.getCarac()
const selectedCaracName = ['apparence', 'perception', 'force', 'reve'].find(it => carac[it] != undefined)
await this.openRollDialog({
name: `jet-${this.id}`,
label: `Jet de ${this.name}`,
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll.html',
rollData: {
carac: carac,
selectedCarac: carac[selectedCaracName],
selectedCaracName: selectedCaracName,
competences: this.itemTypes['competence']
},
callbackAction: r => this.$onRollCaracResult(r)
});
}
getCarac() {
// TODO: le niveau d'une entité de cauchemar devrait être exclu...
const carac = mergeObject(duplicate(this.system.carac),
{
'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle()
});
return carac;
}
/* -------------------------------------------- */
async rollCarac(caracName, jetResistance = undefined) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
let selectedCarac = this.getCaracByName(caracName)
await this.openRollDialog({
name: 'jet-' + caracName,
label: 'Jet ' + Grammar.apostrophe('de', selectedCarac.label),
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html',
rollData: {
selectedCarac: selectedCarac,
competences: this.itemTypes['competence'],
jetResistance: jetResistance ? caracName : undefined
},
callbackAction: r => this.$onRollCaracResult(r)
});
}
/* -------------------------------------------- */
async $onRollCaracResult(rollData) {
// Final chat message
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-general.html');
}
/* -------------------------------------------- */
async rollCompetence(idOrName, options = { tryTarget: true }) {
RdDEmpoignade.checkEmpoignadeEnCours(this)
const competence = this.getCompetence(idOrName);
let rollData = { carac: this.system.carac, competence: competence }
if (competence.type == TYPES.competencecreature) {
const arme = RdDItemCompetenceCreature.armeCreature(competence)
if (arme && options.tryTarget && Targets.hasTargets()) {
Targets.selectOneToken(target => {
if (arme.action == "possession") {
RdDPossession.onAttaquePossession(target, this, competence)
}
else {
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
}
});
return;
}
// Transformer la competence de créature
RdDItemCompetenceCreature.setRollDataCreature(rollData)
}
await this.openRollDialog({
name: 'jet-competence',
label: 'Jet ' + Grammar.apostrophe('de', competence.name),
template: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-competence.html',
rollData: rollData,
callbackAction: r => this.$onRollCompetence(r, options)
});
}
async $onRollCompetence(rollData, options) {
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-competence.html')
if (options?.onRollAutomate) {
options.onRollAutomate(rollData);
}
}
/** --------------------------------------------
* @param {*} arme item d'arme/compétence de créature
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
* @returns
*/
rollArme(arme, categorieArme = "competence") {
let compToUse = this.$getCompetenceArme(arme, categorieArme)
if (!RdDItemArme.isArmeUtilisable(arme)) {
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
return
}
if (!Targets.hasTargets()) {
RdDConfirm.confirmer({
settingConfirmer: "confirmer-combat-sans-cible",
content: `<p>Voulez vous faire un jet de ${compToUse} sans choisir de cible valide?
<br>Tous les jets de combats devront être gérés à la main
</p>`,
title: 'Ne pas utiliser les automatisation de combat',
buttonLabel: "Pas d'automatisation",
onAction: async () => {
this.rollCompetence(compToUse, { tryTarget: false })
}
});
return
}
Targets.selectOneToken(target => {
if (Targets.isTargetEntite(target)) {
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
return
}
const competence = this.getCompetence(compToUse)
if (competence.isCompetencePossession()) {
return RdDPossession.onAttaquePossession(target, this, competence);
}
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme);
})
}
$getCompetenceArme(arme, competenceName) {
switch (arme.type) {
case TYPES.competencecreature:
return arme.name
case TYPES.arme:
switch (competenceName) {
case 'competence': return arme.system.competence;
case 'unemain': return RdDItemArme.competence1Mains(arme);
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
case 'tir': return arme.system.tir;
case 'lancer': return arme.system.lancer;
}
}
return undefined
}
verifierForceMin(item) {
}
/* -------------------------------------------- */
async resetItemUse() { }
async incDecItemUse(itemId, inc = 1) { }
getItemUse(itemId) { return 0; }
/* -------------------------------------------- */
async encaisser() { await RdDEncaisser.encaisser(this) }
async encaisserDommages(rollData, attacker = undefined, show = undefined) {
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
return;
}
const attackerId = attacker?.id;
if (ReglesOptionnelles.isUsing('validation-encaissement-gr') && !game.user.isGM) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'encaisserDommages',
args: [rollData, show, attackerId]
});
return;
}
const armure = await this.computeArmure(rollData);
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
jet => this.$onEncaissement(jet, show, attacker));
}
else {
const jet = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE });
await this.$onEncaissement(jet, show, attacker);
}
}
async $onEncaissement(jet, show, attacker) {
await this.onAppliquerJetEncaissement(jet, attacker);
await this.$afficherEncaissement(jet, show);
}
async onAppliquerJetEncaissement(encaissement, attacker) { }
async $afficherEncaissement(encaissement, show) {
mergeObject(encaissement, {
alias: this.name,
hasPlayerOwner: this.hasPlayerOwner,
show: show ?? {}
});
await ChatUtility.createChatWithRollMode(this.name, {
roll: encaissement.roll,
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
});
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
encaissement = duplicate(encaissement);
encaissement.isGM = true;
ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients("GM"),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
});
}
}
/* -------------------------------------------- */
async accorder(entite, when = 'avant-encaissement') {
if (when != game.settings.get(SYSTEM_RDD, "accorder-entite-cauchemar")
|| entite == undefined
|| !entite.isEntite([ENTITE_INCARNE])
|| entite.isEntiteAccordee(this)) {
return true;
}
const rolled = await RdDResolutionTable.roll(this.getReveActuel(), - Number(entite.system.carac.niveau.value));
const rollData = {
alias: this.name,
rolled: rolled,
entite: entite.name,
selectedCarac: this.system.carac.reve
};
if (rolled.isSuccess) {
await entite.setEntiteReveAccordee(this);
}
await RdDResolutionTable.displayRollData(rollData, this, 'chat-resultat-accorder-cauchemar.html');
if (rolled.isPart) {
await this.appliquerAjoutExperience(rollData, true);
}
return rolled.isSuccess;
}
isEntiteAccordee(attacker) { return true }
async setEntiteReveAccordee(attacker) {
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve");
}
}

View File

@ -0,0 +1,41 @@
import { ChatUtility } from "../chat-utility.js";
import { RdDItemBlessure } from "../item/blessure.js";
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
/* -------------------------------------------- */
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDBaseActorSangSheet extends RdDBaseActorReveSheet {
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.creer-blessure-legere').click(async event => RdDItemBlessure.createBlessure(this.actor, 2));
this.html.find('.creer-blessure-grave').click(async event => RdDItemBlessure.createBlessure(this.actor, 4));
this.html.find('.creer-blessure-critique').click(async event => RdDItemBlessure.createBlessure(this.actor, 6));
this.html.find('.jet-vie').click(async event => this.actor.jetDeVie())
this.html.find('.jet-endurance').click(async event => await this.jetEndurance())
this.html.find('.vie-plus').click(async event => this.actor.santeIncDec("vie", 1))
this.html.find('.vie-moins').click(async event => this.actor.santeIncDec("vie", -1))
}
async jetEndurance() {
const endurance = this.actor.getEnduranceActuelle()
const result = await this.actor.jetEndurance(endurance);
ChatMessage.create({
content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance}
<br>${this.actor.name} a ${result.sonne ? 'échoué' : 'réussi'} son Jet d'Endurance ${result.sonne ? 'et devient Sonné' : ''}`,
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.actor.name)
});
}
}

View File

@ -0,0 +1,280 @@
import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
import { STATUSES } from "../settings/status-effects.js";
import { TYPES } from "../item.js";
import { RdDBaseActorReve } from "./base-actor-reve.js";
import { RdDDice } from "../rdd-dice.js";
import { RdDItemBlessure } from "../item/blessure.js";
/**
* Classe de base pour les acteurs qui peuvent subir des blessures
* - créatures
* - humanoides
*/
export class RdDBaseActorSang extends RdDBaseActorReve {
getForce() { return Number(this.system.carac.force?.value ?? 0) }
getBonusDegat() { return Number(this.system.attributs?.plusdom?.value ?? 0) }
getProtectionNaturelle() { return Number(this.system.attributs?.protection?.value ?? 0) }
getSConst() { return 0 }
getEnduranceMax() { return Math.max(1, Math.min(this.system.sante.endurance.max, MAX_ENDURANCE_FATIGUE)) }
getFatigueActuelle() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return Math.max(0, Math.min(this.getFatigueMax(), this.system.sante.fatigue?.value ?? 0));
}
return 0;
}
getFatigueRestante() { return this.getFatigueMax() - this.getFatigueActuelle() }
getFatigueMin() { return this.system.sante.endurance.max - this.system.sante.endurance.value }
getFatigueMax() { return this.getEnduranceMax() * 2 }
malusFatigue() {
if (ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return RdDUtility.calculMalusFatigue(this.getFatigueActuelle(), this.getEnduranceMax())
}
return 0;
}
/* -------------------------------------------- */
getEncombrementMax() { return Number(this.system.attributs?.encombrement?.value ?? 0) }
isSurenc() { return this.computeMalusSurEncombrement() < 0 }
computeMalusSurEncombrement() {
return Math.min(0, Math.floor(this.getEncombrementMax() - this.encTotal));
}
isDead() { return this.system.sante.vie.value < -this.getSConst() }
nbBlessuresLegeres() { return this.itemTypes[TYPES.blessure].filter(it => it.isLegere()).length }
nbBlessuresGraves() { return this.itemTypes[TYPES.blessure].filter(it => it.isGrave()).length }
nbBlessuresCritiques() { return this.itemTypes[TYPES.blessure].filter(it => it.isCritique()).length }
/* -------------------------------------------- */
computeResumeBlessure() {
const nbLegeres = this.nbBlessuresLegeres()
const nbGraves = this.nbBlessuresGraves()
const nbCritiques = this.nbBlessuresCritiques()
if (nbLegeres + nbGraves + nbCritiques == 0) {
return "Aucune blessure";
}
let resume = "Blessures:";
if (nbLegeres > 0) {
resume += " " + nbLegeres + " légère" + (nbLegeres > 1 ? "s" : "");
}
if (nbGraves > 0) {
if (nbLegeres > 0)
resume += ",";
resume += " " + nbGraves + " grave" + (nbGraves > 1 ? "s" : "");
}
if (nbCritiques > 0) {
if (nbGraves > 0 || nbLegeres > 0)
resume += ",";
resume += " une CRITIQUE !";
}
return resume;
}
blessuresASoigner() { return [] }
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
async remiseANeuf() { }
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { }
/* -------------------------------------------- */
async onAppliquerJetEncaissement(encaissement, attacker) {
const santeOrig = duplicate(this.system.sante);
const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
sonne: perteEndurance.sonne,
jetEndurance: perteEndurance.jetEndurance,
endurance: perteEndurance.perte,
vie: santeOrig.vie.value - perteVie.newValue,
blessure: blessure
});
}
/* -------------------------------------------- */
async santeIncDec(name, inc, isCritique = false) {
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
return;
}
const sante = duplicate(this.system.sante)
let compteur = sante[name];
if (!compteur) {
return;
}
let result = {
sonne: false,
};
let minValue = name == "vie" ? -this.getSConst() - 1 : 0;
result.newValue = Math.max(minValue, Math.min(compteur.value + inc, compteur.max));
//console.log("New value ", inc, minValue, result.newValue);
let fatigue = 0;
if (name == "endurance") {
if (result.newValue == 0 && inc < 0 && !isCritique) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
sante.vie.value--;
result.perteVie = true;
}
result.newValue = Math.max(0, result.newValue);
if (inc > 0) { // le max d'endurance s'applique seulement à la récupération
result.newValue = Math.min(result.newValue, this._computeEnduranceMax())
}
const perte = compteur.value - result.newValue;
result.perte = perte;
if (perte > 1) {
// Peut-être sonné si 2 points d'endurance perdus d'un coup
mergeObject(result, await this.jetEndurance(result.newValue));
} else if (inc > 0) {
await this.setSonne(false);
}
if (sante.fatigue && inc < 0) { // Each endurance lost -> fatigue lost
fatigue = perte;
}
}
compteur.value = result.newValue;
// If endurance lost, then the same amount of fatigue cannot be recovered
if (ReglesOptionnelles.isUsing("appliquer-fatigue") && sante.fatigue && fatigue > 0) {
sante.fatigue.value = Math.max(sante.fatigue.value + fatigue, this.getFatigueMin());
}
await this.update({ "system.sante": sante })
if (this.isDead()) {
await this.setEffect(STATUSES.StatusComma, true);
}
return result
}
/* -------------------------------------------- */
_computeEnduranceMax() {
const diffVie = this.system.sante.vie.max - this.system.sante.vie.value;
const maxEndVie = this.system.sante.endurance.max - (diffVie * 2);
const nbGraves = this.countBlessures(it => it.isGrave()) > 0
const nbCritiques = this.countBlessures(it => it.isCritique()) > 0
const maxEndGraves = Math.floor(this.system.sante.endurance.max / (2 * nbGraves));
const maxEndCritiques = nbCritiques > 0 ? 1 : this.system.sante.endurance.max;
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
}
/* -------------------------------------------- */
async ajouterBlessure(encaissement, attacker = undefined) {
if (encaissement.gravite < 0) return;
if (encaissement.gravite > 0) {
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
// Aggravation
encaissement.gravite += 2
if (encaissement.gravite > 2) {
encaissement.vie += 2;
}
}
}
const endActuelle = this.getEnduranceActuelle();
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg.loc.label, attacker);
if (blessure.isCritique()) {
encaissement.endurance = endActuelle;
}
if (blessure.isMort()) {
this.setEffect(STATUSES.StatusComma, true);
encaissement.mort = true;
ChatMessage.create({
content: `<img class="chat-icon" src="icons/svg/skull.svg" data-tooltip="charge" />
<strong>${this.name} vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix !</strong>`
});
}
return blessure;
}
async supprimerBlessures(filterToDelete) {
const toDelete = this.filterItems(filterToDelete, TYPES.blessure)
.map(it => it.id);
await this.deleteEmbeddedDocuments('Item', toDelete);
}
countBlessures(filter = it => !it.isContusion()) {
return this.filterItems(filter, 'blessure').length
}
/* -------------------------------------------- */
async jetDeVie() {
if (this.isDead()) {
ChatMessage.create({ content: `Jet de Vie: ${this.name} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`, whisper: ChatMessage.getWhisperRecipients(this.name) });
return
}
const jetDeVie = await RdDDice.roll("1d20");
const sConst = this.getSConst();
const vie = this.system.sante.vie.value;
const isCritique = this.nbBlessuresCritiques() > 0;
const isGrave = this.nbBlessuresGraves();
const isEchecTotal = jetDeVie.total == 20;
const isSuccess = jetDeVie.total == 1 || jetDeVie.total <= vie;
const perte = isSuccess ? 0 : 1 + (isEchecTotal ? vie + sConst : 0)
const prochainJet = (jetDeVie.total == 1 && vie > 0 ? 20 : 1) * (isCritique ? 1 : isGrave > 0 ? sConst : 0)
let msgText = `Jet de Vie: <strong>${jetDeVie.total} / ${vie}</strong>`
if (isSuccess) {
msgText += "<br>Réussi, pas de perte de point de vie."
} else {
msgText += `<br>Echoué, perte ${perte} point de vie`;
await this.santeIncDec("vie", -perte);
}
if (this.isDead()) {
msgText += `<br><strong>${this.name} est mort !!!!</strong>`;
}
else if (prochainJet > 0) {
msgText += `<br>Prochain jet de vie dans ${prochainJet} ${isCritique ? 'round' : 'minute'}${prochainJet > 1 ? 's' : ''} ${isCritique ? '(état critique)' : '(état grave)'}`
}
ChatMessage.create({ content: msgText, whisper: ChatMessage.getWhisperRecipients(this.name) });
}
/* -------------------------------------------- */
async jetEndurance(resteEndurance = undefined) {
const jetEndurance = (await RdDDice.roll("1d20")).total;
const sonne = jetEndurance == 20 || jetEndurance > (resteEndurance ?? this.system.sante.endurance.value)
if (sonne) {
await this.setSonne();
}
return { jetEndurance, sonne }
}
async finDeRoundBlessures() {
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
if (nbGraves > 0) {
// Gestion blessure graves : -1 pt endurance par blessure grave
await this.santeIncDec("endurance", -nbGraves);
}
}
async setSonne(sonne = true) {
if (!game.combat && sonne) {
ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`);
return;
}
await this.setEffect(STATUSES.StatusStunned, sonne);
}
getSonne() {
return this.getEffect(STATUSES.StatusStunned);
}
/* -------------------------------------------- */
async computeEtatGeneral() { this.system.compteurs.etat.value = this.malusVie() + this.malusFatigue() + this.malusEthylisme() }
getEtatGeneral(options = { ethylisme: false }) { return this.system.compteurs.etat.value }
malusVie() { return Math.min(this.system.sante.vie.value - this.system.sante.vie.max, 0) }
malusEthylisme() { return 0 }
}

View File

@ -3,7 +3,8 @@ import { Misc } from "../misc.js";
import { DialogSplitItem } from "../dialog-split-item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { Monnaie } from "../item-monnaie.js";
import { RdDItem } from "../item.js";
import { RdDItem, TYPES } from "../item.js";
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
/* -------------------------------------------- */
/**
@ -14,14 +15,10 @@ export class RdDBaseActorSheet extends ActorSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(super.defaultOptions, {
return mergeObject(ActorSheet.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
width: 550,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
showCompNiveauBase: false,
vueDetaillee: false
});
}
@ -30,53 +27,57 @@ export class RdDBaseActorSheet extends ActorSheet {
async getData() {
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
this.actor.recompute();
const userRightLevel = this.actor.getUserLevel(game.user)
const options = duplicate(this.options);
mergeObject(options, {
isGM: game.user.isGM,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
isLimited: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.LIMITED,
isObserver: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER,
isOwner: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER,
owner: this.actor.isOwner,
});
this.actor.computeEtatGeneral();
let formData = {
title: this.title,
id: this.actor.id,
type: this.actor.type,
img: this.actor.img,
name: this.actor.name,
system: foundry.utils.deepClone(this.actor.system),
system: this.actor.system,
description: await TextEditor.enrichHTML(this.actor.system.description, { async: true }),
notesmj: await TextEditor.enrichHTML(this.actor.system.notesmj, { async: true }),
options: options,
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable)
}
this.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
formData.calc = {
fortune: this.toSolsDeniers(this.actor.getFortune()),
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
encTotal: await this.actor.computeEncTotal(),
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
this._appliquerRechercheObjets(formData.conteneurs, formData.inventaires);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.competences.filter(it => it.type == TYPES.competencecreature)
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
return formData;
}
toSolsDeniers(fortune) {
return {
sols: Math.floor(fortune),
deniers: Math.round(100 * (fortune - Math.floor(fortune)))
};
_appliquerRechercheObjets(conteneurs, inventaires) {
if (this.options.recherche?.text) {
const recherche = this.options.recherche;
const allVisible = inventaires.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id);
let addVisible = conteneurs.filter(it => it.isNomTypeLike(recherche.text)).map(it => it.id)
do {
allVisible.push(...addVisible)
const parentsIds = conteneurs.filter(it => it.system.contenu.find(id => allVisible.includes(id))).map(it => it.id)
addVisible = parentsIds.filter(id => !allVisible.includes(id))
}
while (addVisible.length > 0)
inventaires.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
conteneurs.forEach(it => it.system.isHidden = !allVisible.includes(it.id))
}
else {
inventaires.forEach(it => it.system.isHidden = false)
conteneurs.forEach(it => it.system.isHidden = false)
}
}
/* -------------------------------------------- */
filterItemsPerTypeForSheet(formData, itemTypes) {
static filterItemsPerTypeForSheet(formData, itemTypes) {
formData.blessures = Misc.arrayOrEmpty(itemTypes['blessure']);
formData.recettescuisine = Misc.arrayOrEmpty(itemTypes['recettecuisine']);
formData.recettesAlchimiques = Misc.arrayOrEmpty(itemTypes['recettealchimique']);
formData.maladies = Misc.arrayOrEmpty(itemTypes['maladie']);
@ -110,14 +111,16 @@ export class RdDBaseActorSheet extends ActorSheet {
formData.munitions = Misc.arrayOrEmpty(itemTypes['munition']);
formData.livres = Misc.arrayOrEmpty(itemTypes['livre']);
formData.potions = Misc.arrayOrEmpty(itemTypes['potion']);
formData.plantes = Misc.arrayOrEmpty(itemTypes['plante']);
formData.ingredients = Misc.arrayOrEmpty(itemTypes['ingredient']);
formData.faunes = Misc.arrayOrEmpty(itemTypes['faune']);
formData.herbes = Misc.arrayOrEmpty(itemTypes['herbe']);
formData.nourritureboissons = Misc.arrayOrEmpty(itemTypes['nourritureboisson']);
formData.gemmes = Misc.arrayOrEmpty(itemTypes['gemme']);
formData.monnaie = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.monnaies = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
formData.objets = Misc.arrayOrEmpty(itemTypes['objet'])
formData.objets = RdDItem.getItemTypesInventaire('all')
formData.inventaires = RdDItem.getItemTypesInventaire('all')
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
.reduce((a, b) => a.concat(b), [])
.sort(Misc.ascending(it => it.name));
@ -132,17 +135,33 @@ export class RdDBaseActorSheet extends ActorSheet {
RdDUtility.toggleAfficheContenu(this.getItemId(event));
this.render(true);
});
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true))
this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat());
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
this.html.find('.recherche')
.each((index, field) => {
this._rechercheSelectArea(field);
})
.keyup(async event => this._rechercherKeyup(event))
.change(async event => this._rechercherKeyup(event));
this.html.find('.recherche').prop("disabled", false);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
this.html.find('.item-action').click(async event => {
const item = RdDSheetUtility.getItem(event, this.actor);
item?.actionPrincipale(this.actor, async () => this.render())
});
this.html.find('.item-split').click(async event => {
const item = this.getItem(event);
RdDSheetUtility.splitItem(item, this.actor);
});
this.html.find('.item-quantite-plus').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), 1));
this.html.find('.item-quantite-moins').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), -1));
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event)));
this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event)));
@ -152,12 +171,48 @@ export class RdDBaseActorSheet extends ActorSheet {
this.html.find('.nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs();
});
this.html.find('.monnaie-plus').click(async event => {
this.actor.monnaieIncDec(this.getItemId(event), 1);
});
this.html.find('.monnaie-moins').click(async event => {
this.actor.monnaieIncDec(this.getItemId(event), -1);
this.html.find('.vue-detaillee').click(async event => {
this.options.vueDetaillee = !this.options.vueDetaillee;
this.render(true);
});
if (this.options.vueDetaillee) {
// On carac change
this.html.find('.carac-value').change(async event => {
let caracName = event.currentTarget.name.replace(".value", "").replace("system.carac.", "");
this.actor.updateCarac(caracName, parseInt(event.target.value));
});
// On competence change
this.html.find('.competence-value').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value));
});
}
}
_rechercherKeyup(event) {
const currentTarget = event.currentTarget;
const nouvelleRecherche = this._optionRecherche(currentTarget);
if (this.options.recherche?.text != nouvelleRecherche?.text) {
this.options.recherche = nouvelleRecherche;
if (this.timerRecherche) {
clearTimeout(this.timerRecherche);
}
this.timerRecherche = setTimeout(() => {
this.timerRecherche = undefined;
this.render(true);
}, 500);
}
}
_rechercheSelectArea(field) {
if (this.options.recherche) {
field.focus();
field.setSelectionRange(this.options.recherche.start, this.options.recherche.end);
}
}
getItemId(event) {
@ -168,6 +223,16 @@ export class RdDBaseActorSheet extends ActorSheet {
return RdDSheetUtility.getItem(event, this.actor);
}
_optionRecherche(target) {
if (!target.value?.length) {
return undefined;
}
return {
text: target.value,
start: target.selectionStart,
end: target.selectionEnd,
};
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
@ -193,9 +258,9 @@ export class RdDBaseActorSheet extends ActorSheet {
/* -------------------------------------------- */
async selectObjetTypeToCreate() {
let typeObjets = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
let types = this.getTypesInventaire().sort(Misc.ascending(type => Misc.typeName('Item', type)));
let content = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of typeObjets) {
for (let typeName of types) {
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
}
content += '</select>';

View File

@ -1,19 +1,36 @@
import { ChatUtility } from "../chat-utility.js";
import { SYSTEM_SOCKET_ID } from "../constants.js";
import { Grammar } from "../grammar.js";
import { Monnaie } from "../item-monnaie.js";
import { RdDItem } from "../item.js";
import { TYPES } from "../item.js";
import { Misc } from "../misc.js";
import { RdDAudio } from "../rdd-audio.js";
import { RdDConfirm } from "../rdd-confirm.js";
import { RdDUtility } from "../rdd-utility.js";
import { SystemCompendiums } from "../settings/system-compendiums.js";
import { APP_ASTROLOGIE_REFRESH } from "../sommeil/app-astrologie.js";
export class RdDBaseActor extends Actor {
static _findCaracNode(carac, name) {
return Object.entries(carac)
.filter(it => Grammar.equalsInsensitive(it[1].label, name))
.map(it => it[0])
.find(it => it);
}
static $findCaracByName(carac, name) {
const caracList = Object.entries(carac);
let entry = Misc.findFirstLike(name, caracList, { mapper: it => it[0], description: 'caractéristique' });
if (!entry || entry.length == 0) {
entry = Misc.findFirstLike(name, caracList, { mapper: it => it[1].label, description: 'caractéristique' });
}
return entry && entry.length > 0 ? carac[entry[0]] : undefined;
}
static getDefaultImg(itemType) {
return game.system.rdd.actorClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
}
/* -------------------------------------------- */
static init() {
Hooks.on("preUpdateItem", (item, change, options, id) => RdDBaseActor.getParentActor(item)?.onPreUpdateItem(item, change, options, id));
Hooks.on("createItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onCreateItem(item, options, id));
@ -21,14 +38,16 @@ export class RdDBaseActor extends Actor {
Hooks.on("updateActor", (actor, change, options, actorId) => actor.onUpdateActor(change, options, actorId));
}
static onSocketMessage(sockmsg) {
switch (sockmsg.msg) {
case "msg_remote_actor_call":
return RdDBaseActor.onRemoteActorCall(sockmsg.data, sockmsg.userId);
case "msg_reset_nombre_astral":
console.log("RESET ASTRAL", game.user.character);
game.user.character.resetNombreAstral();
game.user.character.resetNombresAstraux();
game.system.rdd.calendrier.notifyChangeNombresAstraux();
return;
case "msg_refresh_nombre_astral":
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
return;
}
}
@ -47,7 +66,7 @@ export class RdDBaseActor extends Actor {
static onRemoteActorCall(callData, userId) {
if (userId == game.user.id) {
const actor = game.actors.get(callData?.actorId);
const actor = RdDBaseActor.getRealActor(callData?.actorId, callData?.tokenId);
if (Misc.isOwnerPlayerOrUniqueConnectedGM(actor)) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
const args = callData.args;
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
@ -56,17 +75,29 @@ export class RdDBaseActor extends Actor {
}
}
static getRealActor(actorId, tokenId) {
if (tokenId) {
let token = canvas.tokens.get(tokenId)
if (token) {
return token.actor
}
}
return game.actors.get(actorId)
}
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
static getParentActor(document) {
return document?.parent instanceof Actor ? document.parent : undefined
}
/**
* Cet methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
* compétences et monnaies.
*
* @param {Object} actorData template d'acteur auquel ajouter des informations.
* @param {Object} options optionspour customiser la création
*/
*
* @param {Object} actorData template d'acteur auquel ajouter des informations.
* @param {Object} options optionspour customiser la création
*/
static async create(actorData, options) {
// import depuis un compendium
if (actorData instanceof Array) {
@ -102,12 +133,64 @@ export class RdDBaseActor extends Actor {
super(docData, context);
}
isCreatureEntite() { return this.type == 'creature' || this.type == 'entite'; }
isCreature() { return this.type == 'creature'; }
isEntite() { return this.type == 'entite'; }
isPersonnage() { return this.type == 'personnage'; }
isVehicule() { return this.type == 'vehicule'; }
findCaracByName(name) {
name = Grammar.toLowerCaseNoAccent(name)
switch (name) {
case 'reve-actuel': case 'reve actuel':
return this.system.carac.reve
case 'chance-actuelle': case 'chance actuelle':
return this.system.carac.chance
case 'vie':
return this.system.sante.vie
}
const carac = this.system.carac;
return RdDBaseActor.$findCaracByName(carac, name);
}
getCaracByName(name) {
switch (Grammar.toLowerCaseNoAccent(name)) {
case 'reve-actuel': case 'reve actuel':
return this.getCaracReveActuel();
case 'chance-actuelle': case 'chance-actuelle':
return this.getCaracChanceActuelle();
}
return this.findCaracByName(name);
}
/* -------------------------------------------- */
async _preCreate(data, options, user) {
await super._preCreate(data, options, user);
// Configure prototype token settings
const prototypeToken = {};
if (this.type === "personnage") Object.assign(prototypeToken, {
sight: { enabled: true }, actorLink: true, disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY
});
this.updateSource({ prototypeToken });
}
/* -------------------------------------------- */
prepareData() {
super.prepareData()
this.prepareActorData()
this.cleanupConteneurs()
this.computeEtatGeneral()
this.computeEncTotal()
}
async prepareActorData() { }
async computeEtatGeneral() { }
/* -------------------------------------------- */
findPlayer() {
return game.users.players.find(player => player.active && player.character?.id == this.id);
}
isCreatureEntite() { return this.isCreature() || this.isEntite() }
isCreature() { return false }
isEntite(typeentite = []) { return false }
isVehicule() { return false }
isPersonnage() { return false }
getItem(id, type = undefined) {
const item = this.items.get(id);
if (type == undefined || (item?.type == type)) {
@ -116,17 +199,17 @@ export class RdDBaseActor extends Actor {
return undefined;
}
listeSuivants(filter = suivant => true) { return [] }
listeSuivants(filter = suivant => true) { return [] }
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
filterItems(filter, type = undefined) { return this.listItems(type)?.filter(filter) ?? []; }
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter) ?? []; }
findItemLike(idOrName, type) {
return this.getItem(idOrName, type)
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
}
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
recompute() { }
getEncombrementMax() { return 0 }
/* -------------------------------------------- */
async onPreUpdateItem(item, change, options, id) { }
@ -137,17 +220,45 @@ export class RdDBaseActor extends Actor {
async onUpdateActor(update, options, actorId) { }
async onTimeChanging(oldTimestamp, newTimestamp) {
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
}
async creerObjetParMJ(object) {
if (!Misc.isUniqueConnectedGM()) {
RdDBaseActor.remoteActorCall({
tokenId: this.token?.id,
actorId: this.id,
method: 'creerObjetParMJ',
args: [object]
});
return;
}
await this.createEmbeddedDocuments('Item', [object])
}
/* -------------------------------------------- */
async cleanupConteneurs() {
let updates = this.itemTypes['conteneur']
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
if (updates.length > 0) {
await this.updateEmbeddedDocuments("Item", updates)
}
}
/* -------------------------------------------- */
getFortune() {
return Monnaie.getFortune(this.itemTypes['monnaie']);
}
/* -------------------------------------------- */
async monnaieIncDec(id, value) {
let monnaie = this.getMonnaie(id);
if (monnaie) {
const quantite = Math.max(0, monnaie.system.quantite + value);
await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'system.quantite': quantite }]);
async itemQuantiteIncDec(id, value) {
let item = this.getItem(id);
if (item && item.isInventaire()) {
const quantite = Math.max(0, item.system.quantite + value);
await item.update({ 'system.quantite': quantite });
}
}
@ -201,6 +312,7 @@ export class RdDBaseActor extends Actor {
if (fromActorId && !game.user.isGM) {
RdDBaseActor.remoteActorCall({
userId: Misc.connectedGMOrUser(),
tokenId: this.token?.id,
actorId: this.id,
method: 'ajouterSols', args: [sols, fromActorId]
});
@ -220,7 +332,7 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
getQuantiteDisponible(item) {
return item?.getQuantite();
return item?.isService() ? undefined : item?.getQuantite();
}
/* -------------------------------------------- */
@ -237,14 +349,16 @@ export class RdDBaseActor extends Actor {
});
return;
}
const cout = Number(achat.prixTotal ?? 0);
const vendeur = achat.vendeurId ? game.actors.get(achat.vendeurId) : undefined;
const acheteur = achat.acheteurId ? game.actors.get(achat.acheteurId) : undefined;
const vente = achat.vente;
const quantite = (achat.choix.nombreLots ?? 1) * (vente.tailleLot);
const itemVendu = vendeur?.getItem(vente.item._id);
if (!this.verifierQuantite(vendeur, itemVendu, quantite)) {
const quantite = (achat.choix.nombreLots ?? 1) * (achat.vente.tailleLot);
const itemVendu = vendeur?.getItem(achat.vente.item._id) ?? game.items.get(achat.vente.item._id);
if (!itemVendu) {
ChatUtility.notifyUser(achat.userId, 'warn', vendeur ? `Le vendeur n'a pas plus de ${achat.vente.item.name} !` : `Impossible de retrouver: ${achat.vente.item.name} !`);
return;
}
if (vendeur && !vendeur.verifierQuantite(itemVendu, quantite)) {
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
return
}
@ -255,13 +369,13 @@ export class RdDBaseActor extends Actor {
await this.decrementerVente(vendeur, itemVendu, quantite, cout);
if (acheteur) {
await acheteur.depenserSols(cout);
const createdItemId = await acheteur.creerQuantiteItem(vente.item, quantite);
await acheteur.consommerNourritureAchetee(achat, vente, createdItemId);
const createdItemId = await acheteur.creerQuantiteItem(itemVendu, quantite);
await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId);
}
if (cout > 0) {
RdDAudio.PlayContextAudio("argent");
}
const chatAchatItem = duplicate(vente);
const chatAchatItem = duplicate(achat.vente);
chatAchatItem.quantiteTotal = quantite;
ChatMessage.create({
user: achat.userId,
@ -270,16 +384,16 @@ export class RdDBaseActor extends Actor {
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
});
if (!vente.quantiteIllimite) {
if (vente.quantiteNbLots <= achat.choix.nombreLots) {
if (!achat.vente.quantiteIllimite) {
if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) {
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
}
else if (achat.chatMessageIdVente) {
vente["properties"] = itemVendu.getProprietes();
vente.quantiteNbLots -= achat.choix.nombreLots;
vente.jsondata = JSON.stringify(vente.item);
achat.vente.properties = itemVendu.getProprietes();
achat.vente.quantiteNbLots -= achat.choix.nombreLots;
achat.vente.jsondata = JSON.stringify(achat.vente.item);
const messageVente = game.messages.get(achat.chatMessageIdVente);
messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente) });
messageVente.update({ content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', achat.vente) });
messageVente.render(true);
}
}
@ -296,9 +410,9 @@ export class RdDBaseActor extends Actor {
return this.getFortune() >= cout;
}
verifierQuantite(vendeur, item, quantiteTotal) {
const disponible = vendeur?.getQuantiteDisponible(item);
return disponible == undefined || disponible >= quantiteTotal;
verifierQuantite(item, quantiteDemande) {
const disponible = this.getQuantiteDisponible(item);
return disponible == undefined || disponible >= quantiteDemande;
}
async consommerNourritureAchetee(achat, vente, createdItemId) {
@ -310,6 +424,9 @@ export class RdDBaseActor extends Actor {
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
if (item.isService()) {
return;
}
let resteQuantite = (item.system.quantite ?? 1) - quantite;
if (resteQuantite <= 0) {
if (options.supprimerSiZero) {
@ -351,6 +468,10 @@ export class RdDBaseActor extends Actor {
return 0;
}
getEncTotal() {
return Math.floor(this.encTotal ?? 0);
}
async createItem(type, name = undefined) {
if (!name) {
name = 'Nouveau ' + Misc.typeName('Item', type);
@ -363,14 +484,15 @@ export class RdDBaseActor extends Actor {
}
async processDropItem(params) {
const targetActorId = this.id;
const sourceActorId = params.sourceActorId;
const itemId = params.itemId;
const destId = params.destId;
const srcId = params.srcId;
const targetActorId = this.id
const sourceActorId = params.sourceActorId
const sourceTokenId = params.sourceTokenId
const itemId = params.itemId
const destId = params.destId
const srcId = params.srcId
if (sourceActorId && sourceActorId != targetActorId) {
console.log("Moving objects", sourceActorId, targetActorId, itemId);
this.moveItemsBetweenActors(itemId, sourceActorId);
console.log("Moving objects", sourceActorId, sourceTokenId, targetActorId, itemId);
this.moveItemsBetweenActors(itemId, sourceActorId, sourceTokenId);
return false;
}
let result = true;
@ -415,65 +537,35 @@ export class RdDBaseActor extends Actor {
/* -------------------------------------------- */
conteneurPeutContenir(dest, item) {
conteneurPeutContenir(dest, moved) {
if (!dest) {
return true;
}
if (!dest.isConteneur()) {
return false;
}
const destData = dest
if (this._isConteneurContenu(item, dest)) {
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`);
return false; // Loop detected !
if (moved.isConteneurContenu(dest)) {
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${moved.name}) dans un de ses contenus ${dest.name} !`);
return false;
}
// Calculer le total actuel des contenus
let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement);
let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet
const encContenu = dest.getEncContenu();
const newEnc = moved.getEncTotal(); // Calculer le total actuel du nouvel objet
const placeDisponible = Math.roundDecimals(dest.system.capacite - encContenu - newEnc, 4)
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
if (Number(destData.system.capacite) < encContenu + newEnc) {
if (placeDisponible < 0) {
ui.notifications.warn(
`Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}.
Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`);
`Le conteneur ${dest.name} a une capacité de ${dest.system.capacite}, et contient déjà ${encContenu}.
Impossible d'y ranger: ${moved.name} d'encombrement ${newEnc}!`);
return false;
}
return true;
}
/* -------------------------------------------- */
_isConteneurContenu(item, conteneur) {
if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant
for (let id of item.system.contenu) {
let subObjet = this.getItem(id);
if (subObjet?.id == conteneur.id) {
return true; // Loop detected !
}
if (subObjet?.isConteneur()) {
return this._isConteneurContenu(subObjet, conteneur);
}
}
}
return false;
}
/* -------------------------------------------- */
getRecursiveEnc(objet) {
if (!objet) {
return 0;
}
const tplData = objet.system;
if (objet.type != 'conteneur') {
return Number(tplData.encombrement) * Number(tplData.quantite);
}
const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu)));
return encContenus.reduce(Misc.sum(), 0)
+ Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/
}
/* -------------------------------------------- */
/** Ajoute un item dans un conteneur, sur la base
* de leurs ID */
/** Ajoute un item dans un conteneur, sur la base de leurs ID */
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
if (!conteneur) {
// TODO: afficher
@ -481,10 +573,8 @@ export class RdDBaseActor extends Actor {
}
else if (conteneur.isConteneur()) {
item.estContenu = true;
await this.updateEmbeddedDocuments('Item', [{
_id: conteneur.id,
'system.contenu': [...conteneur.system.contenu, item.id]
}]);
const nouveauContenu = [...conteneur.system.contenu, item.id];
await conteneur.update({ 'system.contenu': nouveauContenu });
onAjouterDansConteneur(item.id, conteneur.id);
}
}
@ -544,19 +634,16 @@ export class RdDBaseActor extends Actor {
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
if (conteneur?.isConteneur()) {
item.estContenu = false;
await this.updateEmbeddedDocuments('Item', [{
_id: conteneur.id,
'system.contenu': conteneur.system.contenu.filter(id => id != item.id)
}]);
const contenu = conteneur.system.contenu.filter(id => id != item.id);
await conteneur.update({ 'system.contenu': contenu });
onEnleverDeConteneur();
}
}
/* -------------------------------------------- */
async moveItemsBetweenActors(itemId, sourceActorId) {
let itemsList = []
let sourceActor = game.actors.get(sourceActorId);
itemsList.push({ id: itemId, conteneurId: undefined }); // Init list
async moveItemsBetweenActors(itemId, sourceActorId, sourceTokenId) {
let sourceActor = RdDBaseActor.getRealActor(sourceActorId, sourceTokenId)
let itemsList = [{ id: itemId, conteneurId: undefined }]
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
@ -569,20 +656,17 @@ export class RdDBaseActor extends Actor {
for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs
// gestion conteneur/contenu
if (item.conteneurId) { // l'Objet était dans un conteneur
let newConteneurId = itemMap[item.conteneurId]; // Get conteneur
let newConteneur = this.getItem(newConteneurId);
let newItemId = itemMap[item.id]; // Get newItem
const newConteneurId = itemMap[item.conteneurId];
const newConteneur = this.getItem(newConteneurId);
const newItemId = itemMap[item.id]; // Get newItem
console.log('New conteneur filling!', newConteneur, newItemId, item);
let contenu = duplicate(newConteneur.system.contenu);
contenu.push(newItemId);
await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]);
const nouveauContenu = [...newConteneur.system.contenu, newItemId]
await newConteneur.update({ 'system.contenu': nouveauContenu })
}
}
for (let item of itemsList) {
await sourceActor.deleteEmbeddedDocuments('Item', [item.id]);
}
const deletedItemIds = itemsList.map(it => it.id)
await sourceActor.deleteEmbeddedDocuments('Item', deletedItemIds);
}
_buildMapOldNewId(itemsList, newItems) {
@ -608,5 +692,20 @@ export class RdDBaseActor extends Actor {
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
}
actionImpossible(action) {
ui.notifications.info(`${this.name} ne peut pas faire cette action: ${action}`)
}
async roll() { this.actionImpossible("jet de caractéristiques") }
async jetEthylisme() { this.actionImpossible("jet d'éthylisme") }
async rollAppelChance() { this.actionImpossible("appel à la chance") }
async jetDeMoral() { this.actionImpossible("jet de moral") }
async actionPrincipale(item, onActionItem = async () => { }) {
switch (item.type) {
case TYPES.conteneur: return await item.sheet.render(true);
}
return undefined
}
}

View File

@ -1,9 +1,7 @@
import { DialogItemAchat } from "../dialog-item-achat.js";
import { RdDItem } from "../item.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
import { RdDCommerce } from "./commerce.js";
/**
* Extend the basic ActorSheet with some very simple modifications
@ -14,25 +12,43 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
width: 600,
height: 720,
tabs: [],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
width: 600, height: 720,
tabs: []
});
}
get title() {
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
return this.actor.token.name;
}
return super.title
}
async getData() {
const formData = await super.getData();
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
mergeObject(formData,
{
title: this.actor.token.name,
token: {
img: this.actor.token.texture.src
}
},
{ overwrite: true });
}
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
this.html.find('a.item-acheter').click(async event => await this.vente(this.getItem(event)));
if (!this.options.editable) return;
this.html.find('a.item-quantite-moins').click(async event => await this.getItem(event)?.quantiteIncDec(-1, { supprimerSiZero: false}));
this.html.find('a.item-quantite-moins').click(async event => await this.getItem(event)?.quantiteIncDec(-1, { supprimerSiZero: false }));
this.html.find('a.item-quantite-plus').click(async event => await this.getItem(event)?.quantiteIncDec(1));
this.html.find('input.item-quantite').change(async event => {
const newQuantite = Math.max(0, Number.parseInt(this.html.find(event.currentTarget).val()));
@ -48,7 +64,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
return RdDItem.getItemTypesInventaire('all');
}
async vente(item) {
const acheteur = RdDUtility.getSelectedActor();
if (!acheteur) {

View File

@ -2,32 +2,23 @@ import { Misc } from "../misc.js";
import { RdDBaseActor } from "./base-actor.js";
export class RdDCommerce extends RdDBaseActor {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/services/commerce.webp";
}
prepareData() {
super.prepareData();
}
prepareDerivedData() {
super.prepareDerivedData();
}
canReceive(item) {
if (item.isInventaire('all')) {
return true;
}
return super.canReceive(item);
return item.isInventaire('all');
}
getQuantiteDisponible(item) {
return this.system.illimite ? undefined : item.getQuantite();
return (this.system.illimite || item?.isService()) ? undefined : item.getQuantite();
}
verifierFortune(cout) {
return this.system.illimite || super.verifierFortune(cout);
}
async depenserSols(cout) {
if (this.system.illimite) {
return
@ -39,15 +30,15 @@ export class RdDCommerce extends RdDBaseActor {
// ne pas consommer pour un commerce
}
async decrementerQuantiteItem(itemVendu, quantite) {
async decrementerQuantiteItem(item, quantite) {
if (this.system.illimite) {
return;
}
await super.decrementerQuantiteItem(itemVendu, quantite, {supprimerSiZero: false});
await super.decrementerQuantiteItem(item, quantite, { supprimerSiZero: false });
}
calculerPrix(item) {
const pourcentage = this.system.pourcentage ?? 100;
return Misc.keepDecimals(Math.ceil(item.system.cout * pourcentage)/100, 2);
return Misc.keepDecimals(Math.ceil(item.system.cout * pourcentage) / 100, 2);
}
}

View File

@ -1,20 +1,17 @@
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
import { RdDBaseActorSangSheet } from "./base-actor-sang-sheet.js";
/**
* Extend the basic ActorSheet with some very simple modifications
* @extends {ActorSheet}
*/
export class RdDActorCreatureSheet extends RdDActorSheet {
export class RdDCreatureSheet extends RdDBaseActorSangSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
return mergeObject(RdDBaseActorSangSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
width: 640, height: 720
});
}

63
module/actor/creature.js Normal file
View File

@ -0,0 +1,63 @@
import { ENTITE_INCARNE } from "../constants.js";
import { TYPES } from "../item.js";
import { STATUSES } from "../settings/status-effects.js";
import { RdDBaseActorSang } from "./base-actor-sang.js";
export class RdDCreature extends RdDBaseActorSang {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/creatures/bramart.svg";
}
isCreature() { return true }
canReceive(item) {
return item.type == TYPES.competencecreature || item.isInventaire();
}
async remiseANeuf() {
await this.removeEffects(e => true);
await this.supprimerBlessures(it => true);
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max,
'system.sante.vie.value': this.system.sante.vie.max,
'system.sante.fatigue.value': 0
});
}
async finDeRoundBlessures() {
const nbGraves = this.filterItems(it => it.isGrave(), 'blessure').length;
if (nbGraves > 0) {
// Gestion blessure graves : -1 pt endurance par blessure grave
await this.santeIncDec("endurance", -nbGraves);
}
}
isEffectAllowed(effectId) {
return [STATUSES.StatusComma].includes(effectId);
}
isEntiteAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = this.system.sante.resonnance
return (resonnance.actors.find(it => it == attacker.id))
}
return true
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = duplicate(this.system.sante.resonnance);
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé
return;
}
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
}

View File

@ -0,0 +1,61 @@
import { RdDBaseActorReveSheet } from "./base-actor-reve-sheet.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
/** @override */
static get defaultOptions() {
return mergeObject(RdDBaseActorReveSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
width: 640, height: 720,
});
}
async getData() {
let formData = await super.getData();
formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId))
.map(actor => { return { id: actor.id, name: actor.name, img: actor.img } })
return formData
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// On competence change
this.html.find('.creature-carac').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
});
this.html.find('.creature-niveau').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
});
this.html.find('.creature-dommages').change(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
});
this.html.find('.resonance-delete').click(async event => {
const li = RdDSheetUtility.getEventElement(event);
const actorId = li.data("actor-id");
if (actorId) {
const actorResonance = game.actors.get(actorId);
RdDUtility.confirmSubActeurDelete(this, actorResonance, li, () => {
console.log('Delete : ', actorId);
this.deleteSubActeur(actorId);
RdDUtility.slideOnDelete(this, li);
});
}
});
}
async deleteSubActeur(actorId) {
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
}
}

110
module/actor/entite.js Normal file
View File

@ -0,0 +1,110 @@
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
import { TYPES } from "../item.js";
import { Misc } from "../misc.js";
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
import { STATUSES } from "../settings/status-effects.js";
import { RdDBaseActorReve } from "./base-actor-reve.js";
export class RdDEntite extends RdDBaseActorReve {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/entites/darquoine.webp";
}
canReceive(item) {
return item.type == TYPES.competencecreature
}
isEntite(typeentite = []) {
return (typeentite.length == 0 || typeentite.includes(this.system.definition.typeentite));
}
isNonIncarnee() { return this.isEntite([ENTITE_NONINCARNE]) }
getReveActuel() {
return Misc.toInt(this.system.carac.reve?.value)
}
getForce() { return this.getReve() }
getAgilite() { return this.getReve() }
getChance() { return this.getReve() }
getDraconicOuPossession() {
return this.itemTypes[TYPES.competencecreature]
.filter(it => it.system.categorie == 'possession')
.sort(Misc.descending(it => it.system.niveau))
.find(it => true);
}
async remiseANeuf() {
await this.removeEffects(e => true);
if (!this.isNonIncarnee()) {
await this.update({
'system.sante.endurance.value': this.system.sante.endurance.max
});
}
}
isDead() {
return this.isNonIncarnee() ? false : this.system.sante.endurance.value <= 0
}
async santeIncDec(name, inc, isCritique = false) {
if (name == 'endurance' && !this.isNonIncarnee()) {
const oldValue = this.system.sante.endurance.value;
const endurance = Math.max(0,
Math.min(oldValue + inc,
this.system.sante.endurance.max));
await this.update({ "system.sante.endurance.value": endurance })
await this.setEffect(STATUSES.StatusComma, endurance <= 0);
return {
perte: oldValue - endurance,
newValue: endurance
}
}
return {}
}
async encaisser() {
if (this.isNonIncarnee()) {
return
}
await RdDEncaisser.encaisser(this)
}
isEffectAllowed(effectId) {
return [STATUSES.StatusComma].includes(effectId);
}
async onAppliquerJetEncaissement(encaissement, attacker) {
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
mergeObject(encaissement, {
resteEndurance: perteEndurance.newValue,
endurance: perteEndurance.perte
});
}
isEntiteAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = this.system.sante.resonnance
return (resonnance.actors.find(it => it == attacker.id))
}
return true
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = duplicate(this.system.sante.resonnance);
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé
return;
}
resonnance.actors.push(attacker.id);
await this.update({ "system.sante.resonnance": resonnance });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
}

View File

@ -0,0 +1,39 @@
export const XP_TOPIC = {
XP: { code: 'xp', label: 'xp' },
XPSORT: { code: 'xpsort', label: 'xp sort' },
NIVEAU: { code: 'niveau', label: 'Niveau' },
XPCARAC: { code: 'xpcarac', label: 'xp carac' },
CARAC: { code: 'carac', label: 'Carac' },
STRESS: { code: 'stress', label: 'Stress' },
TRANSFORM: { code: 'xps', label: 'Transformé' },
}
export class ExperienceLog {
static async add(actor, topic, from, to, raison, manuel = false) {
if (!actor.hasPlayerOwner || !actor.isPersonnage()) {
return
}
if (from == to) {
return
}
const newXpLog = {
mode: topic?.code ?? topic,
raison: (manuel ? '(manuel) ' : '') + raison,
from: from,
to: to,
valeur: to - from,
daterdd: game.system.rdd.calendrier.dateCourante(),
datereel: game.system.rdd.calendrier.dateReel().replace('T', ' ')
};
console.log('ExperienceLog.add', newXpLog)
const newExperienceLog = (actor.system.experiencelog ?? []).concat([newXpLog]);
await actor.update({ [`system.experiencelog`]: newExperienceLog });
}
static labelTopic(topic) {
const xpt = Object.values(XP_TOPIC).find(it => it.code == topic);
return xpt?.label ?? xpt?.code ?? topic;
}
}

View File

@ -1,23 +1,33 @@
import { RdDUtility } from "./rdd-utility.js";
import { RdDActorSheet } from "./actor-sheet.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
/* -------------------------------------------- */
export class RdDActorVehiculeSheet extends RdDActorSheet {
export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
/** @override */
static get defaultOptions() {
RdDUtility.initAfficheContenu();
return mergeObject(super.defaultOptions, {
classes: ["rdd", "sheet", "actor"],
return mergeObject(RdDBaseActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
width: 640,
height: 720,
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
width: 640, height: 720,
});
}
/* -------------------------------------------- */
async getData() {
let formData = await super.getData();
mergeObject(formData,
{
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
limited: this.actor.limited,
owner: this.actor.isOwner,
});
this.timerRecherche = undefined;
return formData;
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;

28
module/actor/vehicule.js Normal file
View File

@ -0,0 +1,28 @@
import { RdDBaseActor } from "./base-actor.js";
export class RdDVehicule extends RdDBaseActor {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/vehicules/charette.webp";
}
isVehicule() { return true }
canReceive(item) {
return item.isInventaire();
}
getEncombrementMax() {
return this.system.capacite_encombrement;
}
async vehicleIncDec(name, inc) {
if (!['resistance', 'structure'].includes(name)) {
return
}
const newValue = this.system.etat[name].value + inc;
if (0 <= newValue && newValue <= this.system.etat[name].max) {
await this.update({ [`system.etat.${name}.value`]: newValue })
}
}
}

View File

@ -14,8 +14,8 @@ export class ChatUtility {
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data);
}
}
/* -------------------------------------------- */
static notifyUser(userId, level = 'info', message) {
const socketData = {
@ -71,18 +71,14 @@ export class ChatUtility {
}
static removeChatMessageId(messageId) {
if (messageId){
if (messageId) {
ChatUtility.removeMessages({ messageId: messageId });
}
}
/* -------------------------------------------- */
static async createChatWithRollMode(name, chatOptions) {
return await ChatUtility.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
}
/* -------------------------------------------- */
static async createChatMessage(name, rollMode, chatOptions) {
let rollMode = game.settings.get("core", "rollMode")
switch (rollMode) {
case "blindroll": // GM only
if (!game.user.isGM) {
@ -122,9 +118,10 @@ export class ChatUtility {
}
/* -------------------------------------------- */
static getWhisperRecipientsAndGMs(name) {
let recep1 = ChatMessage.getWhisperRecipients(name) || [];
return recep1.concat(ChatMessage.getWhisperRecipients('GM'));
static getWhisperRecipientsAndGMs(...names) {
let recipients = [...ChatMessage.getWhisperRecipients('GM')]
names.forEach(name => recipients.push(...ChatMessage.getWhisperRecipients(name)))
return recipients
}
/* -------------------------------------------- */

169
module/coeur/rdd-coeur.js Normal file
View File

@ -0,0 +1,169 @@
import { RdDBaseActor } from "../actor/base-actor.js";
import { ChatUtility } from "../chat-utility.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
const INFO_COEUR = 'info-coeur';
export class RdDCoeur {
static registerChatCallbacks(html) {
html.on("click", 'a.accepter-tendre-moment', event => {
RdDCoeur.accepterTendreMoment(RdDCoeur.extractInfoCoeur(event))
})
html.on("click", 'a.refuser-tendre-moment', event => {
RdDCoeur.refuserTendreMoment(RdDCoeur.extractInfoCoeur(event))
})
html.on("click", 'a.perdre-point-coeur-douceur', event => {
RdDCoeur.perdreEnDouceur(
RdDCoeur.extractInfoCoeur(event),
event.currentTarget.attributes['data-actor-id'].value)
})
}
static addTagsInfoCoeur(infoCoeur, chatMessage = undefined) {
if (chatMessage) {
infoCoeur.chatMessageId = chatMessage.id
}
else {
chatMessage = game.messages.get(infoCoeur.chatMessageId)
}
ChatUtility.setMessageData(chatMessage, INFO_COEUR, infoCoeur);
}
static extractInfoCoeur(event) {
return ChatUtility.getMessageData(ChatUtility.getChatMessage(event), INFO_COEUR)
}
static getInfoCoeur(sourceActorId, targetActorId) {
const sourceActor = game.actors.get(sourceActorId)
const targetActor = game.actors.get(targetActorId)
if (sourceActor && targetActor) {
return {
source: {
actor: RdDBaseActor.extractActorMin(sourceActor),
coeur: sourceActor.getPointsCoeur(targetActorId),
},
target: {
actor: RdDBaseActor.extractActorMin(targetActor),
coeur: targetActor.getPointsCoeur(sourceActorId),
}
}
}
return {}
}
static async toggleSubActeurCoeur(actorId, subActorId, toggleCoeur) {
const actor = game.actors.get(actorId)
const amoureux = actor.getSuivant(subActorId)
if (toggleCoeur <= amoureux.coeur) {
if (toggleCoeur > amoureux.prochainCoeur) {
toggleCoeur = amoureux.coeur
}
else {
toggleCoeur = amoureux.coeur - 1
}
}
else if (toggleCoeur <= amoureux.prochainCoeur) {
toggleCoeur = Math.max(amoureux.coeur, toggleCoeur - 1)
}
actor.setPointsCoeur(subActorId, Math.max(0, Math.min(toggleCoeur, 4)))
}
static async applyCoeurChateauDormant(actor, message) {
const newSuivants = duplicate(actor.system.subacteurs.suivants)
let count = 0
newSuivants.forEach(async link => {
const suivant = game.actors.get(link.id)
const prochainCoeur = link.prochainCoeur ?? 0;
const coeurCourant = link.coeur ?? 0;
const diff = prochainCoeur - coeurCourant
if (diff < 0) {
await actor.moralIncDec(-4);
link.coeur = Math.max(0, coeurCourant - 1)
link.prochainCoeur = link.coeur
message.content += `<br>Votre c&oelig;ur brisé pour ${suivant.name} vous fait perdre 4 points de moral, il vous reste ${link.coeur} points de C&oelig;ur.`
count++
}
else if (diff > 0) {
link.coeur = Math.min(prochainCoeur, 4)
message.content += `<br>Votre c&oelig;ur bat fort, vous avez maintenant ${link.coeur} points de C&oelig;ur pour ${suivant.name}.`
link.prochainCoeur = link.coeur
count++
}
}
)
if (count > 0) {
await actor.update({ 'system.subacteurs.suivants': newSuivants });
}
}
static async startSubActeurTendreMoment(actorId, subActeurId) {
const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId)
if (infoCoeur.target?.actor.id) {
// TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...)
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
const chatMessage = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.target?.actor.name),
content: chatHtml
})
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
}
}
static async accepterTendreMoment(infoCoeur) {
const target = game.actors.get(infoCoeur.target.actor.id)
if (!target.isOwner) {
ui.notifications.warn(`vous ne pouvez pas accepter pour ${infoCoeur.target.actor.name}`)
return
}
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total
infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total
const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre)
for (let amoureux of [infoCoeur.source, infoCoeur.target]) {
const actorAmoureux = game.actors.get(amoureux.actor.id);
amoureux.situation = diff <= amoureux.coeur ? 'heureux' : 'neutre'
amoureux.gainMoral = await actorAmoureux.jetDeMoral(amoureux.situation)
}
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur)
const chatMessage = await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name),
content: chatHtml
})
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
}
static async refuserTendreMoment(infoCoeur) {
const target = game.actors.get(infoCoeur.target.actor.id)
if (!target.isOwner) {
ui.notifications.warn(`vous ne pouvez pas refuser pour ${infoCoeur.target.actor.name}`)
return
}
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur)
await ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name),
content: chatHtml
});
}
static async perdreEnDouceur(infoCoeur, actorId) {
const [amoureux, partenaire] = (infoCoeur.source.actor.id == actorId
? [infoCoeur.source, infoCoeur.target]
: (infoCoeur.target.actor.id == actorId
? [infoCoeur.target, infoCoeur.source]
: [undefined, undefined]))
if (amoureux.perteCoeur) {
ui.notifications.warn(`Le point de c&oelig;ur a déjà été perdu`)
}
else if (amoureux.coeur > 0) {
const actor = game.actors.get(actorId)
if (actor.isOwner) {
await actor.setPointsCoeur(partenaire?.actor.id, amoureux.coeur - 1, { immediat: true })
amoureux.perteCoeur = true
RdDCoeur.addTagsInfoCoeur(infoCoeur)
}
}
}
}

View File

@ -0,0 +1,84 @@
export class DialogChoixXpCarac extends Dialog {
static async choix(actor, xpData, caracs) {
caracs = caracs.map(it => mergeObject({ ajout: 0 }, it))
xpData = mergeObject({ reste: xpData.xpCarac }, xpData)
const dialogData = {
title: `Choisissez la répartition d'expérience`,
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-choix-xp-carac.hbs", {
actor,
caracDerivee: actor.findCaracByName(xpData.caracName),
xpData,
caracs
}),
}
const dialogOptions = {
classes: ["rdd-dialog-select"],
width: 400,
height: 'fit-content',
'z-index': 99999
}
new DialogChoixXpCarac(dialogData, dialogOptions, actor, xpData, caracs).render(true)
}
constructor(dialogData, dialogOptions, actor, xpData, caracs) {
dialogData = mergeObject(dialogData, {
default: 'appliquer',
buttons: {
'appliquer': { icon:'<i class="fa-solid fa-check"></i>', label: "Ajouter la répartition", callback: it => this.appliquerSelection() }
}
})
super(dialogData, dialogOptions)
this.actor = actor
this.xpData = xpData
this.caracs = caracs
}
activateListeners(html) {
//TODO
super.activateListeners(html)
this.html = html
this.html.find("li.xpCarac-option .xpCarac-moins").click(event =>
this.ajouterXp(event, -1)
)
this.html.find("li.xpCarac-option .xpCarac-plus").click(event =>
this.ajouterXp(event, 1)
)
}
async ajouterXp(event, delta) {
const liCarac = this.html.find(event.currentTarget)?.parents("li.xpCarac-option")
const label = liCarac?.data("carac-label")
const carac = this.caracs.find(c => c.label == label)
if (carac.ajout + delta < 0) {
ui.notifications.warn(`Impossible de diminuer les points à répartir en ${carac.label} en dessous de 0`)
return
}
if (this.xpData.reste - delta < 0) {
ui.notifications.warn(`Il ne reste plus de points à répartir en ${carac.label}`)
return
}
carac.ajout += delta
this.xpData.reste -= delta
liCarac.find("input.xpCarac-view-ajout").val(carac.ajout)
this.html.find("input.xpCarac-reste").val(this.xpData.reste)
}
async appliquerSelection() {
if (this.xpData.reste > 0) {
ui.notifications.warn(`Il vous reste ${this.xpData.reste} points à répartir`)
return
}
this.caracs.filter(c => c.ajout > 0).forEach(c => {
const xpData = { caracName: c.label, xpCarac: c.ajout }
this.actor._xpCarac(xpData)
})
await super.close()
}
async close() { }
_getHeaderButtons() { return [] }
}

View File

@ -1,5 +1,7 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
@ -16,62 +18,75 @@ export class DialogChronologie extends Dialog {
});
}
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()
timestamp: game.system.rdd.calendrier.timestamp,
dateReel: game.system.rdd.calendrier.dateReel()
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
const dialog = new DialogChronologie(html);
const dialog = new DialogChronologie(html, dialogData);
dialog.render(true);
}
constructor(html) {
constructor(html, dialogData) {
const options = {
classes: ["DialogChronologie"],
width: 500,
height: 'fit-content',
'z-index': 99999
};
const timeData = dialogData.timestamp.toCalendrier()
const conf = {
title: "Chronologie",
title: `Chronologie - ${timeData.jourDuMois} ${timeData.mois.label} - Heure ${timeData.heure.label}`,
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");
this.dialogData = dialogData;
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
super.activateListeners(html);
const journalPrecedent = game.journal.get(this.dialogData.journalId);
this.showChronologiePreset(!(journalPrecedent?.canUserModify(game.user)))
this.html.find("a.chronologie-preset-show").click(event => this.showChronologiePreset(true));
this.html.find("a.chronologie-preset-hide").click(event => this.showChronologiePreset(false));
this.html.find("button.chronologie-ajouter").click(event => this.ajouter());
}
showChronologiePreset(showPreset) {
HtmlUtility.showControlWhen(this.html.find(".chronologie-preset-show"), !showPreset);
HtmlUtility.showControlWhen(this.html.find(".chronologie-preset-hide"), showPreset);
HtmlUtility.showControlWhen(this.html.find(".chronologie-preset"), showPreset);
}
async ajouter() {
await this.forceValidation();
const { journalId, journalEntry } = this.findJournal();
// ajouter à la page ou créer une page
this.addContentToJournal(journalEntry, await this.prepareChronologieEntry());
if (journalEntry?.canUserModify(game.user)) {
const journalParameters = this.extractJournalParameters();
this.storeLatestUsedJournalEntry(journalId);
const jour = journalParameters.dateRdD.jour;
const mois = journalParameters.dateRdD.mois.label;
const annee = journalParameters.dateRdD.annee;
const section = `${jour} ${mois} ${annee}`
const content = await this.prepareChronologieEntry(journalParameters);
// ajouter à la page ou créer une page
this.addContentToJournal(journalEntry, section, content);
this.storeLatestUsedJournalEntry(journalId);
this.close();
}
else {
const journal = this.html.find("form.rdddialogchrono select[name='journalId']").val();
ui.notifications.warn(`Le journal ${journal} n'est pas accessible`);
}
}
async forceValidation() {
@ -84,8 +99,8 @@ export class DialogChronologie extends Dialog {
return { journalId, journalEntry };
}
async prepareChronologieEntry() {
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", this.extractJournalParameters());
async prepareChronologieEntry(journalParameters) {
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", journalParameters);
}
extractJournalParameters() {
@ -93,28 +108,29 @@ export class DialogChronologie extends Dialog {
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()
jour: this.html.find("form.rdddialogchrono :input[name='chronologie.jourDuMois']").val(),
mois: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.mois']").val()),
annee: this.html.find("form.rdddialogchrono :input[name='chronologie.annee']").val(),
heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()),
minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").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'));
addContentToJournal(journalEntry, section, content) {
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, section));
if (page) {
page.update({ 'text.content': content + '\n' + page.text.content });
page.update({ 'text.content': page.text.content + '\n' + content });
}
else {
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(content)]);
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(section, content)]);
}
}
newPageChronologie(content) {
newPageChronologie(section, content) {
return new JournalEntryPage({
name: 'Chronologie',
name: section,
type: 'text',
title: { show: true, level: 1 },
text: { content: content, format: 1 }

View File

@ -1,6 +1,6 @@
import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog {
@ -14,7 +14,7 @@ export class DialogCreateSigneDraconique extends Dialog {
.map(actor => ({
id: actor.id,
name: actor.name,
selected: true
selected: false
}))
};
@ -98,7 +98,7 @@ export class DialogCreateSigneDraconique extends Dialog {
async setEphemere(ephemere) {
this.dialogData.signe.system.ephemere = ephemere;
HtmlUtility._showControlWhen(this.html.find(".signe-system-duree"), ephemere);
HtmlUtility.showControlWhen(this.html.find(".signe-system-duree"), ephemere);
}
async onSelectActor(event) {
@ -111,7 +111,7 @@ export class DialogCreateSigneDraconique extends Dialog {
onSelectTmr(event) {
const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
const onTmr = this.tmrs.find(it => it.name == tmrName);
const onTmr = this.dialogData.tmrs.find(it => it.name == tmrName);
if (onTmr){
onTmr.selected = event.currentTarget.checked;
}

View File

@ -5,7 +5,7 @@ import { RdDUtility } from "./rdd-utility.js";
export class DialogFabriquerPotion extends Dialog {
/* -------------------------------------------- */
static async create(actor, item, dialogConfig) {
static async create(actor, item, onActionItem) {
const min = DialogFabriquerPotion.nombreBrinsMinimum(item);
if (item.system.quantite < min) {
ui.notifications.warn(`Vous avez ${item.system.quantite} brins de ${item.name}, il en faut au moins ${min} pour faire une potion!`);
@ -13,12 +13,10 @@ export class DialogFabriquerPotion extends Dialog {
}
let potionData = DialogFabriquerPotion.prepareData(actor, item);
const html = await renderTemplate(dialogConfig.html, potionData);
const html = await renderTemplate( 'systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData);
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
new DialogFabriquerPotion(actor, potionData, html, options).render(true);
new DialogFabriquerPotion(actor, potionData, onActionItem, html, options).render(true);
}
/* -------------------------------------------- */
@ -34,14 +32,14 @@ export class DialogFabriquerPotion extends Dialog {
}
/* -------------------------------------------- */
constructor(actor, potionData, html, options) {
constructor(actor, potionData, onActionItem, html, options) {
const conf = {
title: `Fabriquer une potion de ${potionData.system.categorie}`,
content: html,
default: 'fabriquer',
buttons: {
'fabriquer': {
label: potionData.buttonName, callback: it => this.onFabriquer(html)
label: potionData.buttonName, callback: it => this.onFabriquer()
}
}
};
@ -50,6 +48,7 @@ export class DialogFabriquerPotion extends Dialog {
this.actor = actor;
this.potionData = potionData;
this.onActionItem = onActionItem;
}
/* -------------------------------------------- */
@ -64,10 +63,11 @@ export class DialogFabriquerPotion extends Dialog {
}
/* -------------------------------------------- */
async onFabriquer(html) {
async onFabriquer() {
await this.html.find("[name='nbBrins']").change();
this.actor.fabriquerPotion(this.potionData);
await this.actor.fabriquerPotion(this.potionData);
this.close();
await this.onActionItem()
}
static nombreBrinsMinimum(herbeData) {

View File

@ -18,7 +18,7 @@ export class DialogItemAchat extends Dialog {
}
return {
item: (json ? JSON.parse(json) : undefined),
item: JSON.parse(json),
vendeur,
acheteur,
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
@ -34,7 +34,6 @@ export class DialogItemAchat extends Dialog {
const venteData = {
item,
actingUserId: game.user.id,
vendeurId: vendeur?.id,
vendeur,
acheteur,
tailleLot,

View File

@ -4,11 +4,11 @@ export class DialogItemVente extends Dialog {
static async display({ item, callback, quantiteMax = undefined }) {
const quantite = quantiteMax ?? item.getQuantite() ?? 1;
const isOwned = item.isOwned;
const isOwned = item.parent;
const venteData = {
item: item,
alias: item.actor?.name ?? game.user.name,
vendeurId: item.actor?.id ,
vendeurId: item.actor?.id,
prixOrigine: item.calculerPrixCommercant(),
prixUnitaire: item.calculerPrixCommercant(),
prixLot: item.calculerPrixCommercant(),
@ -16,7 +16,7 @@ export class DialogItemVente extends Dialog {
quantiteNbLots: quantite,
quantiteMaxLots: quantite,
quantiteMax: quantite,
quantiteIllimite: !isOwned || quantiteMax == undefined,
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned,
isOwned: isOwned,
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
@ -40,53 +40,63 @@ export class DialogItemVente extends Dialog {
activateListeners(html) {
super.activateListeners(html);
this.html = html;
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
this.html = html;
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
this.setQuantiteIllimite(this.venteData.quantiteIllimite);
}
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.updateVente(this.getChoixVente());
this.callback(this.venteData);
}
updateVente(update) {
mergeObject(this.venteData, update);
}
getChoixVente() {
return {
quantiteNbLots: Number(this.html.find(".quantiteNbLots").val()),
tailleLot: Number(this.html.find(".tailleLot").val()),
quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'),
prixLot: Number(this.html.find(".prixLot").val())
};
}
/* -------------------------------------------- */
setPrixLot(prixLot) {
this.venteData.prixLot = prixLot;
}
setTailleLot(tailleLot) {
// recalculer le prix du lot
if (tailleLot != this.venteData.tailleLot) {
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
this.html.find(".prixLot").val(this.venteData.prixLot);
}
this.venteData.tailleLot = tailleLot;
// recalculer le nombre de lots max
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.updateVente({
tailleLot,
quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots),
quantiteMaxLots: maxLots,
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
});
this.html.find(".prixLot").val(this.venteData.prixLot);
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
}
setNbLots(nbLots) {
if (this.venteData.isOwned) {
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
}
this.venteData.quantiteNbLots = nbLots;
this.updateVente({
quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots
})
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
}
setQuantiteIllimite(checked) {
this.venteData.quantiteIllimite = checked;
this.updateVente({ quantiteIllimite: checked })
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility._showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
}
}

View File

@ -1,57 +0,0 @@
export class DialogRepos extends Dialog {
static async create(actor) {
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actor);
const dialog = new DialogRepos(html, actor);
dialog.render(true);
}
constructor(html, actor) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 400, height: 'fit-content', 'z-index': 99999 };
let conf = {
title: "Se reposer",
content: html,
default: "repos",
buttons: {
"repos": { label: "Se reposer", callback: async it => { this.repos(); } }
}
};
super(conf, options);
this.actor = actor;
}
activateListeners(html) {
super.activateListeners(html);
this.html = html;
}
/* -------------------------------------------- */
async repos() {
await this.html.find("[name='nb-heures']").change();
await this.html.find("[name='nb-jours']").change();
const selection = await this.html.find("[name='repos']:checked").val();
const nbHeures = Number.parseInt(await this.html.find("[name='nb-heures']").val());
const nbJours = Number.parseInt(await this.html.find("[name='nb-jours']").val());
console.log("ACTOR", this.actor)
switch (selection) {
case "sieste": {
await this.actor.dormir(nbHeures);
return;
}
case "nuit": {
let heuresDormies = await this.actor.dormir(nbHeures);
if (heuresDormies == nbHeures) {
await this.actor.dormirChateauDormant();
}
return;
}
case "chateau-dormant":
await this.actor.dormirChateauDormant();
return;
case "gris-reve": {
await this.actor.grisReve(nbJours);
return;
}
}
}
}

View File

@ -1,37 +0,0 @@
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);
}
}
}

45
module/dialog-select.js Normal file
View File

@ -0,0 +1,45 @@
export class DialogSelect extends Dialog {
static extractIdNameImg(it) { return { id: it.id, name: it.name, img: it.img } }
static async select(selectData, onSelectChoice) {
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-select.html", selectData)
const dialogData = {
title: selectData.title ?? selectData.label,
content: html,
buttons: {}
}
const dialogOptions = {
classes: ["rdd-dialog-select"],
width: 'fit-content',
height: 'fit-content',
'max-height': 600,
'z-index': 99999
}
new DialogSelect(dialogData, dialogOptions, selectData, onSelectChoice).render(true)
}
constructor(dialogData, dialogOptions, selectionData, onSelectChoice) {
super(dialogData, dialogOptions)
this.selectionData = selectionData
this.onSelectChoice = onSelectChoice
}
activateListeners(html) {
super.activateListeners(html)
this.html = html
this.html.find("li.select-choice").click(event =>
this.choiceSelected(this.html.find(event.currentTarget)?.data("id"))
)
}
choiceSelected(selectedId) {
const selected = this.selectionData.find(it => it.id == selectedId)
this.close()
if (selected) {
this.onSelectChoice(selected)
}
}
}

View File

@ -7,23 +7,22 @@ import { RdDUtility } from "./rdd-utility.js";
*/
export class DialogValidationEncaissement extends Dialog {
static async validerEncaissement(actor, rollData, armure, show, onEncaisser) {
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
actor: actor,
rollData: rollData,
encaissement: encaissement,
show: show
encaissement: encaissement
});
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser);
dialog.render(true);
}
/* -------------------------------------------- */
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
constructor(html, actor, rollData, armure, encaissement, onEncaisser) {
// Common conf
let buttons = {
"valider": { label: "Valider", callback: html => this.validerEncaissement() },
"valider": { label: "Valider", callback: html => this.onValider() },
"annuler": { label: "Annuler", callback: html => { } },
};
@ -47,7 +46,6 @@ export class DialogValidationEncaissement extends Dialog {
this.rollData = rollData;
this.armure = armure;
this.encaissement = encaissement;
this.show = show;
this.onEncaisser = onEncaisser;
this.forceDiceResult = {total: encaissement.roll.result };
}
@ -64,8 +62,8 @@ export class DialogValidationEncaissement extends Dialog {
});
}
async validerEncaissement() {
async onValider() {
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
this.onEncaisser(this.encaissement, this.show)
this.onEncaisser(this.encaissement)
}
}

View File

@ -1,223 +1,78 @@
import { SYSTEM_RDD } from "./constants.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { CompendiumTableHelpers, CompendiumTable } from "./settings/system-compendiums.js";
import { CompendiumTableHelpers, CompendiumTable, SystemCompendiums } 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'
]
const COMPENDIUMS_RECHERCHE = 'compendiums-recherche';
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",
game.settings.register(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, {
name: COMPENDIUMS_RECHERCHE,
default: [
SystemCompendiums.getCompendium('faune-flore-mineraux'),
SystemCompendiums.getCompendium('meditations-et-ecrits'),
SystemCompendiums.getCompendium('equipement')
],
scope: "world",
config: true,
default: MILIEUX.reduce(Misc.joining(',')),
type: String
config: false,
type: Object
});
game.system.rdd.environnement = new Environnement();
Hooks.once('ready', () => game.system.rdd.environnement.onReady());
}
constructor() {
this.table = new CompendiumTable('faune-flore-mineraux', 'Item', ITEM_ENVIRONNEMENT_TYPES)
this.compendiums = [];
this.compendiumTables = [];
this.mapMilieux = {}
}
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 onReady() {
await this.$prepareCompendiums()
}
async milieux() {
return Object.values(await this.mapMilieux());
return Object.values(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)));
async saveCompendiums(compendiumIds) {
game.settings.set(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, compendiumIds);
await this.$prepareCompendiums();
}
static listMilieux(items) {
return Misc.concat(items.map(it => Environnement.$itemToMilieux(it).filter(m => m)));
async $prepareCompendiums() {
this.compendiums = game.settings.get(SYSTEM_RDD, COMPENDIUMS_RECHERCHE).filter(c => SystemCompendiums.getPack(c));
this.compendiumTables = this.compendiums.map(it => new CompendiumTable(it, 'Item'));
const compendiumItems = await this.getElements(it => 1, it => it.isInventaire());
const fromCompendiums = Misc.concat(compendiumItems.map(it => it.getMilieux().filter(m => m)));
this.mapMilieux = Misc.indexLowercase(fromCompendiums);
}
async autresMilieux(item) {
const mapMilieux = await this.mapMilieux();
const milieuxExistants = Environnement.$itemToMilieux(item).map(it => Grammar.toLowerCaseNoAccent(it));
return Object.keys(mapMilieux)
const milieuxExistants = item.getMilieux().map(it => Grammar.toLowerCaseNoAccent(it));
return Object.keys(this.mapMilieux)
.filter(it => !milieuxExistants.includes(it))
.map(it => mapMilieux[it]);
.map(it => this.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);
const compendiumsElement = await Promise.all(
this.compendiumTables.map(async compTable => await compTable.getContent(itemFrequence, filter))
);
const elements = compendiumsElement.reduce((a, b) => a.concat(b));
elements.sort(Misc.ascending(it => it.name))
return elements;
}
async buildTable(itemFrequence, filter = it => true) {
if (!itemFrequence) {
itemFrequence = it => it.getFrequence()
}
const elements = await this.getElements(itemFrequence, filter);;
return CompendiumTableHelpers.buildTable(elements, itemFrequence);
}
}
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

@ -1,5 +1,5 @@
export class HtmlUtility{
static _showControlWhen(jQuerySelector, condition) {
static showControlWhen(jQuerySelector, condition) {
if (condition) {
jQuerySelector.show();
}

View File

@ -1,5 +1,5 @@
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
import { Misc } from "./misc.js";
import { TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js";
const nomCategorieParade = {
@ -20,15 +20,15 @@ const nomCategorieParade = {
export class RdDItemArme extends Item {
static isArme(item) {
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme';
return item.type == TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
}
/* -------------------------------------------- */
static getArme(arme) {
switch (arme ? arme.type : '') {
case 'arme': return arme;
case 'competencecreature':
return RdDItemCompetenceCreature.armeNaturelle(arme);
case TYPES.arme: return arme;
case TYPES.competencecreature:
return RdDItemCompetenceCreature.armeCreature(arme);
}
return RdDItemArme.mainsNues();
}
@ -68,14 +68,14 @@ export class RdDItemArme extends Item {
return armeData.system.categorie_parade;
}
// pour compatibilité avec des personnages existants
if (armeData.type == 'competencecreature' || armeData.system.categorie == 'creature') {
if (armeData.type == TYPES.competencecreature || armeData.system.categorie == 'creature') {
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
}
if (!armeData.type.match(/arme|competencecreature/)) {
return '';
}
if (armeData.system.competence == undefined) {
return 'competencecreature';
return TYPES.competencecreature;
}
let compname = armeData.system.competence.toLowerCase();
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
@ -157,23 +157,37 @@ export class RdDItemArme extends Item {
}
return armeData;
}
static competence2Mains(arme) {
return arme.system.competence.replace(" 1 main", " 2 mains");
}
static competence1Mains(arme) {
return arme.system.competence.replace(" 2 mains", " 1 main");
}
static isArmeUtilisable(arme) {
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0);
switch (arme.type) {
case TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
case TYPES.competencecreature: return true
}
return false
}
static ajoutCorpsACorps(armes, competences, carac) {
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
//armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
static ajoutCorpsACorps(armes, actor) {
armes.push(RdDItemArme.mainsNues(actor));
armes.push(RdDItemArme.empoignade(actor));
}
static corpsACorps(mainsNuesActor) {
const corpsACorps = {
static corpsACorps(actor) {
let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } };
let melee = actor? actor.system.carac['melee'].value : 0
return {
_id: competence?.id,
name: 'Corps à corps',
type: TYPES.arme,
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
system: {
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
equipe: true,
rapide: true,
force: 0,
@ -181,23 +195,23 @@ export class RdDItemArme extends Item {
dommagesReels: 0,
mortalite: 'non-mortel',
competence: 'Corps à corps',
resistance: 1,
deuxmains: true,
categorie_parade: 'sans-armes'
}
};
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false });
return corpsACorps;
}
}
static mainsNues(mainsNuesActor) {
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor)
static mainsNues(actor) {
const mainsNues = RdDItemArme.corpsACorps(actor)
mainsNues.name = 'Mains nues'
mainsNues.system.cac = 'pugilat'
mainsNues.system.baseInit = 4
return mainsNues;
}
static empoignade(mainsNuesActor) {
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor)
static empoignade(actor) {
const empoignade = RdDItemArme.corpsACorps(actor)
empoignade.name = 'Empoignade'
empoignade.system.cac = 'empoignade'
empoignade.system.baseInit = 3

View File

@ -8,22 +8,22 @@ 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 limitesArchetypes = [
{ "niveau": 0, "nombreMax": 100, "reste": 100 },
{ "niveau": 1, "nombreMax": 10, "reste": 10 },
{ "niveau": 2, "nombreMax": 9, "reste": 9 },
{ "niveau": 3, "nombreMax": 8, "reste": 8 },
{ "niveau": 4, "nombreMax": 7, "reste": 7 },
{ "niveau": 5, "nombreMax": 6, "reste": 6 },
{ "niveau": 6, "nombreMax": 5, "reste": 5 },
{ "niveau": 7, "nombreMax": 4, "reste": 4 },
{ "niveau": 8, "nombreMax": 3, "reste": 3 },
{ "niveau": 9, "nombreMax": 2, "reste": 2 },
{ "niveau": 10, "nombreMax": 1, "reste": 1 },
{ "niveau": 11, "nombreMax": 1, "reste": 1 }
{ niveau: 0, nombreMax: 100 },
{ niveau: 1, nombreMax: 10 },
{ niveau: 2, nombreMax: 9 },
{ niveau: 3, nombreMax: 8 },
{ niveau: 4, nombreMax: 7 },
{ niveau: 5, nombreMax: 6 },
{ niveau: 6, nombreMax: 5 },
{ niveau: 7, nombreMax: 4 },
{ niveau: 8, nombreMax: 3 },
{ niveau: 9, nombreMax: 2 },
{ niveau: 10, nombreMax: 1 },
{ niveau: 11, nombreMax: 1 },
];
/* -------------------------------------------- */
const categorieCompetences = {
const categoriesCompetences = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
@ -49,16 +49,16 @@ const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static getCategorieCompetences() {
return categorieCompetences;
}
/* -------------------------------------------- */
static getNiveauBase(category) {
return categorieCompetences[category].base;
static getCategories() {
return categoriesCompetences;
}
/* -------------------------------------------- */
static getLabelCategorie(category) {
return categorieCompetences[category].label;
return categoriesCompetences[category].label;
}
/* -------------------------------------------- */
static getNiveauBase(category, categories = categoriesCompetences) {
return categories[category]?.base ?? 0;
}
/* -------------------------------------------- */
@ -79,10 +79,9 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static isCompetenceArme(competence) {
if (competence.isCompetence()) {
if (competence.isCompetence() && !competence.isCorpsACorps() && !competence.isEsquive()) {
switch (competence.system.categorie) {
case 'melee':
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
case 'tir':
case 'lancer':
return true;
@ -93,10 +92,10 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static isArmeUneMain(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main");
return competence.isCompetenceArme() && competence.name.toLowerCase().includes("1 main");
}
static isArme2Main(competence) {
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main");
return competence.isCompetenceArme() && competence.name.toLowerCase().includes("2 main");
}
static isThanatos(competence) {
@ -190,18 +189,9 @@ export class RdDItemCompetence extends Item {
}
}
/* -------------------------------------------- */
static isVisible(item) {
return Number(item.system.niveau) != RdDItemCompetence.getNiveauBase(item.system.categorie);
}
static nomContientTexte(item, texte) {
return Grammar.toLowerCaseNoAccent(item.name).includes(Grammar.toLowerCaseNoAccent(texte))
}
/* -------------------------------------------- */
static isNiveauBase(item) {
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie);
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.getCategories());
}
/* -------------------------------------------- */
@ -268,18 +258,22 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static computeResumeArchetype(competences) {
const computed = duplicate(limitesArchetypes);
computed.forEach(it => { it.nombre = 0; it.reste = it.nombreMax; });
competences.map(it => Math.max(0, it.system.niveau_archetype))
.filter(n => n > 0)
.forEach(n => {
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 };
computed[n].reste = computed[n].reste - 1;
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0, nombre: 0 };
computed[n].reste--;
computed[n].nombre++;
});
return computed.filter(it => it.reste > 0 && it.niveau > 0);
return computed.filter(it => it.niveau > 0);
}
/* -------------------------------------------- */
static triVisible(competences) {
return competences.filter(it => it.system.isVisible)
return competences.filter(it => !it.system.isHidden)
.sort((a, b) => RdDItemCompetence.compare(a, b))
}

View File

@ -1,51 +1,112 @@
import { TYPES } from "./item.js";
import { RdDCombatManager } from "./rdd-combat.js";
const categories = {
"generale": { base: 0, label: "Générale" },
"naturelle": { base: 0, label: "Arme naturelle" },
"melee": { base: 0, label: "Mêlée" },
"parade": { base: 0, label: "Parade" },
"tir": { base: 0, label: "Tir" },
"lancer": { base: 0, label: "Lancer" },
"possession": { base: 0, label: "Possession" },
}
/* -------------------------------------------- */
export class RdDItemCompetenceCreature extends Item {
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
rollData.competence = rollData.competence
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
rollData.competence.system.defaut_carac = "carac_creature"
rollData.competence.system.categorie = "creature"
rollData.selectedCarac = rollData.carac.carac_creature
if (rollData.competence.system.iscombat) {
rollData.arme = RdDItemCompetenceCreature.armeNaturelle(rollData.competence);
}
static getCategories() {
return categories;
}
/* -------------------------------------------- */
static armeNaturelle(competencecreature) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(competencecreature)) {
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
let arme = (competencecreature instanceof Item) ? competencecreature.clone(): competencecreature;
mergeObject(arme.system,
static setRollDataCreature(rollData) {
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
rollData.competence.system.defaut_carac = "carac_creature"
rollData.selectedCarac = rollData.carac.carac_creature
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
}
/* -------------------------------------------- */
static armeCreature(item) {
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
if (categorieAttaque != undefined) {
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
let arme = item.clone();
mergeObject(arme,
{
competence: arme.name,
initiative: RdDCombatManager.calculInitiative(competencecreature.system.niveau, competencecreature.system.carac_value),
niveau: competencecreature.system.niveau,
equipe: true,
resistance: 100,
dommagesReels: arme.system.dommages,
penetration: 0,
force: 0,
rapide: true,
cac: competencecreature.system.isnaturelle ? "naturelle" : "",
action: 'attaque'
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: arme.name,
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
niveau: item.system.niveau,
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
equipe: true,
resistance: 100,
dommagesReels: arme.system.dommages,
penetration: 0,
force: 0,
rapide: true,
}
});
return arme;
}
console.error("RdDItemCompetenceCreature.toActionArme(", competencecreature, ") : impossible de transformer l'Item en arme");
return undefined;
}
/* -------------------------------------------- */
static isCompetenceAttaque(item) {
return item.type == 'competencecreature' && item.system.iscombat;
if (item.type == TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
return true
}
}
return undefined
}
static getCategorieAttaque(item) {
if (item.type == TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
case "possession":
case "parade":
return item.system.categorie
}
}
return undefined
}
static isDommages(item) {
if (item.type == TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "tir":
case "lancer":
case "naturelle":
return true
}
}
return false
}
static isParade(item) {
if (item.type == TYPES.competencecreature) {
switch (item.system.categorie) {
case "melee":
case "naturelle":
case "parade":
return true
}
}
return false
}
/* -------------------------------------------- */
static isCompetenceParade(item) {
return item.type == 'competencecreature' && item.system.categorie_parade !== "";

View File

@ -1,67 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -17,7 +17,7 @@ const MONNAIE_ARGENT = {
system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" }
};
const MONNAIE_OR = {
name: "Dreagon (or)", type: 'monnaie',
name: "Dragon (or)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" }
};
@ -62,6 +62,13 @@ export class Monnaie {
return deniers;
}
static toSolsDeniers(fortune) {
return {
sols: Math.floor(fortune),
deniers: Math.round(100 * (fortune - Math.floor(fortune)))
};
}
static getFortune(monnaies) {
return (monnaies??[])
.map(m => Number(m.system.cout) * Number(m.system.quantite))

View File

@ -5,11 +5,14 @@ import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDGemme } from "./rdd-gemme.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
import { SYSTEM_RDD } from "./constants.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { Misc } from "./misc.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
import { TYPES } from "./item.js";
/**
* Extend the basic ItemSheet for RdD specific items
@ -85,33 +88,32 @@ export class RdDItemSheet extends ItemSheet {
/* -------------------------------------------- */
async getData() {
let formData = {
id: this.item.id,
title: this.item.name,
id: this.item.id,
type: this.item.type,
img: this.item.img,
name: this.item.name,
system: this.item.system,
isGM: game.user.isGM,
actorId: this.actor?.id,
isOwned: this.actor ? true : false,
owner: this.item.isOwner,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
isSoins: false,
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
isComestible: this.item.isComestible()
isComestible: this.item.getUtilisationCuisine(),
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable)
}
if (this.item.type == TYPES.competencecreature) {
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
}
const competences = await SystemCompendiums.getCompetences(this.actor?.type);
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
const competences = await SystemCompendiums.getCompetences('personnage');
formData.categories = this.item.getCategories()
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["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
formData.competences = competences;
}
if (this.item.type == 'arme') {
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it));
formData.competences = competences.filter(it => it.isCompetenceArme())
}
if (['sort', 'sortreserve'].includes(this.item.type)) {
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
@ -135,18 +137,14 @@ export class RdDItemSheet extends ItemSheet {
RdDGemme.calculDataDerivees(this.item);
}
if (this.item.type == 'potion') {
if (this.dateUpdated) {
formData.system.prdate = this.dateUpdated;
this.dateUpdated = undefined;
}
await RdDHerbes.updatePotionData(formData);
await RdDHerbes.addPotionFormData(formData);
}
if (formData.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
if (formData.options.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
formData.isIngredientPotionBase = true;
}
if (this.item.type == 'sortreserve') {
const sortId = this.item.system.sortid;
formData.sort = formData.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
}
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
@ -159,8 +157,10 @@ export class RdDItemSheet extends ItemSheet {
super.activateListeners(html);
this.html = html;
HtmlUtility._showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.item.isOwned);
HtmlUtility._showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionnelles.isUsing('afficher-prix-joueurs')
|| game.user.isGM
|| !this.item.isOwned);
HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
@ -185,15 +185,18 @@ export class RdDItemSheet extends ItemSheet {
}
})
this.html.find('.enchanteDate').change((event) => {
let jour = Number(this.html.find('[name="splitDate.day"]').val());
let mois = this.html.find('[name="splitDate.month"]').val();
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
this.html.find('.date-enchantement').change((event) => {
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val());
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure);
this.item.update({ 'system.prdate': indexDate });
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
});
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item));
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).actionHerbe(this.item));
this.html.find('input[name="system.cacher_points_de_tache"]').change(async event => await this.item.update({ 'system.cacher_points_de_tache': event.currentTarget.checked }));
this.html.find('.alchimie-tache a').click((event) => {
let actor = this._getEventActor(event);
@ -207,12 +210,38 @@ export class RdDItemSheet extends ItemSheet {
}
});
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, async () => this.render(true)));
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, async () => this.render(true)));
if (this.actor) {
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem()));
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem()));
this.html.find('.item-quantite-plus').click(async event => {
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1)
this.render();
});
this.html.find('.item-quantite-moins').click(async event => {
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1)
this.render();
});
}
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: duplicate(timestamp) })
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp);
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp);
}
getActionRenderItem() {
return async () => {
let item = this.item;
while (item) {
await item.sheet?.render()
item = this.actor.getContenant(item)
}
}
}
_getEventActor(event) {
@ -221,12 +250,14 @@ export class RdDItemSheet extends ItemSheet {
return actor;
}
/* -------------------------------------------- */
async _onSelectCategorie(event) {
event.preventDefault();
if (this.item.isCompetence()) {
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
const categorie = event.currentTarget.value;
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.getCategories());
this.item.system.base = level;
this.html.find('[name="system.base"]').val(level);
}
@ -237,9 +268,8 @@ export class RdDItemSheet extends ItemSheet {
_updateObject(event, formData) {
if (this.item.type == 'sort') {
// Données de bonus de cases ?
formData['system.bonuscase'] = RdDItemSort.buildBonusCaseStringFromFormData(formData.bonusValue, formData.caseValue);
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue);
}
return this.item.update(formData);
}

View File

@ -1,4 +1,3 @@
/* -------------------------------------------- */
import { Misc } from "./misc.js";
import { TMRUtility } from "./tmr-utility.js";
@ -14,9 +13,9 @@ export class RdDItemSort extends Item {
static isCoutVariable(sort) {
return sort && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0);
}
/* -------------------------------------------- */
static setCoutReveReel(sort){
static setCoutReveReel(sort) {
if (sort) {
sort.system.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.system.ptreve;
}
@ -25,94 +24,91 @@ export class RdDItemSort extends Item {
/* -------------------------------------------- */
static getDifficulte(sort, variable) {
if (sort && !RdDItemSort.isDifficulteVariable(sort)) {
return Misc.toInt(sort.system.difficulte);
return Misc.toInt(sort.system.difficulte);
}
return variable;
}
/* -------------------------------------------- */
static buildBonusCaseList( caseBonusString, newCase ) {
if (caseBonusString == undefined) {
return [];
}
let bonusCaseList = [];
let bonusCaseArray = caseBonusString == undefined ? [] : caseBonusString.split(',');
for( let bonusCase of bonusCaseArray) {
let bonusSplit = bonusCase.split(':');
bonusCaseList.push( { case: bonusSplit[0], bonus: bonusSplit[1] } );
}
if ( newCase )
bonusCaseList.push( {case: "Nouvelle", bonus: 0} );
return bonusCaseList;
static buildBonusCaseList(bonuscase, newCase) {
const list = RdDItemSort._bonuscaseStringToList(bonuscase)
if (newCase) {
return list.concat({ case: "Nouvelle", bonus: 0 });
}
/* -------------------------------------------- */
return list;
}
/**
* Retourne une liste de bonus/case pour un item-sheet
* @param {} item
*/
static getBonusCaseList( item, newCase = false ) {
static getBonusCaseList(item, newCase = false) {
// Gestion spéciale case bonus
if ( item.type == 'sort') {
return this.buildBonusCaseList(item.system.bonuscase, newCase );
if (item.type == 'sort') {
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
}
return undefined;
}
/* -------------------------------------------- */
/** Met à jour les données de formulaire
* si static des bonus de cases sont présents
* */
static buildBonusCaseStringFromFormData( bonuses, cases ) {
if ( bonuses ) {
let list = [];
let caseCheck = {};
for (let i=0; i<bonuses.length; i++) {
let coord = cases[i]?.toUpperCase() || 'A1';
let bonus = bonuses[i] || 0;
if ( TMRUtility.verifyTMRCoord( coord ) && bonus > 0 && caseCheck[coord] == undefined ) {
static buildBonuscaseFromArrays(bonuses, coords) {
if (bonuses) {
const list = [];
const caseCheck = {};
for (let i = 0; i < bonuses.length && i < coords.length; i++) {
const coord = coords[i] == 'Fleuve' ? 'Fleuve' : (coords[i]?.toUpperCase() ?? 'A1');
const bonus = bonuses[i] || 0;
if (TMRUtility.verifyTMRCoord(coord) && bonus > 0 && caseCheck[coord] == undefined) {
caseCheck[coord] = bonus;
list.push( coord+":"+bonus );
list.push({ case: coord, bonus: bonus });
}
}
return list.toString();
return RdDItemSort._bonuscaseListToString(list);
}
return undefined;
}
/* -------------------------------------------- */
static incrementBonusCase( actor, sort, coord ) {
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false);
//console.log("ITEMSORT", sort, bonusCaseList);
let found = false;
let StringList = [];
for( let bc of bonusCaseList) {
if (bc.case == coord) { // Case existante
found = true;
bc.bonus = Number(bc.bonus) + 1;
}
StringList.push( bc.case+':'+bc.bonus );
}
if ( !found) { //Nouvelle case, bonus de 1
StringList.push(coord+':1');
}
// Sauvegarde/update
let bonuscase = StringList.toString();
//console.log("Bonus cae :", bonuscase);
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }] );
}
/* -------------------------------------------- */
static getCaseBonus( sort, coord) {
let bonusCaseList = this.buildBonusCaseList(sort.system.bonuscase, false);
for( let bc of bonusCaseList) {
if (bc.case == coord) { // Case existante
return Number(bc.bonus);
}
static incrementBonusCase(actor, sort, coord) {
if (TMRUtility.getTMR(coord).type == "fleuve") {
coord = 'Fleuve';
}
return 0;
const list = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false);
const bonus = Number(list.find(it => it.case == coord)?.bonus ?? 0);
const modified = { case: coord, bonus: bonus + 1 };
const bonuscase = RdDItemSort._bonuscaseListToString(
list.filter(it => it.case != coord).concat(modified)
);
// Sauvegarde/update
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
}
/* -------------------------------------------- */
static getCaseBonus(sort, coord) {
const isFleuve = TMRUtility.getTMR(coord).type == "fleuve";
let bc = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false)
.filter(it => it.case == coord || (isFleuve && it.case == 'Fleuve'))
.find(it => true)
return Number(bc?.bonus ?? 0);
}
static _bonuscaseListToString(list) {
return list.map(it => `${it.case}:${it.bonus}`)
.sort(Misc.ascending())
.join(',');
}
static _bonuscaseStringToList(bonuscase) {
return (bonuscase ?? '').split(',').map(it => {
const b = it.split(':');
return { case: b[0], bonus: b[1] };
});
}
}

View File

@ -1,4 +0,0 @@
export class RdDItemTache extends Item {
}

View File

@ -2,34 +2,88 @@ import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDUtility } from "./rdd-utility.js";
import { SystemCompendiums } from "./settings/system-compendiums.js";
import { RdDRaretes } from "./item/raretes.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
export const TYPES = {
competence: 'competence',
competencecreature: 'competencecreature',
empoignade: 'empoignade',
possession: 'possession',
blessure: 'blessure',
maladie: 'maladie',
poison: 'poison',
arme: 'arme',
armure: 'armure',
conteneur: 'conteneur',
objet: 'objet',
monnaie: 'monnaie',
gemme: 'gemme',
munition: 'munition',
nourritureboisson: 'nourritureboisson',
herbe: 'herbe',
plante: 'plante',
ingredient: 'ingredient',
faune: 'faune',
livre: 'livre',
potion: 'potion',
service: 'service',
musique: 'musique',
danse: 'danse',
chant: 'chant',
jeu: 'jeu',
recettecuisine: 'recettecuisine',
oeuvre: 'oeuvre',
recettealchimique: 'recettealchimique',
tache: 'tache',
sort: 'sort',
sortreserve: 'sortreserve',
rencontre: 'rencontre',
queue: 'queue',
ombre: 'ombre',
souffle: 'souffle',
tete: 'tete',
casetmr: 'casetmr',
meditation: 'meditation',
signedraconique: 'signedraconique',
tarot: 'tarot',
nombreastral: 'nombreastral',
extraitpoetique: 'extraitpoetique',
}
const typesInventaireMateriel = [
"arme",
"armure",
"conteneur",
"faune",
"gemme",
"herbe",
"ingredient",
"livre",
"monnaie",
"munition",
"nourritureboisson",
"objet",
"potion",
TYPES.arme,
TYPES.armure,
TYPES.conteneur,
TYPES.faune,
TYPES.gemme,
TYPES.herbe,
TYPES.plante,
TYPES.ingredient,
TYPES.livre,
TYPES.monnaie,
TYPES.munition,
TYPES.nourritureboisson,
TYPES.objet,
TYPES.potion,
]
const typesInventaire = {
materiel: typesInventaireMateriel,
all: ['service'].concat(typesInventaireMateriel),
}
const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"]
const typesObjetsDraconiques = ["queue", "ombre", "souffle", "tete", "signedraconique", "sortreserve", "rencontre"]
const typesObjetsConnaissance = ["meditation", "recettealchimique", "sort"]
const typesObjetsEffet = ["possession", "poison", "maladie"]
const typesObjetsCompetence = ["competence", "competencecreature"]
const typesObjetsOeuvres = [TYPES.oeuvre, TYPES.recettecuisine, TYPES.musique, TYPES.chant, TYPES.danse, TYPES.jeu]
const typesObjetsDraconiques = [TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.tete, TYPES.signedraconique, TYPES.sortreserve, TYPES.rencontre]
const typesObjetsConnaissance = [TYPES.meditation, TYPES.recettealchimique, TYPES.sort]
const typesObjetsEffet = [TYPES.possession, TYPES.poison, TYPES.maladie, TYPES.blessure]
const typesObjetsCompetence = [TYPES.competence, TYPES.competencecreature]
const typesObjetsTemporels = [TYPES.blessure, TYPES.poison, TYPES.maladie, TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.signedraconique, TYPES.rencontre]
const typesObjetsEquipable = [TYPES.arme, TYPES.armure, TYPES.objet];
const typesEnvironnement = typesInventaireMateriel;
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
densité 3.5 (~2.3 à 4, parfois plus) -- https://www.juwelo.fr/guide-des-pierres/faits-et-chiffres/
@ -70,11 +124,16 @@ export const defaultItemImg = {
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",
empoignade: "systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp"
}
/* -------------------------------------------- */
export class RdDItem extends Item {
static get defaultIcon() {
return undefined;
}
static getDefaultImg(itemType) {
return game.system.rdd.itemClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
}
@ -82,12 +141,12 @@ export class RdDItem extends Item {
static isFieldInventaireModifiable(type, field) {
switch (field) {
case 'quantite':
if (['conteneur'].includes(type)) {
if ([TYPES.conteneur].includes(type)) {
return false;
}
break;
case 'cout':
if (['monnaie'].includes(type)) {
if ([TYPES.monnaie].includes(type)) {
return game.user.isGM;
}
break;
@ -105,6 +164,12 @@ export class RdDItem extends Item {
static getItemTypesInventaire(mode = 'materiel') {
return typesInventaire[mode ?? 'materiel']
}
static getItemTypesDraconiques() {
return typesObjetsDraconiques;
}
static getItemTypesEnvironnement() {
return typesEnvironnement;
}
static getTypesOeuvres() {
return typesObjetsOeuvres
@ -127,48 +192,101 @@ export class RdDItem extends Item {
super(docData, context);
}
static get defaultIcon() {
return undefined;
}
getUniteQuantite() {
switch (this.type) {
case "monnaie": return "(Pièces)"
case "herbe":
case TYPES.monnaie: return "(Pièces)"
case TYPES.herbe:
switch (this.system.categorie) {
case 'Alchimie': case 'Repos': case 'Soin':
return "(Brins)"
case 'Cuisine': return '';
}
return '';
case "ingredient": return "(Pépins ou Brins)"
case TYPES.ingredient: return "(Pépins ou Brins)"
}
return '';
}
isCompetencePersonnage() { return this.type == 'competence' }
isCompetenceCreature() { return this.type == 'competencecreature' }
isConteneur() { return this.type == 'conteneur'; }
isMonnaie() { return this.type == 'monnaie'; }
isNourritureBoisson() { return this.type == 'nourritureboisson'; }
isService() { return this.type == 'service'; }
isCompetence() {
return typesObjetsCompetence.includes(this.type)
isEquipable() {
return typesObjetsEquipable.includes(this.type)
}
isInventaire(mode = 'materiel') {
return RdDItem.getItemTypesInventaire(mode).includes(this.type);
isCompetencePersonnage() { return this.type == TYPES.competence }
isCompetenceCreature() { return this.type == TYPES.competencecreature }
isConteneur() { return this.type == TYPES.conteneur; }
isMonnaie() { return this.type == TYPES.monnaie; }
isPotion() { return this.type == TYPES.potion; }
isNourritureBoisson() { return this.type == TYPES.nourritureboisson; }
isService() { return this.type == TYPES.service; }
isCompetence() { return typesObjetsCompetence.includes(this.type) }
isEsquive() {
return (this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, 'Esquive'));
}
isOeuvre() {
return typesObjetsOeuvres.includes(this.type)
isCorpsACorps() {
return this.isCompetence()
&& this.system.categorie == 'melee'
&& Grammar.includesLowerCaseNoAccent(this.name, 'Corps à Corps')
}
isDraconique() {
return typesObjetsDraconiques.includes(this.type)
isCompetenceArme() {
return this.isCompetence() && [ 'melee','tir', 'lancer'].includes(this.system.categorie)
}
isEffet() {
return typesObjetsEffet.includes(this.type)
isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" }
isTemporel() { return typesObjetsTemporels.includes(this.type) }
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
isQueueDragon() { return [TYPES.queue, TYPES.ombre].includes(this.type) }
isEffet() { return typesObjetsEffet.includes(this.type) }
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
isHerbeAPotion() { return this.type == TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
isBlessure() { return this.type == TYPES.blessure }
isPresentDansMilieux(milieux) {
return this.getEnvironnements(milieux).length > 0
}
isConnaissance() {
return typesObjetsConnaissance.includes(this.type)
getCategories() {
switch (this.type) {
case TYPES.competence: return RdDItemCompetence.getCategories()
case TYPES.competencecreature: return RdDItemCompetenceCreature.getCategories()
}
return {}
}
getEnvironnements(milieux = undefined) {
const environnements = this.isInventaire() ? this.system.environnement : undefined;
if (milieux == undefined || !environnements) {
return environnements ?? [];
}
return environnements.filter(env => milieux.includes(env.milieu))
}
getMilieux() {
return this.getEnvironnements().map(env => env.milieu);
}
getRaretes(milieux = undefined) {
if (this.isInventaire()) {
const raretes = this.getEnvironnements(milieux).map(env => RdDRaretes.byCode(env.rarete));
if (milieux == undefined && raretes.length == 0) {
return [RdDRaretes.rareteFrequente()];
}
return raretes;
}
return [RdDRaretes.rareteEgale()];
}
getFrequence(milieux = undefined) {
const frequences = this.getEnvironnements(milieux).map(it => it.frequence);
return frequences.length == 0 ? 0 : Math.max(...frequences);
}
getItemGroup() {
@ -181,65 +299,128 @@ export class RdDItem extends Item {
return "autres";
}
isConteneurNonVide() {
return this.isConteneur() && (this.system.contenu?.length ?? 0) > 0;
isConteneurNonVide() { return this.isConteneur() && (this.system.contenu?.length ?? 0) > 0; }
isConteneurVide() { return this.isConteneur() && (this.system.contenu?.length ?? 0) == 0; }
isVideOuNonConteneur() { return !this.isConteneur() || (this.system.contenu?.length ?? 0) == 0; }
isFinPeriode(oldTimestamp, newTimestamp) {
if (!this.isTemporel()) {
return false;
}
const finPeriode = new RdDTimestamp(this.system.temporel.fin);
return oldTimestamp.compare(finPeriode) < 0 && finPeriode.compare(newTimestamp) <= 0
}
isConteneurVide() {
return this.isConteneur() && (this.system.contenu?.length ?? 0) == 0;
async onCreateItemTemporel(actor) {
if (this.isTemporel()) {
const timestampDebut = game.system.rdd.calendrier.timestamp;
const timestampFin = await this.calculerFinPeriodeTemporel(timestampDebut);
await actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
'system.temporel.debut': duplicate(timestampDebut),
'system.temporel.fin': duplicate(timestampFin),
}])
}
}
isVideOuNonConteneur() {
return !this.isConteneur() || (this.system.contenu?.length ?? 0) == 0;
async calculerFinPeriodeTemporel(timestampDebut) {
return timestampDebut;
}
isComestible() {
async onFinPeriodeTemporel(oldTimestamp, newTimestamp) {
if (this.isTemporel() && this.actor) {
await this.onFinPeriode(oldTimestamp, newTimestamp);
}
}
async onFinPeriode(oldTimestamp, newTimestamp) {
console.log(`${this.actor.name}: l'objet ${this.name} a expiré et été supprimé`);
await this.actor?.deleteEmbeddedDocuments('Item', [this.id]);
}
getUtilisation() {
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' : '';
case TYPES.potion:
switch (this.system.categorie) {
case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie'
case 'Cuisine': return 'cuisine'
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins'
}
return '';
case TYPES.nourritureboisson: return 'cuisine';
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
switch (this.system.categorie) {
case 'Cuisine': return 'cuisine';
case 'Toxique': case 'Poison': return 'poison';
case 'Alchimie': return 'alchimie'
case 'Soin': case 'Repos': return 'soins'
}
return this.system.sust > 0 ? 'cuisine' : '';
}
return '';
}
isAlcool() {
return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise;
getUtilisationCuisine() {
if (this.getUtilisation() == 'cuisine') {
switch (this.type) {
case TYPES.nourritureboisson:
return 'pret';
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
return 'brut';
}
}
return '';
}
isHerbeAPotion() {
return this.type == 'herbe' && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos');
}
isPotion() {
return this.type == 'potion';
}
isCristalAlchimique() {
return this.type == 'objet' && Grammar.toLowerCaseNoAccent(this.name) == 'cristal alchimique' && this.system.quantite > 0;
return this.type == TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
}
isMagique() {
return this.system.magique
}
isItemCommerce() {
return this.parent?.type == 'commerce';
}
isNomLike(texte) {
return Grammar.includesLowerCaseNoAccent(this.name, texte)
}
isNomTypeLike(texte) {
return this.isNomLike(texte) || Grammar.includesLowerCaseNoAccent(Misc.typeName(this.type, 'Item'), texte)
}
getQuantite() {
return Math.round(this.system.quantite ?? 0)
return this.isService() ? undefined : Math.round(this.system.quantite ?? 0)
}
getEncTotal() {
return this.getEnc() * this.getQuantite();
return (this.getQuantite() ?? 0) * this.getEnc();
}
getEnc() {
switch (this.type) {
case 'herbe':
case TYPES.service:
return 0;
case TYPES.herbe:
return this.getEncHerbe();
case 'gemme':
case TYPES.gemme:
return encPepin * this.system.taille;
}
return Math.max(this.system.encombrement ?? 0, 0);
}
getEncContenu() {
return this.getContenu()
.map(it => it.getRecursiveEnc())
.reduce(Misc.sum(), 0);
}
getRecursiveEnc() {
return this.getEncTotal() + this.getEncContenu()
}
getEncHerbe() {
switch (this.system.categorie) {
case 'Repos': case 'Soin': case 'Alchimie':
@ -249,8 +430,20 @@ export class RdDItem extends Item {
}
getContenu() {
if (this.isConteneur()) {
return this.system.contenu.map(idContenu => this.actor.getItem(idContenu));
}
return []
}
isConteneurContenu(conteneur) {
return this.getContenu()
.find(it => it.id == conteneur.id || it.isConteneurContenu(conteneur))
}
valeurTotale() {
return this.getQuantite() * this.valeur()
return (this.isService() ? 1 : this.getQuantite()) * this.valeur()
}
valeur() {
@ -258,7 +451,7 @@ export class RdDItem extends Item {
}
calculerPrixCommercant() {
if (this.parent?.type == 'commerce') {
if (this.isItemCommerce()) {
// appliquer le pourcentage
return this.parent.calculerPrix(this);
}
@ -274,6 +467,7 @@ export class RdDItem extends Item {
}
this.system.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
}
this.equipable = this.isEquipable();
}
prepareDataPotion() {
@ -289,19 +483,19 @@ export class RdDItem extends Item {
getActionPrincipale(options = { warnIfNot: true }) {
switch (this.type) {
case 'conteneur': return 'Ouvrir';
case TYPES.conteneur: return 'Ouvrir';
}
if (this.actor?.isPersonnage()) {
const warn = options.warnIfNot;
if (this.isComestible() == 'brut') {
return 'Utiliser';
if (this.getUtilisationCuisine() == 'brut') {
return 'Cuisiner';
}
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;
case TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
case TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn);
case TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
case TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
case TYPES.queue: case TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
}
}
return undefined;
@ -309,19 +503,8 @@ export class RdDItem extends Item {
/* -------------------------------------------- */
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);
}
if (!this.getActionPrincipale()) { return }
await actor?.actionPrincipale(this, onActionItem);
}
_actionOrWarnQuantiteZero(actionName, warn) {
@ -342,7 +525,7 @@ export class RdDItem extends Item {
}
async onCreateDecoupeComestible(actor) {
if (actor && this.isComestible() == 'brut' && this.system.sust != 1) {
if (actor && this.getUtilisationCuisine() == 'brut' && this.system.sust != 1) {
if (this.system.sust < 1) {
await actor.updateEmbeddedDocuments('Item', [{
_id: this.id,
@ -363,7 +546,7 @@ export class RdDItem extends Item {
}
async empiler(item) {
if (this.isComestible() == 'brut') {
if (this.getUtilisationCuisine() == 'brut') {
const sust = this.system.sust + item.system.sust;
const encombrement = this.system.encombrement + item.system.encombrement;
await this.update({
@ -414,8 +597,8 @@ export class RdDItem extends Item {
return [false, `Impossible de regrouper ${this.name} avec ${other.name}`];
}
else {
const excludedProperties = ['quantite', 'cout', 'encTotal', 'environnement'];
if (this.isComestible()) {
const excludedProperties = ['quantite', 'cout', 'encTotal', 'environnement', 'contenu'];
if (this.getUtilisationCuisine()) {
excludedProperties.push('sust', 'encombrement');
}
let differences = Object.entries(this.system)
@ -519,7 +702,7 @@ export class RdDItem extends Item {
_armeChatData() {
return [
`<b>Compétence</b>: ${this.system.competence}`,
`<b>Dommages</b>: ${this.system.dommages}`,
`<b>Dommages</b>: ${this.system.dommages} ${this.system.mortalite == 'non-mortel' ? '(Non mortel)' : ''}`,
`<b>Force minimum</b>: ${this.system.force}`,
`<b>Resistance</b>: ${this.system.resistance}`,
...this._inventaireTemplateChatData()
@ -604,7 +787,7 @@ export class RdDItem extends Item {
`<b>Périodicité</b>: ${this.system.periodicite}`,
`<b>Fatigue</b>: ${this.system.fatigue}`,
`<b>Difficulté</b>: ${this.system.difficulte}`,
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, !this.system.cacher_points_de_tache),
`<b>Points de Tâche atteints</b>: ${this.system.points_de_tache_courant}`]
}
/* -------------------------------------------- */
@ -613,7 +796,7 @@ export class RdDItem extends Item {
`<b>Compétence</b>: ${this.system.competence}`,
`<b>Auteur</b>: ${this.system.auteur}`,
`<b>Difficulté</b>: ${this.system.difficulte}`,
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, this.system.cacher_points_de_tache),
RdDItem.propertyIfDefined('Points de Tâche', this.system.points_de_tache, !this.system.cacher_points_de_tache),
...this._inventaireTemplateChatData()
]
}

51
module/item/armure.js Normal file
View File

@ -0,0 +1,51 @@
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
export class RdDItemArmure extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp";
}
deteriorerArmure(dmg) {
if (!ReglesOptionnelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
return;
}
let deterioration = (this.system.deterioration ?? 0) + dmg;
let protection = this.system.protection;
if (deterioration >= 10) {
deterioration -= 10;
protection = this.calculProtectionDeterioree();
ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` });
}
this.update({
system: {
deterioration: deterioration,
protection: protection
}
});
}
calculProtectionDeterioree() {
const protectionCourante = this.system.protection;
let res = /(\d+)?d(\d+)(\-\d+)?/.exec(protectionCourante);
if (res) {
let protection = Misc.toInt(res[2]);
let malus = Misc.toInt(res[3]) - 1;
if (protection + malus <= 0) {
return 0;
} else {
return `1d${protection}${malus}`;
}
}
else if (/\d+/.exec(protectionCourante)) {
return `1d${protectionCourante}`;
}
else {
ui.notifications.warn(`La valeur d'armure de votre ${this.name} est incorrecte`);
return undefined;
}
}
}

202
module/item/blessure.js Normal file
View File

@ -0,0 +1,202 @@
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
const BASE_TACHE_SOIN_BLESSURE = {
type: "tache",
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_chirurgie.webp',
system: { carac: "dexterite", competence: "Chirurgie", periodicite: "1 round", fatigue: 0, }
}
const TACHES_SOIN_BLESSURE = {
6: { name: 'Blessure critique', system: { difficulte: -6, points_de_tache: 6 } },
4: { name: 'Blessure grave', system: { difficulte: -4, points_de_tache: 4 } },
2: { name: 'Blessure légère', system: { difficulte: -2, points_de_tache: 2 } },
}
const definitionsBlessures = [
{ type: "contusion", gravite: 0, label: 'Contusion/éraflure', max: 100, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/eraflure.webp" },
{ type: "legere", gravite: 2, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "grave", gravite: 4, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "critique", gravite: 6, label: 'Critique', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
{ type: "mort", gravite: 8, label: 'Mort', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/mort.webp" }
]
export class RdDItemBlessure extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp";
}
prepareDerivedData() {
super.prepareDerivedData();
this.system.label = this.getLabelGravite()
}
static prepareTacheSoin(gravite) {
const tache = TACHES_SOIN_BLESSURE[gravite]
if (!tache) {
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
return undefined;
}
return mergeObject(duplicate(BASE_TACHE_SOIN_BLESSURE), tache)
}
static async createBlessure(actor, gravite, localisation = '', attacker) {
const definition = RdDItemBlessure.getDefinition(gravite)
const blessure = {
name: definition.label,
type: 'blessure',
img: definition.icon,
system: {
gravite: gravite,
difficulte: - gravite,
localisation: localisation,
origine: attacker?.name ?? ""
}
}
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
return blessures[0]
}
static async createTacheSoinBlessure(actor, gravite) {
const tache = RdDItemBlessure.prepareTacheSoin(gravite)
if (tache) {
const taches = await actor.createEmbeddedDocuments('Item', [tache], { renderSheet: false });
return taches[0];
}
return undefined
}
async updateTacheSoinBlessure(tache) {
if (tache) {
await tache.update({
system: {
itemId: this.id,
difficulte: Math.min(this.system.difficulte, tache.system.difficulte),
points_de_tache_courant: Math.max(0, this.system.premierssoins.tache)
}
});
}
}
async setSoinsBlessure(systemUpdate = {}) {
systemUpdate = mergeObject(systemUpdate, this.system, { overwrite: false }),
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
await this.update({
img: this.getImgSoins(systemUpdate.gravite, systemUpdate.soinscomplets.done),
system: systemUpdate
});
}
async recuperationBlessure({ actor, timestamp, message, isMaladeEmpoisonne, blessures }) {
if (this.parent != actor || actor == undefined) {
return
}
if (new RdDTimestamp(this.system.temporel.fin).compare(timestamp) > 0) {
// attente periode
return
}
if (this.system.gravite > 0) {
const update = { system: { premierssoins: { bonus: 0 }, soinscomplets: { bonus: 0 } } }
const gravite = this.system.gravite;
const graviteMoindre = gravite - 2;
const moindres = blessures.filter(it => it.system.gravite == graviteMoindre, 'blessures').length
const label = this.getLabelGravite();
let rolled = await actor.jetRecuperationConstitution(this.system.soinscomplets.bonus, message);
if (rolled.isETotal) {
message.content += ` -- une blessure ${label} s'infecte (temps de guérison augmenté de ${gravite} jours, perte de vie)`;
await actor.santeIncDec("vie", -1);
mergeObject(update, {
system: { fin: { indexDate: timestamp.addJours(gravite).indexDate } }
});
}
else {
if (!isMaladeEmpoisonne && rolled.isSuccess && this.peutRetrograder(graviteMoindre, moindres)) {
message.content += ` -- une blessure ${label} cicatrise`;
mergeObject(update, {
system: {
gravite: graviteMoindre,
temporel: { fin: { indexDate: timestamp.addJours(graviteMoindre).indexDate } }
}
});
}
else {
message.content += ` -- une blessure ${label} reste stable`;
}
}
await this.update(update);
}
}
peutRetrograder(graviteMoindre, moindres) {
return moindres < RdDItemBlessure.getDefinition(graviteMoindre).max
}
async calculerFinPeriodeTemporel(debut) {
return await debut.nouveauJour().addJours(this.system.gravite);
}
async onFinPeriode(oldTimestamp, newTimestamp) {
if (this.system.gravite <= 0) {
await super.onFinPeriode(oldTimestamp, newTimestamp)
}
}
getImgSoins(gravite, soins) {
let img = 'blessure'
if (gravite > 6) {
img = 'mort'
}
if (gravite <= 0) {
img = 'eraflure'
}
return `systems/foundryvtt-reve-de-dragon/icons/sante/${soins ? 'blessure-soins' : img}.webp`
}
getLabelGravite() {
return RdDItemBlessure.getDefinition(this.system.gravite).label
}
static getDefinition(gravite) {
return definitionsBlessures.sort(Misc.ascending(it => it.gravite))
.find(it => it.gravite >= gravite);
}
static maxBlessures(gravite) {
return RdDItemBlessure.getDefinition(gravite).max
}
isContusion() {
return this.system.gravite <= 0
}
isLegere() {
return this.system.gravite > 0 && this.system.gravite <= 2
}
isGrave() {
return this.system.gravite > 2 && this.system.gravite <= 4
}
isCritique() {
return this.system.gravite > 4 && this.system.gravite <= 6
}
isMort() {
return this.system.gravite > 6
}
getProprietes() {
return [
RdDItem.propertyIfDefined('Causée par', this.system.origine, this.system.origine),
`<b>Heure et Date</b>: ${new RdDTimestamp(this.system.temporel.debut).formatDateHeure()}`,
RdDItem.propertyIfDefined('Blessé', this.parent?.name, this.parent),
`<b>Localisation</b>: ${this.system.localisation}`,
`<b>Gravité</b>: ${RdDItemBlessure.getDefinition(this.system.gravite).label}`,
`<b>Difficulté des soins</b>: ${this.system.difficulte}`,
(this.system.soinscomplets.done ?
`<b>Bonus soins complets</b>: ${this.system.soinscomplets.bonus}` :
(this.system.premierssoins.done ?
`<b>Bonus premiers soins</b>: ${this.system.premierssoins.bonus}` :
`<b>Points de tâche</b>: ${this.system.premierssoins.tache}`
)
),
];
}
}

47
module/item/maladie.js Normal file
View File

@ -0,0 +1,47 @@
import { RdDItem } from "../item.js";
import { Misc } from "../misc.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
export class RdDItemMaladie extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
}
async onFinPeriode(oldTimestamp, newTimestamp) {
await RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
}
static async notifierMaladiePoison(mal, oldTimestamp, newTimestamp) {
if (mal.actor) {
const souffrance = mal.system.identifie
? `de ${mal.name}`
: `d'un mal inconnu`
ChatMessage.create({ content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !` });
mal.postItemToChat('gmroll');
await RdDItemMaladie.prolongerPeriode(mal,oldTimestamp, newTimestamp);
}
}
static async prolongerPeriode(mal, oldTimestamp, newTimestamp) {
if (mal.actor) {
// TODO: déterminer le nombre de périodes écoulées
console.log(`${mal.actor.name}: le mal ${mal.name} a atteint la fin de sa période et été prolongé`);
const current = newTimestamp;
const finPeriode = new RdDTimestamp(mal.system.temporel.fin)
const periodeSuivante = (finPeriode.compare(current) > 0 ? finPeriode : current);
const timestampFin = await mal.calculerFinPeriodeTemporel(periodeSuivante);
await mal.actor.updateEmbeddedDocuments('Item', [{
_id: mal.id,
'system.temporel.fin': duplicate(timestampFin),
}])
}
}
}

11
module/item/ombre.js Normal file
View File

@ -0,0 +1,11 @@
import { RdDItem } from "../item.js";
export class RdDItemOmbre extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

17
module/item/poison.js Normal file
View File

@ -0,0 +1,17 @@
import { RdDItem } from "../item.js";
import { RdDItemMaladie } from "./maladie.js";
export class RdDItemPoison extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
}
async onFinPeriode(oldTimestamp, newTimestamp) {
RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
}
}

13
module/item/queue.js Normal file
View File

@ -0,0 +1,13 @@
import { RdDItem } from "../item.js";
export class RdDItemQueue extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

31
module/item/raretes.js Normal file
View File

@ -0,0 +1,31 @@
const RARETE_COMMUNE = { code: 'Commune', label: 'Commune', frequence: 54, min: 27, max: 108 };
const RARETE_FREQUENTE = { code: 'Frequente', label: 'Fréquente', frequence: 18, min: 9, max: 36 };
const RARETE_RARE = { code: 'Rare', label: 'Rare', frequence: 6, min: 3, max: 12 };
const RARETE_RARISSIME = { code: 'Rarissime', label: 'Rarissime', frequence: 2, min: 1, max: 4 };
const RARETE_INEXISTANT = { code: 'Inexistant', label: 'Inexistant', frequence: 0, min: 0, max: 0 };
const RARETE_EGALE = { code: 'eqal', label: 'Egal', frequence: 1, min: 1, max: 1 };
const RARETES = [
RARETE_COMMUNE,
RARETE_FREQUENTE,
RARETE_RARE,
RARETE_RARISSIME,
RARETE_INEXISTANT,
]
export class RdDRaretes {
static rareteFrequente() { return RARETE_FREQUENTE; }
static rareteEgale() { return RARETE_EGALE; }
static raretes() { return RARETES; }
static byCode(code = undefined) {
return RARETES.find(it => it.code == code) ?? RARETE_FREQUENTE;
}
static getChamp(rarete, field = undefined) {
return RdDRaretes.byCode(rarete)[field ?? 'frequence'];
}
}

View File

@ -1,4 +1,5 @@
import { EffetsRencontre } from "./effets-rencontres.js";
import { EffetsRencontre } from "../tmr/effets-rencontres.js";
import { RdDItem } from "../item.js";
const tableEffets = [
{ code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager },
@ -36,7 +37,11 @@ const tableEffets = [
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
];
export class RdDRencontre {
export class RdDRencontre extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp";
}
static getEffetsSucces() { return RdDRencontre.getEffets("succes"); }
static getEffetsEchec() { return RdDRencontre.getEffets("echec"); }
@ -68,4 +73,8 @@ export class RdDRencontre {
}
}
async calculerFinPeriodeTemporel(debut) {
return await debut.nouvelleHeure().addHeures(12);
}
}

View File

@ -1,4 +1,4 @@
import { RdDItem } from "./item.js";
import { RdDItem } from "../item.js";
export class RdDItemService extends RdDItem {

View File

@ -0,0 +1,120 @@
import { HtmlUtility } from "../html-utility.js";
import { RdDItemSheet } from "../item-sheet.js";
import { Misc } from "../misc.js";
import { RdDRaretes } from "./raretes.js";
const TYPE_ITEMS_NATURELS = ["faune", "herbe", "plante", "ingredient"];
export class RdDItemInventaireSheet extends RdDItemSheet {
static get defaultOptions() {
return mergeObject(RdDItemSheet.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
});
}
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 = await super.getData();
return mergeObject(formData, {
milieux: await game.system.rdd.environnement.autresMilieux(this.item)
});
}
activateListeners(html) {
super.activateListeners(html);
HtmlUtility.showControlWhen(this.html.find("div.description-milieu"), TYPE_ITEMS_NATURELS.includes(this.item.type));
if (!this.options.editable) return;
this.html.find("a.preparer-nourriture").click(event => this.preparerNourriture(event));
this.html.find("a.manger-nourriture").click(event => this.mangerNourriture(event));
this.html.find("input.input-selection-milieu").keypress(event => {
if (event.keyCode == '13') {
this.onAddMilieu(event);
}
event.stopPropagation();
})
this.html.find("a.milieu-add").click(event => this.onAddMilieu(event));
this.html.find("div.environnement-milieu a.milieu-delete").click(event => this.onDeleteMilieu(event));
this.html.find("div.environnement-milieu select.environnement-rarete").change(event => this.onChange(event,
updated => this.$changeRarete(event, updated)));
this.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => this.onChange(event,
updated => this.$changeFrequence(event, updated)));
}
async preparerNourriture(event) {
if (this.actor && this.item.getUtilisationCuisine() == 'brut') {
await this.actor.preparerNourriture(this.item);
}
}
async mangerNourriture(event) {
if (this.actor && this.item.getUtilisation() == 'cuisine') {
await this.actor.mangerNourriture(this.item);
}
}
$changeFrequence(event, updated) {
updated.frequence = Number(this.html.find(event.currentTarget).val());
}
$changeRarete(event, updated) {
const code = this.html.find(event.currentTarget).val();
const rarete = RdDRaretes.byCode(code);
updated.rarete = rarete.code;
updated.frequence = rarete.frequence;
}
async onAddMilieu(event) {
const milieu = this.html.find('input.input-selection-milieu').val();
if (!milieu) {
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${this.item.name}`);
return
}
const list = this.item.getEnvironnements();
const exists = list.find(it => it.milieu == milieu);
if (exists) {
ui.notifications.warn(`${this.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
return
}
const rarete = RdDRaretes.rareteFrequente();
const added = { milieu, rarete: rarete.code, frequence: rarete.frequence };
const newList = [added, ...list].sort(Misc.ascending(it => it.milieu))
await this.item.update({ 'system.environnement': newList })
}
async onDeleteMilieu(event) {
const milieu = this.$getEventMilieu(event);
if (milieu != undefined) {
const newList = this.item.getEnvironnements().filter(it => it.milieu != milieu)
.sort(Misc.ascending(it => it.milieu));
await this.item.update({ 'system.environnement': newList });
}
}
async onChange(event, doMutation) {
const list = this.item.system.environnement;
const milieu = this.$getEventMilieu(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 this.item.update({ 'system.environnement': newList });
}
}
$getEventMilieu(event) {
return this.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
}
}

View File

@ -0,0 +1,29 @@
import { RdDItemSheet } from "../item-sheet.js";
export class RdDBlessureItemSheet extends RdDItemSheet {
static get ITEM_TYPE() { return "blessure" };
async getData() {
const formData = await super.getData();
formData.disabled = formData.options.isGM || formData.options.isOwned ? '' : 'disabled';
return formData;
}
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
this.html.find('[name="premierssoins-done"]').change(async event => {
await this.item.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
});
this.html.find('[name="soinscomplets-done"]').change(async event => {
await this.item.setSoinsBlessure({ soinscomplets: { done: event.currentTarget.checked } })
});
this.html.find('[name="system-gravite"]').change(async event => {
const gravite = Number(event.currentTarget.value)
await this.item.setSoinsBlessure({ gravite: gravite, difficulte: - gravite })
});
}
}

View File

@ -1,8 +1,9 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDBaseActorSheet } from "../actor/base-actor-sheet.js";
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
import { RdDUtility } from "../rdd-utility.js";
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDConteneurItemSheet extends RdDItemSheet {
export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return "conteneur" };
@ -27,9 +28,8 @@ export class RdDConteneurItemSheet extends RdDItemSheet {
/* -------------------------------------------- */
prepareConteneurData(formData) {
RdDUtility.filterEquipementParType(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
}
@ -43,7 +43,8 @@ export class RdDConteneurItemSheet extends RdDItemSheet {
const dragData = {
actorId: this.actor.id,
type: "Item",
data: item.system
data: item.system,
uuid: item.uuid
};
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
@ -51,7 +52,8 @@ export class RdDConteneurItemSheet extends RdDItemSheet {
async _onDropItem(event, dragData) {
if (this.actor) {
const dropParams = await RdDSheetUtility.prepareItemDropParameters(this.item.id, this.actor, dragData, this.objetVersConteneur);
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id') ?? this.item.id
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur);
await this.actor.processDropItem(dropParams);
await this.render(true);
}

View File

@ -0,0 +1,38 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDFauneItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return "faune" };
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find("a.linked-actor-delete").click(event => this.onDeleteLinkedActor());
}
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': ''
});
}
}

View File

@ -0,0 +1,6 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDHerbeItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return "herbe" };
}

View File

@ -0,0 +1,5 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDIngredientItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return "ingredient" };
}

View File

@ -0,0 +1,7 @@
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
export class RdDPlanteItemSheet extends RdDItemInventaireSheet {
static get ITEM_TYPE() { return "plante" };
}

View File

@ -1,5 +1,5 @@
import { RdDRencontre } from "./item-rencontre.js";
import { RdDItemSheet } from "./item-sheet.js";
import { RdDRencontre } from "./rencontre.js";
import { RdDItemSheet } from "../item-sheet.js";
export class RdDRencontreItemSheet extends RdDItemSheet {

View File

@ -1,4 +1,4 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDItemSheet } from "../item-sheet.js";
export class RdDServiceItemSheet extends RdDItemSheet {
@ -6,7 +6,7 @@ export class RdDServiceItemSheet extends RdDItemSheet {
async getData() {
const formData = await super.getData();
formData.disabled = formData.isGM || formData.isOwned ? '' : 'disabled';
formData.disabled = formData.options.isGM || formData.options.isOwned ? '' : 'disabled';
return formData;
}

View File

@ -1,6 +1,6 @@
import { RdDItemSheet } from "./item-sheet.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { TMRUtility } from "./tmr-utility.js";
import { RdDItemSheet } from "../item-sheet.js";
import { RdDItemSigneDraconique } from "./signedraconique.js";
import { TMRUtility } from "../tmr-utility.js";
/**
* Item sheet pour signes draconiques

View File

@ -1,8 +1,9 @@
import { defaultItemImg } from "./item.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
import { RdDItem, defaultItemImg } from "../item.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { RdDRollTables } from "../rdd-rolltables.js";
import { RdDTimestamp } from "../time/rdd-timestamp.js";
import { TMRType, TMRUtility } from "../tmr-utility.js";
const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
@ -15,7 +16,17 @@ const tableSignesIndicatifs = [
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
export class RdDItemSigneDraconique {
export class RdDItemSigneDraconique extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp";
}
async calculerFinPeriodeTemporel(debut) {
// TODO
return RdDTimestamp.formulesDuree().find(it => it.code == "").calcul(debut, this.actor);
}
static prepareSigneDraconiqueMeditation(meditation, rolled) {
return {
@ -96,6 +107,6 @@ export class RdDItemSigneDraconique {
static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
}
}
}

13
module/item/souffle.js Normal file
View File

@ -0,0 +1,13 @@
import { RdDItem } from "../item.js";
export class RdDItemSouffle extends RdDItem {
static get defaultIcon() {
return "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp";
}
async calculerFinPeriodeTemporel(debut) {
return await debut.appliquerDuree(this.system.duree, this.parent);
}
}

View File

@ -1,9 +1,10 @@
import { RdDBaseActor } from "./actor/base-actor.js";
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
import { Environnement } from "./environnement.js";
import { Grammar } from "./grammar.js";
import { Monnaie } from "./item-monnaie.js";
import { RdDItem } from "./item.js";
import { RdDItem, TYPES } from "./item.js";
import { RdDTimestamp } from "./time/rdd-timestamp.js";
import { RdDRaretes } from "./item/raretes.js";
class Migration {
get code() { return "sample"; }
@ -12,7 +13,7 @@ class Migration {
async applyItemsUpdates(computeUpdates) {
await game.actors.forEach(async (actor) => {
const actorItemUpdates = computeUpdates(actor.items);
const actorItemUpdates = computeUpdates(actor.items).filter(it => it != undefined);
if (actorItemUpdates.length > 0) {
console.log(
this.code,
@ -23,7 +24,7 @@ class Migration {
}
});
const itemUpdates = computeUpdates(game.items);
const itemUpdates = computeUpdates(game.items).filter(it => it != undefined);
if (itemUpdates.length > 0) {
console.log(this.code, "Applying updates on items", itemUpdates);
await Item.updateDocuments(itemUpdates);
@ -64,7 +65,6 @@ class _1_5_34_migrationPngWebp {
}
}
class _10_0_16_MigrationSortsReserve extends Migration {
get code() { return "creation-item-sort-reserve"; }
get version() { return "10.0.16"; }
@ -287,10 +287,11 @@ class _10_3_0_FrequenceEnvironnement extends Migration {
}
_updatesFrequences(it) {
const rarete = RdDRaretes.byCode(it.system.rarete);
return {
_id: it.id,
'system.rarete': undefined,
'system.environnement': [{ milieu: it.system.milieu, rarete: it.system.rarete, frequence: Environnement.getFrequenceRarete(it.system.rarete, 'frequence') }]
'system.environnement': [{ milieu: it.system.milieu, rarete: rarete.code, frequence: rarete.frequence }]
}
}
}
@ -369,6 +370,150 @@ class _10_4_6_ServicesEnCommerces extends Migration {
}
}
class _10_5_0_UpdatePeriodicite extends Migration {
get code() { return "migration-periodicite-poisons-maladies"; }
get version() { return "10.5.0"; }
async migrate() {
await this.applyItemsUpdates(items => this._updatePeriodicite(items));
}
_updatePeriodicite(items) {
return items.filter(it => ['poison', 'maladie'].includes(it.type))
.filter(it => it.system.periodicite != "")
.map(it => {
let [incubation, periodicite] = this.getPeriodicite(it);
const periode = periodicite.split(' ');
let unite = periode.length == 2
? RdDTimestamp.formulesPeriode().find(it => Grammar.includesLowerCaseNoAccent(periode[1], it.code))?.code
: undefined
if (unite && Number(periode[0])) {
return {
_id: it.id,
'system.periodicite': undefined,
'system.incubation': incubation,
'system.periode.nombre': Number.parseInt(periode[0]),
'system.periode.unite': unite
};
}
else {
return {
_id: it.id,
'system.periodicite': undefined,
'system.incubation': it.system.periodicite
};
}
}).filter(it => it != undefined);
}
getPeriodicite(it) {
let p = it.system.periodicite.split(/[\/\\]/);
switch (p.length) {
case 2: return [p[0].trim(), p[1].trim()];
case 1: return ["", it.system.periodicite.trim()];
default: return [it.system.periodicite.trim(), ""];
}
}
}
class _10_7_0_MigrationBlessures extends Migration {
get code() { return "migration-blessures"; }
get version() { return "10.7.0"; }
async migrate() {
const timestamp = game.system.rdd.calendrier.getTimestamp()
await Promise.all(game.actors.filter(it => it.isPersonnage() || it.isCreature())
.map(async (actor) => {
const legeres = actor.system.blessures?.legeres.liste.filter(it => it.active).map(it => this.creerBlessure(2, 'légère', it, timestamp)) ?? [];
const graves = actor.system.blessures?.graves.liste.filter(it => it.active).map(it => this.creerBlessure(4, 'grave', it, timestamp)) ?? [];
const critiques = actor.system.blessures?.critiques.liste.filter(it => it.active).map(it => this.creerBlessure(6, 'critique', it, timestamp));
const blessures = legeres.concat(graves).concat(critiques);
if (blessures.length > 0) {
await actor.createEmbeddedDocuments("Item", blessures);
}
await actor.update({
'system.blessures.legeres.liste': [],
'system.blessures.graves.liste': [],
'system.blessures.critiques.liste': []
})
}));
}
creerBlessure(gravite, graviteTexte, blessure, timestamp) {
const dateBlessure = timestamp.addJours(-blessure.jours);
const datePremiereRecup = dateBlessure.addJours(gravite);
return {
name: `Blessure ${graviteTexte}`,
type: 'blessure',
img: `systems/foundryvtt-reve-de-dragon/icons/sante/blessure${blessure.psdone ? '-soins' : ''}.webp`,
system: {
gravite: gravite,
difficulte: -gravite,
debut: { indexDate: dateBlessure.indexDate, indexMinute: 0 },
fin: { indexDate: datePremiereRecup.indexDate, indexMinute: 0 },
premierssoins: { done: blessure.psdone, bonus: blessure.premiers_soins },
soinscomplets: { done: blessure.scdone, bonus: blessure.soins_complets },
localisation: blessure.localisation
}
}
}
}
class _10_7_19_CategorieCompetenceCreature extends Migration {
get code() { return "categorie-competence-creature"; }
get version() { return "10.7.19"; }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => TYPES.competencecreature == it.type)
.map(it => this.migrateCompetenceCreature(it))
);
}
migrateCompetenceCreature(it) {
const categorie = this.getCategorie(it)
if (categorie == it.system.categorie) {
return undefined
}
return { _id: it.id, 'system.categorie': categorie }
}
getCategorie(it) {
if (it.system.ispossession) {
return 'possession'
}
switch (it.system.categorie) {
case "melee":
if (it.system.isnaturelle) {
return 'naturelle'
}
return 'melee'
case "particuliere": case "specialisee": case "connaissance":
return "generale"
default:
return it.system.categorie
}
}
}
class _10_7_19_PossessionsEntiteVictime extends Migration {
get code() { return "possessions-entite-victime"; }
get version() { return "10.7.19"; }
async migrate() {
await this.applyItemsUpdates(items => items
.filter(it => TYPES.possession == it.type)
.map(it => this.migratePossession(it))
);
}
migratePossession(it) {
return { _id: it.id,
'system.entite.actorid': it.system.possesseurid,
'system.victime.actorid': it.system.possedeid
}
}
}
export class Migrations {
static getMigrations() {
return [
@ -383,6 +528,10 @@ export class Migrations {
new _10_3_0_FrequenceEnvironnement(),
new _10_3_17_Monnaies(),
new _10_4_6_ServicesEnCommerces(),
new _10_5_0_UpdatePeriodicite(),
new _10_7_0_MigrationBlessures(),
new _10_7_19_CategorieCompetenceCreature(),
new _10_7_19_PossessionsEntiteVictime(),
];
}
@ -399,7 +548,7 @@ export class Migrations {
migrate() {
const currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion");
if (isNewerVersion(game.system.version, currentVersion)) {
//if (true) { /* comment previous and uncomment here to test before upgrade */
// if (true) { /* comment previous and uncomment here to test before upgrade */
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
if (migrations.length > 0) {
migrations.sort((a, b) => this.compareVersions(a, b));

View File

@ -22,6 +22,10 @@ export class Misc {
const isPositiveNumber = value != NaN && value > 0;
return isPositiveNumber ? "+" + number : number
}
static modulo(n, m) {
return ((n % m) + m) % m;
}
static sum() {
return (a, b) => Number(a) + Number(b);
@ -42,7 +46,7 @@ export class Misc {
}
static typeName(type, subType) {
return subType ? game.i18n.localize(`${type.toUpperCase()}.Type${Misc.upperFirst(subType)}`)
return subType ? game.i18n.localize(`TYPES.${type}.${Misc.upperFirst(subType)}`)
: '';
}
@ -63,8 +67,8 @@ export class Misc {
static keepDecimals(num, decimals) {
if (decimals <= 0 || decimals > 6) return num;
const decimal = Math.pow(10, parseInt(decimals));
return Math.round(num * decimal) / decimal;
const power10n = Math.pow(10, parseInt(decimals));
return Math.round(num * power10n) / power10n;
}
static getFractionHtml(diviseur) {
@ -85,6 +89,7 @@ export class Misc {
list.forEach(it => addToObj(obj, it))
return obj;
}
static concat(lists) {
return lists.reduce((a, b) => a.concat(b), []);
}
@ -118,6 +123,17 @@ export class Misc {
}
}
/**
* @returns an array of incremental integers (including from / excluding to).
* if max<min, the array is decrementing integers
*/
static intArray(from, to) {
if (from > to) {
return Array.from(Array(from - to).keys()).map(i => from - i)
}
return Array.from(Array(to - from).keys()).map(i => from + i)
}
static distinct(array) {
return [...new Set(array)];
}
@ -193,6 +209,7 @@ export class Misc {
const subset = this.findAllLike(value, elements, options);
if (subset.length == 0) {
console.log(`Aucune ${options.description} pour ${value}`);
return undefined
}
if (subset.length == 1) {
@ -227,4 +244,15 @@ export class Misc {
}
return subset;
}
static cssRotation(angle) {
const rotation = `rotate(${angle}deg)`;
return {
'transform': rotation,
'-ms-transform': rotation,
'-moz-transform': rotation,
'-webkit-transform': rotation,
'-o-transform': rotation
};
}
}

View File

@ -8,13 +8,11 @@ export class RdDAlchimie {
/* -------------------------------------------- */
static processManipulation(recette, actorId = undefined) {
//console.log("CALLED", recette, recette.isOwned, actorId );
let manip = recette.system.manipulation;
let matchArray = manip.match(matchOperations);
if (matchArray) {
for (let matchStr of matchArray) {
let result = matchStr.match(matchOperationTerms);
//console.log("RESULT ", result);
if (result[1] && result[2]) {
let commande = Misc.upperFirst(result[1]);
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId);
@ -27,20 +25,19 @@ export class RdDAlchimie {
/* -------------------------------------------- */
static _alchimieCouleur(recette, couleurs, actorId) {
if (actorId) {
return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="couleur" data-alchimie-data="${couleurs}">couleur ${couleurs}</a></span>`;
} else {
return `<span class="alchimie-tache">couleur ${couleurs} </span>`;
}
return RdDAlchimie._alchimieLink(recette, couleurs, actorId, 'couleur', 'Température');
}
/* -------------------------------------------- */
static _alchimieConsistance(recette, consistances, actorId) {
if (actorId) {
return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="consistance" data-alchimie-data="${consistances}">consistance ${consistances}</a></span>`;
} else {
return `<span class="alchimie-tache">consistance ${consistances} </span>`;
}
return RdDAlchimie._alchimieLink(recette, consistances, actorId, 'consistance', 'Consistance');
}
static _alchimieLink(recette, termes, actorId, tacheAlchimie, labelTache) {
const difficulte = RdDAlchimie.getDifficulte(termes);
const link = actorId ? ` <a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="${tacheAlchimie}" data-alchimie-data="${termes}">` : '';
const endLink = actorId ? '</a>' : '';
return `<span class="alchimie-tache">${link}${labelTache} ${termes} (${difficulte})${endLink}</span>`;
}
/* -------------------------------------------- */

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