Compare commits
259 Commits
foundryvtt
...
v10
| Author | SHA1 | Date | |
|---|---|---|---|
| 54df875451 | |||
| 253a1bd433 | |||
| e58d88fab6 | |||
| 41d2404de2 | |||
| 631ee0b801 | |||
| ed9c574cd2 | |||
| bb624e8e96 | |||
| 40f2ac8714 | |||
| 804fa3b784 | |||
| d35e47824d | |||
| 37d3fa5bc5 | |||
| 8a12eb865c | |||
| 5baa94b3f0 | |||
| 37c2b6432d | |||
| fc63835a71 | |||
| d82a543860 | |||
| 2e76961ba7 | |||
| a9f50bbc5e | |||
| 8ba3476d7b | |||
| 4e8f6e8872 | |||
| 727701bdcd | |||
| dcc0f0acfd | |||
| 61eee66ebe | |||
| c75d10f69b | |||
| 333bb051c1 | |||
| 1bf247db33 | |||
| 49fc2c9b0a | |||
| 9013376096 | |||
| 972459a08d | |||
| 1607629365 | |||
| 8f7efdad87 | |||
| 2dbe0dea4a | |||
| 5fc455fbad | |||
| 8a7e4d3a9e | |||
| c10195f753 | |||
| 4d7317b964 | |||
| 7b1fa009bb | |||
| 71bb8a14e1 | |||
| 5444bc7fd8 | |||
| debaf1da34 | |||
| 69e2ab9000 | |||
| 24218ed062 | |||
| da4e18dc3c | |||
| 154a9b7a37 | |||
| fb8189606b | |||
| cfbfad27bd | |||
| f541849306 | |||
| d2d1891838 | |||
| 5580b6d59c | |||
| 40c45c30de | |||
| 1b6c5256cc | |||
| c0e6759164 | |||
| a096590a07 | |||
| 9883048fb5 | |||
| 7bec42c4cf | |||
| 6708dc0da9 | |||
| 96c2da0d05 | |||
| 2b19250e8b | |||
| 957eabcac7 | |||
| 285937c201 | |||
| 93965ce91a | |||
| 18aba9adff | |||
| 0a5662ff71 | |||
| bf98e4eae2 | |||
| e32a1d25f6 | |||
| 327943c4aa | |||
| de56fa909a | |||
| 2aa62cffe9 | |||
| c57f140c54 | |||
| 9cf14f8b75 | |||
| b8e7b21e14 | |||
| c1d02d9fda | |||
| 23af30a538 | |||
| 4e1b663dec | |||
| c9d98c57da | |||
| 0aef139cf8 | |||
| 9c85293714 | |||
| ab1c04ae17 | |||
| a585e0faba | |||
| 50c730ba72 | |||
| 928a60f092 | |||
| e5c2f52b0e | |||
| f9391523f8 | |||
| 55434762f4 | |||
| 5e6ffc7846 | |||
| 3344e20936 | |||
| 5a66e4e741 | |||
| d329724d63 | |||
| 8a5405c9f5 | |||
| ea992aae46 | |||
| 0bfcfec58f | |||
| 88e00c59bc | |||
| d314dc39a0 | |||
| 30bb803da2 | |||
| dd79e16ea5 | |||
| 83e2d56fd4 | |||
| afc23dfa7b | |||
| 3e189cbe5f | |||
| d0475e8677 | |||
| a3694c1673 | |||
| 9e6d5856b1 | |||
| acc880b53f | |||
| 2598ae3489 | |||
| 4f5fb63751 | |||
| d739a7993a | |||
| 41335cd433 | |||
| e470d76ea0 | |||
| ffccc819f1 | |||
| 45bfc69b39 | |||
| 79e9358072 | |||
| 5cab418e62 | |||
| 7809f7c21a | |||
| 1bac204071 | |||
| 3bf5beb67b | |||
| ac1da6e979 | |||
| 67735197bc | |||
| f81dc9a5f5 | |||
| a563233d6b | |||
| 0c11013694 | |||
| 77cf72a752 | |||
| 42ed5da2d4 | |||
| 5fd3a43b2a | |||
| 1bb710ce83 | |||
| 80579032ea | |||
| a810e20eca | |||
| c6f0aaeba0 | |||
| 3c3be7409d | |||
| f97345e407 | |||
| 4cc50fc190 | |||
| 26967fe1cd | |||
| b23dcaace5 | |||
| 045ee76013 | |||
| 7fed3844b5 | |||
| b5571e6c7a | |||
| b5eac8ccfa | |||
| 673196c644 | |||
| 9741028914 | |||
| 10daab2bcd | |||
| 99d2d38279 | |||
| e30825db6b | |||
| 10ed4d9382 | |||
| 2ffa0d8dc7 | |||
| f229537206 | |||
| 5c31c7bd7f | |||
| 4cf428f630 | |||
| 0c1b70f3f0 | |||
| b7ea857bb4 | |||
| 0238976ce8 | |||
| 31fd91336a | |||
| c70b6c9d5f | |||
| 07d0d92f57 | |||
| a2968697f4 | |||
| fb7dbe6ea0 | |||
| 59641bf5cf | |||
| 4ee4445836 | |||
| 1a346a21c3 | |||
| c6c0dd43fd | |||
| d69a07d4dd | |||
| 56379a9234 | |||
| fbcc167272 | |||
| 703ab2579d | |||
| 6b7e881bf2 | |||
| dc3ceb1732 | |||
| 7a0132cf8d | |||
| ca1ea5a854 | |||
| 9bdde92d61 | |||
| 74313b7fd3 | |||
| 9a9399a581 | |||
| 95a7ac73d0 | |||
| ab4c118d12 | |||
| 681358238d | |||
| 5511acc876 | |||
| 2e144851d4 | |||
| 9f24aee1f3 | |||
| e605ab405a | |||
| 86f69566a6 | |||
| 2561a658f2 | |||
| 8a1d1fd253 | |||
| e42f384d7f | |||
| d381191692 | |||
| 53a7230f1d | |||
| 4d5651c2d3 | |||
| 61474172a7 | |||
| 083806612b | |||
| 1c417d02a1 | |||
| ee9e7d2adb | |||
| fa3334273d | |||
| 05b73a41a5 | |||
| 842243485a | |||
| 1e53f2d9e8 | |||
| 792fcc1b39 | |||
| 3d914a29c3 | |||
| 7fe7c1e9bd | |||
| d86b81fbbc | |||
| 22da2807d8 | |||
| 76e03b07ed | |||
| e4098c813b | |||
| 90aecd6cc0 | |||
| 254709f55b | |||
| 064472dc11 | |||
| 7a67cb7cea | |||
| 7f051e76be | |||
| 38db7fb7c8 | |||
| c448f32bb8 | |||
| e194514965 | |||
| a790c36618 | |||
| f221bb31eb | |||
| bdc2d8db3a | |||
| 782dc38268 | |||
| 024e355586 | |||
| 37704558e0 | |||
| d816490839 | |||
| a4186da540 | |||
| b8b4a1ff14 | |||
| 8925a4979d | |||
| 851a208aee | |||
| 4df04fe06f | |||
| f4d074fa31 | |||
| f7595a1bfe | |||
| 86feb12811 | |||
| 2383094254 | |||
| 2a72f6ffea | |||
| 3cc56c615c | |||
| 948309bb4f | |||
| 40fdff4057 | |||
| c972913a67 | |||
| 0d5c8e5304 | |||
| 0aba6d2f0a | |||
| df3e181d7f | |||
| 8877939b9f | |||
| 7334f2d8e6 | |||
| ceff3d1b50 | |||
| a4802d1113 | |||
| 162a6a04b8 | |||
| 0c36cf3c47 | |||
| 969e5f6b2d | |||
| 306ecacc98 | |||
| 2dc86e6679 | |||
| 484530d67d | |||
| a08890dcb0 | |||
| 1956fdd755 | |||
| 651356159a | |||
| ca304109d5 | |||
| 9c0d08cb6f | |||
| f9fd8a1e24 | |||
| 03f84eb3f7 | |||
| 05e48b61ff | |||
| f20788d6d9 | |||
| 009639dd5f | |||
| 14542cf7cd | |||
| f4f2db68e0 | |||
| 7e75715d88 | |||
| d62d1c45bc | |||
| 62914c343f | |||
| 9349e81580 | |||
| 404539a004 | |||
| 9eaeceafc4 | |||
| 1cd3bdef25 | |||
| fa356bd7f8 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.vscode/settings.json
|
||||
.idea
|
||||
.history
|
||||
todo.md
|
||||
/.vscode
|
||||
/ignored/
|
||||
|
||||
302
changelog.md
302
changelog.md
@@ -1,10 +1,298 @@
|
||||
==================================================================
|
||||
v0.9.2 - 05/09/2020
|
||||
# v10.7 - L'os de Sémolosse
|
||||
|
||||
Erreur de calcul sur points de vie
|
||||
Gestion différente des compétences "troncs"
|
||||
## v10.7.20 - la poigne de Sémolosse
|
||||
- correction de méthodes qui filtrent les items
|
||||
- recherche de cases TMR
|
||||
- recherche de tâches de lecture
|
||||
- recherche d'armure (pour le malus armure)
|
||||
- recherche de potions
|
||||
|
||||
==================================================================
|
||||
v0.9.1 - 03/09/2020
|
||||
## v10.7.20 - la poigne de Sémolosse
|
||||
- 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
|
||||
|
||||
Initial official release
|
||||
## v10.7.19 - les fantômes de Sémolosse
|
||||
- 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é
|
||||
|
||||
## v10.7.18 - le repos de Sémolosse
|
||||
- correction des dates de blessures qui ne marchaient plus
|
||||
|
||||
## v10.7.17 - le doigt du destin de Sémolosse
|
||||
- correction de la validation d'encaissement par le MJ
|
||||
|
||||
## v10.7.16 - la morsure de Sémolosse
|
||||
- correction de l'affichage des objets suite à confusion
|
||||
- correction de liens dans la liste des équipements
|
||||
|
||||
## v10.7.14 - l'expérience de Sémolosse
|
||||
- Affichage des personnages accordés sur les fiches des entités
|
||||
- Refonte du journal d'expérience
|
||||
- disponible pour les personnages des joueurs
|
||||
- explication "comptable" des changements (dépense ou ajout, changements de niveaux, ...)
|
||||
- tri alphabétique des différentes listes (sorts, recettes, oeuvres, ...)
|
||||
|
||||
## v10.7.13 - l'armure de Sémolosse
|
||||
- Fix: en cas d'armure variable, la détérioration diminue le dé d'armure
|
||||
|
||||
## v10.7.12
|
||||
- Fix: si le MJ gère les changements de jours, l'option "sieste" de la fenêtre de repos est prise par défaut si chateau dormant n'est pas passé
|
||||
|
||||
## v10.7.11 - Le Pugilat de Sémolosse
|
||||
- Fix sur la projection au sol.
|
||||
|
||||
## v10.7.10 - Le Pugilat de Sémolosse
|
||||
- Gestion de l'empoignade
|
||||
- Corrections sur l'initiative
|
||||
- Correction sur l'equipement des vêtements et bijoux
|
||||
|
||||
## v10.7.9 - Le Pugilat de Sémolosse
|
||||
|
||||
- Gestion assistée de l'empoignade
|
||||
1. On selectionne sa cible (ie le token qui va être empoigné)
|
||||
2. On lance une attaque avec l'"arme" _Empoignade_
|
||||
3. A ce stade, si la victime a une arme, on rappelle le point de règle d'engagement
|
||||
(page 134), et un bouton permet de confirmer l'empoignade
|
||||
4. L'empoigneur fait son jet
|
||||
5. Si réussite, l'empoigné peut se défendre, avec gestion du premier round d'engagement
|
||||
(ie Esquive autorisée ou pas)
|
||||
- 4 bis. et 5 bis. L'empoigné, à son tour, peut tenter de se libérer, toujours en cliquant sur l'action "Empoignade"
|
||||
6. Selon le résultat, incrément/décrément des points d'emp
|
||||
7. Retour en 4., ou si 2 points d'Emp, alors 8.
|
||||
8. Affichage des options disponibles pour l'empoigneur : perte d'endurance, projection au
|
||||
sol ou entrainer au sol. Ces 3 options sont gérées automatiquement ensuite, selon le
|
||||
bouton cliqué par l'empoigneur.
|
||||
|
||||
Les empoignades sont des "items" supprimées à la fin d'un combat, qui peuvent aussi être
|
||||
gérés par le MJ au cas ou. Hors combat, penser à les supprimer (ou commencer et
|
||||
arrêter un combat).
|
||||
|
||||
## v10.7.7 - Les bobos de Sémolosse
|
||||
- Mise à jour du texte de l'heure pour les joueurs
|
||||
- L'horloge n'empêche plus de sélectionner les tokens dessous
|
||||
- _Lecture & Détection d'Aura_ sous Hypnos sont des rituels
|
||||
- _Lire les étoiles_ pour les joueurs de nouveau fonctionnel
|
||||
- Ajout de logs pour comprendre un cas d'échec des achatVente
|
||||
|
||||
## v10.7.6 - L'origine des maux de Sémolosse
|
||||
- Calendrier
|
||||
- fix du ré-affichage de l'horloge qui ne marchait pas pour les joueurs
|
||||
- l'horloge ne se ferme plus sur Escape
|
||||
- amélioration d'affichage
|
||||
- couleurs jour/nuit plus marquées
|
||||
- Divers
|
||||
- correction de l'affichage de quantités diminuées d'herbes dans les contenants ouvert
|
||||
- ajout d'un bouton pour diminuer les quantités dans l'équipement (si quantité > 1)
|
||||
- ajout de la signature de l'acteur sur les blessures qu'il a causées
|
||||
|
||||
- Magie
|
||||
- correction des bonus de cases pour les sorts en Fleuve
|
||||
|
||||
## v10.7.5 - La montre-gousset de Sémolosse
|
||||
- Amélioration de la fenêtre calendrier
|
||||
* plus compacte
|
||||
* horloge analogique (optionnelle)
|
||||
* minimizable (juste la barre de titre)
|
||||
* normalement compatible pop-out
|
||||
|
||||
## v10.7.4 - Les ligatures de Sémolosse
|
||||
- Corrections diverses
|
||||
- Correction des boutons pour déclencher un sort en réserve avec réserve en sécurité ou réserve extensible
|
||||
- le lien pour les jets de vie suite à une blessure critique est remplacé par un bouton
|
||||
- déplacement des tâches et boutons de chirurgie dans l'onglet savoirs et tâches
|
||||
- correction de l'affichage des bonus de cases des sorts
|
||||
- corrections des queues non-refoulables dans le compendium
|
||||
|
||||
## v10.7.3 - Les tisanes de Sémolosse
|
||||
- Soins
|
||||
- on peut de nouveau boire une potion de soins enchantée
|
||||
- les potions non enchantées donnent de nouveau un bonus au prochain jet de récupération
|
||||
- Une fois les soins complets faits, le bonus aux soins complets fournis par les premiers soins est masqué
|
||||
|
||||
- Horloge
|
||||
- A l'heure de Couronne pile, les aiguilles des heures et des minutes pointent sur couronne (comme une montre) au lieu d'avoir l'aiguille des heures 15° à gauche
|
||||
|
||||
## v10.7.2 - les maux de dents de Sémolosse
|
||||
- correction des récupérations de blessures
|
||||
- la fin de château dormant se passe normalement
|
||||
|
||||
## v10.7.1 - L'os de Sémolosse
|
||||
- Fix rapide sur les jets de carac qui n'étaient plus possibles
|
||||
|
||||
## v10.7.0 - L'os de Sémolosse
|
||||
- gestion des blessures en items
|
||||
- soins du token ciblé par menu contextuel (comme le combat)
|
||||
- automatisation des soins et de l'affichage de l'avancement des soins
|
||||
- support des changements d'opérants
|
||||
|
||||
---
|
||||
# v10.6 - Les recherches de Pralinor le Goûteux
|
||||
|
||||
## v10.6.25 - Fix sur l'astrologie
|
||||
|
||||
## v10.6.22 - le nuage de lait dans le thé de Pralinor
|
||||
- Amélioration de l'affichage de l'horloge
|
||||
- Fix: affichage des points de guérison dans les potions
|
||||
|
||||
## v10.6.21 - La théière de Pralinor
|
||||
- Astrologie
|
||||
- le thème astral est directement dans la fenêtre d'astrologie
|
||||
- la roue des heures sert d'horloge
|
||||
- sélectionner un personnage ajuste le thème astral pour son heure de naissance
|
||||
- sélectionner le nombre astral d'un jour ajuste le thème astral
|
||||
|
||||
- Fix: les PNJs peuvent de nouveau dormir
|
||||
|
||||
## v10.6.20 - Les Oracles de Pralinor: vous mangerez à Couronne
|
||||
- Ajout de la fenêtre pour effectuer un thème astral
|
||||
|
||||
## v10.6.19 - La cerise de Pralinor
|
||||
- les joueurs peuvent chercher dans les commerces avec un droit limité/observateur
|
||||
- simplifications des fins de tours et nombre d'utilisations
|
||||
- ajout du _Haubert d'Oniros_ dans le compendium de sorts
|
||||
|
||||
## v10.6.17 - Les désordres de Pralinor
|
||||
- le contenu des casseroles et autres contenants est maintenant trié dans l'ordre alphabétique
|
||||
- les objets dupliqués du compendium d'équipement sont de nouveaux uniques
|
||||
|
||||
## v0.6.16 - Le pardon de Pralinor
|
||||
- Ajout d'un commerce _Liste d'équipement_ dans les archétypes de PNJs
|
||||
- Séparations d'équipements groupés et corrections de quelques objets & herbes
|
||||
- On peut éditer les armes stockées dans un commerce
|
||||
|
||||
## v10.6.15 - les digestifs de Pralinor
|
||||
- amélioration des messages de sommeil (nombre d'heure dormies, uniquement les
|
||||
récupérations de rêve en dessous du seuil, affichage de la récupération d'endurance
|
||||
qui avait disparu, meilleur message sur le jet de moral)
|
||||
- les insomnies ne durent bien que 12h draconique à partir du prochain
|
||||
Chateau Dormant (elles pouvaient durer 3 nuits suite à une erreur).
|
||||
- la recherche dans l'équipement affiche correctement les conteneurs dans lesquels les
|
||||
objets trouvés sont rangés
|
||||
|
||||
## v10.6.14 - la digestion de Pralinor
|
||||
- Chateau dormant
|
||||
- la situation du jet de moral peut être choisie lorsque l'on dort
|
||||
- les queues de dragon "insomnie" empêchent de dormir, et de rêver
|
||||
- ajout d'une option pour meilleure gestion de Chateau Dormant par le MJ
|
||||
- avec cette option, à la fin Chateau Dormant, une fenêtre permet au gardien de
|
||||
positionner pour chaque joueur:
|
||||
- le stress de la journée
|
||||
- les heures de sommeil
|
||||
- la situation du jet de moral (neutre/heureux/malheureux)
|
||||
|
||||
- l'affichage des heures Chateau Dormant et Poisson Acrobate est correct
|
||||
- le jet de moral en situation neutre fait maintenant retourner le moral vers 0, et
|
||||
n'affecte plus un moral à 0.
|
||||
## v10.6.13 - la cave de Pralinor
|
||||
- on peut maintenant chercher dans l'inventaire des commerces
|
||||
- l'inventaire est correctement affiché en entier après suppression de la recherche
|
||||
- le message de chateau dormant reflète correctement un jet de moral neutre qui passe le moral de 0 à +1
|
||||
|
||||
## v10.6.12 - l'index de Pralinor
|
||||
- On peut désormais chercher dans l'inventaire comme dans les compétences
|
||||
|
||||
## v10.6.11 - l'empoisonnement de Pralinor
|
||||
- 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
|
||||
- ajout d'un "poison" pour bloquer la récupération sous Griffe Morbide de Thanatos.
|
||||
Ajout du lien vers l'objet du compendium dans la description MJ,, qui pourra donc
|
||||
ajouter ce "poison" à la victime pour empêcher ses guérisons de vie ou blessure.
|
||||
|
||||
## v10.6.10
|
||||
- Correction de l'édition des description
|
||||
- Amélioration des descriptions d'alchimie:
|
||||
- difficulté calculée automatiquement
|
||||
- Température pour les couleurs
|
||||
- La sustentation n'est plus concaténée dans certains cas (ce qui donnait 2+2=22)
|
||||
|
||||
## v10.6.8 : les bon mots de Pralinor
|
||||
- Dans la fenêtre de _recherche et tirages_, possibilité de chercher sur le nom des objets en plus des autres critères
|
||||
|
||||
## v10.6.7 : les grumelés de Pralinor
|
||||
- les objets peuvent être utilisés depuis la fenêtre d'un conteneur
|
||||
- dans les fenêtres de contenants, le contenu est correctement indenté
|
||||
- la présentation du contenu d'un sac est améliorée
|
||||
- le bouton Nouvel Objet n'est affiché que si on est propriétaire de l'acteur
|
||||
- la fenêtre de vente permet de nouveau de choisir les quantités à vendre
|
||||
|
||||
## v10.6.6
|
||||
- Corrections d'armes rudimentaires
|
||||
- Inversion: Taille puis poids
|
||||
- Suppression d'une ligne de caractéristique vide (causée par la beauté)
|
||||
- Les messages liés aux compétences troncs deviennent des notifications
|
||||
## v10.6.5
|
||||
- Le +dom est de nouveau affiché
|
||||
- L'édition de caractéristiques des créatures fonctionne de nouveau
|
||||
|
||||
## v10.6.4 - La sénilité de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- les résultats de recherches sur plusieurs compendiums sont triés
|
||||
- lors de recherches avec un ou des milieux sélectionnés:
|
||||
- le filtre sur la rareté utilise la rareté dans ces milieux
|
||||
- les tirages se basent sur la fréquence la plus élevées dans ces milieux
|
||||
- les filtres par utilisation prennent les potions en compte
|
||||
- les remèdes ont une catégorie de potion 'Remède' (et correspondent à une utilisation médicale)
|
||||
- ajout d'un filtre d'utilisation 'cuisine'
|
||||
|
||||
|
||||
# Divers
|
||||
- fix du cas où la transformation de 0 points de stress était concaténé, (passage de 29 à 290 avec 0 points transformés)
|
||||
- suppression du compendium de taches courantes, désormais inutile
|
||||
|
||||
## v10.6.3 - le baba-brandevin de Pralinor
|
||||
- les tâches de Soins sont maintenant déplacées à côté des blessures
|
||||
- on peut créer les tâches de soins directement avec un bouton par gravité.
|
||||
|
||||
- le round n'est plus bloqué si un acteur est sonné
|
||||
- un rare cas d'initiative négative pouvait empêcher de faire une initiative (à cause de l'état général)
|
||||
- dans une circonstance inconnue, une rencontre pouvait disparaître lors de la maîtrise. Ajout d'un message pour essayer d'obtenir des détails sur ce cas, et ajout d'une sécurité pour retrouver la rencontre (qui est conservée par la fenêtre de choix d'action).
|
||||
- les objets temporels (queues, souffles, poisons, maladies...) créés avant la gestion temporelle ne pouvaient pas être édités.
|
||||
- les particulières sur les jets de résistance de rêve actuel ne rapportent qu'un point d'expérience (p191)
|
||||
- pour lutter contre l'alcoolisme, les jets d'éthylisme sont considérés comme des jets de résistance, et n'apportent qu'un point d'expérience.
|
||||
## v10.6.2 - Le méli-mélo de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- support de la recherche dans les compendiums choisis
|
||||
- suppression des commandes `/table milieu` et `/tirer milieu` (remplacées par la fenêtre de recherche)
|
||||
- ajout de fréquences à tous les équipements
|
||||
## v10.6.1 - Les recherches de Pralinor
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- Amélioration des filtres de cuisine/utilisation
|
||||
- Ajout de catégories pour les poisons, urtiquants, ...
|
||||
- Bouton "Effacer les filtres" plus clair
|
||||
- Drag&drop depuis la recherche
|
||||
- Reprise du compendium
|
||||
- pour les plantes vénéneuses
|
||||
- pour les plantes venimeuses
|
||||
- ajout de sust pour les champignons et autres plantes comestibles
|
||||
|
||||
- Affichage de l'image du token pour les commerces non liés
|
||||
- Les pièces d'or sont appelées 'Dragon'
|
||||
|
||||
## v10.6.0 - Les recherches de Pralinor le Goûteux
|
||||
- Fenêtre _Recherches et tirages_
|
||||
- ajout de la fenêtre _Recherches et tirages_ avec filtres paramétrables
|
||||
- ouverture de la fenêtre: commande `/tirage` ou macro disponible dans les macros du système
|
||||
- support des équipements, faune & flore (depuis les compendiums configurés par défaut)
|
||||
- nombreux choix à activer
|
||||
- possibilité de montrer les objets correspondant à la sélection
|
||||
- possibilité de faire un tirage parmi ces objets (en prenant en compte la fréquence)
|
||||
|
||||
- Plantes & pèche
|
||||
- séparation des ingrédients et plantes comestibles
|
||||
- retour des poissons dans les compendiums
|
||||
- ajout d'un lien depuis les plantes toxiques/dangereuses vers la maladie/poison correspondante
|
||||
|
||||
- On peut de nouveau ouvrir les conteneurs dans une fenêtre séparée
|
||||
- Les jets de volontés d'éthylisme calculent correctement la difficulté liée au moral (ie: 0 au lieu de -22)
|
||||
- si le journal de chronologie est supprimée, on peut en choisir un autre
|
||||
- la taille du calendrier est ajustée pour éviter une présentation bancale quand le nom du mois est court
|
||||
|
||||
BIN
icons/sante/blessure-mort.webp
Normal file
BIN
icons/sante/blessure-mort.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
BIN
icons/sante/blessure-soins.webp
Normal file
BIN
icons/sante/blessure-soins.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
BIN
icons/sante/blessure.webp
Normal file
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
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
BIN
icons/sante/mort.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
64
lang/fr.json
64
lang/fr.json
@@ -7,46 +7,48 @@
|
||||
"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",
|
||||
"TypeBlessure": "Blessure",
|
||||
"TypeCasetmr": "TMR spéciale",
|
||||
"TypeChant": "Chant",
|
||||
"TypeCompetence": "Compétence",
|
||||
"TypeCompetencecreature": "Compétence de créature",
|
||||
"TypeConteneur": "Conteneur",
|
||||
"TypeDanse": "Danse",
|
||||
"TypeMusique": "Musique",
|
||||
"TypeOeuvre": "Oeuvre",
|
||||
"TypeTache": "Tâche",
|
||||
"TypeExtraitpoetique": "Extrait poetique",
|
||||
"TypeFaune": "Faune",
|
||||
"TypeGemme": "Gemme",
|
||||
"TypeHerbe": "Herbe",
|
||||
"TypeIngredient": "Ingrédient",
|
||||
"TypeJeu": "Jeu",
|
||||
"TypeLivre": "Livre",
|
||||
"TypeMaladie": "Maladie",
|
||||
"TypeMeditation": "Méditation",
|
||||
"TypeMonnaie": "Monnaie",
|
||||
"TypeMunition": "Munition",
|
||||
"TypeMusique": "Musique",
|
||||
"TypeNombreastral": "Nombre astral",
|
||||
"TypeNourritureboisson": "Nourriture & boisson",
|
||||
"TypeObjet": "Objet",
|
||||
"TypeOeuvre": "Oeuvre",
|
||||
"TypeOmbre": "Ombre de Thanatos",
|
||||
"TypePlante": "Plante",
|
||||
"TypePoison": "Poison",
|
||||
"TypePossession": "Possession",
|
||||
"TypePotion": "Potion",
|
||||
"TypeQueue": "Queue de Dragon",
|
||||
"TypeRecettealchimique": "Recette alchimique",
|
||||
"TypeRecettecuisine": "Recette de cuisine",
|
||||
"TypeSort": "Sort",
|
||||
"TypeMeditation": "Méditation",
|
||||
"TypeRencontre": "Rencontre TMR",
|
||||
"TypeService": "Service",
|
||||
"TypeSignedraconique": "Signe draconique",
|
||||
"TypeQueue": "Queue de Dragon",
|
||||
"TypeOmbre": "Ombre de Thanatos",
|
||||
"TypeSouffle": "Souffle de Dragon",
|
||||
"TypeTete": "Tête de Dragon",
|
||||
"TypePossession": "Possession",
|
||||
"TypeSort": "Sort",
|
||||
"TypeSortreserve": "Sort en réserve",
|
||||
"TypeExtraitpoetique": "Extrait poetique"
|
||||
"TypeSouffle": "Souffle de Dragon",
|
||||
"TypeTache": "Tâche",
|
||||
"TypeTarot": "Carte de tarot",
|
||||
"TypeTete": "Tête de Dragon"
|
||||
},
|
||||
"EFFECT": {
|
||||
"StatusStunned": "Sonné",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
|
||||
export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
|
||||
@@ -13,6 +15,12 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
}
|
||||
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 */
|
||||
@@ -35,6 +43,23 @@ export class RdDActorEntiteSheet extends RdDActorSheet {
|
||||
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.confirmerSuppressionSubacteur(this, actorResonance, li, () => {
|
||||
console.log('Delete : ', actorId);
|
||||
this.removeSubacteur(actorId);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async removeSubacteur(actorId) {
|
||||
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
|
||||
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import { STATUSES } from "./settings/status-effects.js";
|
||||
import { MAINS_DIRECTRICES } from "./actor.js";
|
||||
import { RdDBaseActorSheet } from "./actor/base-actor-sheet.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -82,6 +84,7 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.system.carac);
|
||||
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;
|
||||
|
||||
@@ -111,19 +114,26 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
HtmlUtility._showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
|
||||
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor));
|
||||
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('.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);
|
||||
RdDUtility.confirmerSuppressionSubacteur(this, subActor, li, () => {
|
||||
console.log('Delete : ', subActor.id);
|
||||
this.actor.removeSubacteur(subActor.id);
|
||||
RdDUtility.slideOnDelete(this, li);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.html.find('.experiencelog-delete').click(async event => {
|
||||
@@ -136,6 +146,13 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(0, key + 1);
|
||||
});
|
||||
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("input.derivee-value[name='system.compteurs.experience.value']").change(async event => {
|
||||
this.actor.updateCompteurValue("experience", parseInt(event.target.value));
|
||||
});
|
||||
|
||||
this.html.find('.encaisser-direct').click(async event => {
|
||||
this.actor.encaisser();
|
||||
})
|
||||
@@ -151,33 +168,31 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
this.html.find('.creer-tache').click(async event => {
|
||||
this.createEmptyTache();
|
||||
});
|
||||
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));
|
||||
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('.creer-une-oeuvre').click(async event => {
|
||||
this.selectTypeOeuvreToCreate();
|
||||
});
|
||||
|
||||
// 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('.blessure-premierssoins-done').change(async event => {
|
||||
const blessure = this.getBlessure(event);
|
||||
await blessure?.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
|
||||
});
|
||||
|
||||
// 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-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
|
||||
@@ -249,9 +264,14 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
|
||||
// Points de reve actuel
|
||||
this.html.find('.ptreve-actuel a').click(async event => {
|
||||
this.actor.rollCarac('reve-actuel');
|
||||
this.actor.rollCarac('reve-actuel', true);
|
||||
});
|
||||
|
||||
// Suite empoignade
|
||||
this.html.find('.empoignade-label a').click(async event => {
|
||||
let emp = RdDSheetUtility.getItem(event, this.actor)
|
||||
RdDEmpoignade.onAttaqueEmpoignadeFromItem(emp)
|
||||
});
|
||||
// Roll Weapon1
|
||||
this.html.find('.arme-label a').click(async event => {
|
||||
let arme = this._getEventArmeCombat(event);
|
||||
@@ -345,29 +365,6 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
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);
|
||||
@@ -440,6 +437,12 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
});
|
||||
}
|
||||
|
||||
getBlessure(event) {
|
||||
const itemId = this.html.find(event.currentTarget).parents(".item-blessure").data('item-id');
|
||||
const blessure = this.actor.getItem(itemId, 'blessure');
|
||||
return blessure;
|
||||
}
|
||||
|
||||
isCompetenceAffichable(competence) {
|
||||
return !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(competence);
|
||||
}
|
||||
@@ -453,9 +456,9 @@ export class RdDActorSheet extends RdDBaseActorSheet {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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 +481,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");
|
||||
|
||||
1583
module/actor.js
1583
module/actor.js
File diff suppressed because it is too large
Load Diff
@@ -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";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
@@ -31,52 +32,56 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
|
||||
|
||||
this.actor.recompute();
|
||||
const userRightLevel = game.user.isGM ? CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER : 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,
|
||||
});
|
||||
|
||||
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 +115,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));
|
||||
@@ -135,7 +142,13 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
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;
|
||||
|
||||
@@ -143,6 +156,8 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
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 +167,28 @@ 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);
|
||||
});
|
||||
}
|
||||
|
||||
_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 +199,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 +234,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>';
|
||||
|
||||
@@ -3,8 +3,10 @@ import { SYSTEM_SOCKET_ID } from "../constants.js";
|
||||
import { Monnaie } from "../item-monnaie.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 {
|
||||
|
||||
@@ -20,14 +22,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;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +110,6 @@ export class RdDBaseActor extends Actor {
|
||||
isEntite() { return this.type == 'entite'; }
|
||||
isPersonnage() { return this.type == 'personnage'; }
|
||||
isVehicule() { return this.type == 'vehicule'; }
|
||||
|
||||
getItem(id, type = undefined) {
|
||||
const item = this.items.get(id);
|
||||
if (type == undefined || (item?.type == type)) {
|
||||
@@ -116,7 +119,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
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) });
|
||||
@@ -141,17 +144,29 @@ export class RdDBaseActor extends Actor {
|
||||
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
|
||||
}
|
||||
|
||||
async creerObjetParMJ(object){
|
||||
if (!Misc.isUniqueConnectedGM()) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: this.id,
|
||||
method: 'creerObjetParMJ',
|
||||
args: [object]
|
||||
});
|
||||
return;
|
||||
}
|
||||
await this.createEmbeddedDocuments('Item', [object])
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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 this.updateEmbeddedDocuments('Item', [{ _id: item.id, 'system.quantite': quantite }]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,14 +256,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 && !this.verifierQuantite(itemVendu, quantite)) {
|
||||
ChatUtility.notifyUser(achat.userId, 'warn', `Le vendeur n'a pas assez de ${itemVendu.name} !`);
|
||||
return
|
||||
}
|
||||
@@ -259,13 +276,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,
|
||||
@@ -274,16 +291,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);
|
||||
}
|
||||
}
|
||||
@@ -300,9 +317,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 = item?.getQuantite();
|
||||
return disponible == undefined || disponible >= quantiteDemande;
|
||||
}
|
||||
|
||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
||||
@@ -350,6 +367,14 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeMalusSurEncombrement() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
getEncombrementMax() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
async computeEncTotal() {
|
||||
if (!this.pack) {
|
||||
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
|
||||
|
||||
@@ -22,17 +22,38 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
||||
});
|
||||
}
|
||||
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 +69,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
return RdDItem.getItemTypesInventaire('all');
|
||||
}
|
||||
|
||||
|
||||
|
||||
async vente(item) {
|
||||
const acheteur = RdDUtility.getSelectedActor();
|
||||
if (!acheteur) {
|
||||
|
||||
@@ -22,7 +22,7 @@ export class RdDCommerce extends RdDBaseActor {
|
||||
}
|
||||
|
||||
getQuantiteDisponible(item) {
|
||||
return this.system.illimite || item.isService() ? undefined : item.getQuantite();
|
||||
return (this.system.illimite || item?.isService()) ? undefined : item.getQuantite();
|
||||
}
|
||||
|
||||
verifierFortune(cout) {
|
||||
|
||||
39
module/actor/experience-log.js
Normal file
39
module/actor/experience-log.js
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -78,11 +78,7 @@ export class ChatUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { SYSTEM_RDD } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDTimestamp } from "./rdd-timestamp.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
|
||||
|
||||
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
|
||||
@@ -24,52 +25,68 @@ export class DialogChronologie extends Dialog {
|
||||
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
|
||||
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
|
||||
timestamp: game.system.rdd.calendrier.timestamp,
|
||||
dateReel: DialogChronologie.getCurrentDateTime()
|
||||
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() {
|
||||
@@ -82,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() {
|
||||
@@ -97,23 +114,23 @@ export class DialogChronologie extends Dialog {
|
||||
heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()),
|
||||
minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").val(),
|
||||
},
|
||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val().replace('T', ' ')
|
||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val()
|
||||
}
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { RdDItemSigneDraconique } from "./item/item-signedraconique.js";
|
||||
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
export class DialogCreateSigneDraconique extends Dialog {
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -8,7 +8,7 @@ export class DialogItemVente extends Dialog {
|
||||
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(),
|
||||
@@ -40,52 +40,63 @@ export class DialogItemVente extends Dialog {
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.html = html;
|
||||
this.setQuantiteIllimite(this.venteData.quantiteIllimite);
|
||||
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
||||
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ 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, show, attackerId, 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,
|
||||
@@ -15,15 +15,15 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
encaissement: encaissement,
|
||||
show: show
|
||||
});
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, onEncaisser);
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser);
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(html, actor, rollData, armure, encaissement, show, onEncaisser) {
|
||||
constructor(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser) {
|
||||
// Common conf
|
||||
let buttons = {
|
||||
"valider": { label: "Valider", callback: html => this.validerEncaissement() },
|
||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
||||
"annuler": { label: "Annuler", callback: html => { } },
|
||||
};
|
||||
|
||||
@@ -48,6 +48,7 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
this.armure = armure;
|
||||
this.encaissement = encaissement;
|
||||
this.show = show;
|
||||
this.attackerId = attackerId;
|
||||
this.onEncaisser = onEncaisser;
|
||||
this.forceDiceResult = {total: encaissement.roll.result };
|
||||
}
|
||||
@@ -64,8 +65,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, this.show, this.attackerId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
export class HtmlUtility{
|
||||
static _showControlWhen(jQuerySelector, condition) {
|
||||
static showControlWhen(jQuerySelector, condition) {
|
||||
if (condition) {
|
||||
jQuerySelector.show();
|
||||
}
|
||||
|
||||
@@ -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,7 +20,7 @@ const nomCategorieParade = {
|
||||
export class RdDItemArme extends Item {
|
||||
|
||||
static isArme(item) {
|
||||
return (item.type == 'competencecreature' && item.system.iscombat) || item.type == 'arme';
|
||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) || item.type == 'arme';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -28,7 +28,7 @@ export class RdDItemArme extends Item {
|
||||
switch (arme ? arme.type : '') {
|
||||
case 'arme': return arme;
|
||||
case 'competencecreature':
|
||||
return RdDItemCompetenceCreature.armeNaturelle(arme);
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.mainsNues();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ export class RdDItemArme extends Item {
|
||||
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 }));
|
||||
armes.push(RdDItemArme.empoignade({ niveau: corpsACorps.system.niveau, initiative: init }));
|
||||
}
|
||||
|
||||
static corpsACorps(mainsNuesActor) {
|
||||
|
||||
@@ -23,7 +23,7 @@ const limitesArchetypes = [
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -190,18 +190,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());
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -279,7 +270,7 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static triVisible(competences) {
|
||||
return competences.filter(it => it.system.isVisible)
|
||||
return competences.filter(it => !it.system.isHidden)
|
||||
.sort((a, b) => RdDItemCompetence.compare(a, b))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +1,97 @@
|
||||
|
||||
import { RdDItem, 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;
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
case "lancer":
|
||||
case "naturelle":
|
||||
case "possession":
|
||||
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 !== "";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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))
|
||||
|
||||
@@ -10,7 +10,9 @@ 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 "./rdd-timestamp.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
|
||||
@@ -86,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 => RdDItemCompetence.isCompetenceArme(it))
|
||||
}
|
||||
if (['sort', 'sortreserve'].includes(this.item.type)) {
|
||||
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
|
||||
@@ -138,12 +139,12 @@ export class RdDItemSheet extends ItemSheet {
|
||||
if (this.item.type == 'potion') {
|
||||
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);
|
||||
|
||||
@@ -156,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"), ReglesOptionelles.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;
|
||||
@@ -191,7 +194,7 @@ export class RdDItemSheet extends ItemSheet {
|
||||
});
|
||||
|
||||
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('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
|
||||
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
|
||||
|
||||
this.html.find('.alchimie-tache a').click((event) => {
|
||||
@@ -206,12 +209,23 @@ 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) })
|
||||
|
||||
@@ -219,6 +233,16 @@ export class RdDItemSheet extends ItemSheet {
|
||||
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) {
|
||||
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||
let actor = game.actors.get(actorId);
|
||||
@@ -231,7 +255,8 @@ export class RdDItemSheet extends ItemSheet {
|
||||
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);
|
||||
}
|
||||
@@ -242,9 +267,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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] };
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export class RdDItemTache extends Item {
|
||||
|
||||
|
||||
}
|
||||
267
module/item.js
267
module/item.js
@@ -2,36 +2,88 @@ import { DialogItemVente } from "./dialog-item-vente.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||