Compare commits
No commits in common. "v10" and "foundryvtt-reve-de-dragon-10.0.8" have entirely different histories.
v10
...
foundryvtt
7
.gitignore
vendored
@ -1,10 +1,5 @@
|
|||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
.idea
|
.idea
|
||||||
.history
|
todo.txt
|
||||||
todo.md
|
todo.md
|
||||||
/.vscode
|
/.vscode
|
||||||
/ignored/
|
|
||||||
/node_modules/
|
|
||||||
/jsconfig.json
|
|
||||||
/package.json
|
|
||||||
/package-lock.json
|
|
||||||
|
302
changelog.md
@ -1,298 +1,10 @@
|
|||||||
# v10.7 - L'os de Sémolosse
|
==================================================================
|
||||||
|
v0.9.2 - 05/09/2020
|
||||||
|
|
||||||
## v10.7.20 - la poigne de Sémolosse
|
Erreur de calcul sur points de vie
|
||||||
- correction de méthodes qui filtrent les items
|
Gestion différente des compétences "troncs"
|
||||||
- recherche de cases TMR
|
|
||||||
- recherche de tâches de lecture
|
|
||||||
- recherche d'armure (pour le malus armure)
|
|
||||||
- recherche de potions
|
|
||||||
|
|
||||||
## v10.7.20 - la poigne de Sémolosse
|
==================================================================
|
||||||
- correction de l'empoignade
|
v0.9.1 - 03/09/2020
|
||||||
- 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
|
|
||||||
|
|
||||||
## v10.7.19 - les fantômes de Sémolosse
|
Initial official release
|
||||||
- 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
|
|
||||||
|
Before Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 6.3 KiB |
Before Width: | Height: | Size: 7.8 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 8.0 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 8.8 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.0 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 6.4 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 5.5 KiB |
61
lang/fr.json
@ -3,52 +3,45 @@
|
|||||||
"TypePersonnage": "Personnage",
|
"TypePersonnage": "Personnage",
|
||||||
"TypeCreature": "Créature",
|
"TypeCreature": "Créature",
|
||||||
"TypeEntite": "Entité de cauchemar",
|
"TypeEntite": "Entité de cauchemar",
|
||||||
"TypeCommerce": "Commerce",
|
|
||||||
"TypeVehicule": "Véhicule"
|
"TypeVehicule": "Véhicule"
|
||||||
},
|
},
|
||||||
"ITEM": {
|
"ITEM": {
|
||||||
"TypeArme": "Arme",
|
"TypeObjet": "Objet",
|
||||||
"TypeArmure": "Armure",
|
"TypeGemme": "Gemme",
|
||||||
"TypeBlessure": "Blessure",
|
|
||||||
"TypeCasetmr": "TMR spéciale",
|
|
||||||
"TypeChant": "Chant",
|
|
||||||
"TypeCompetence": "Compétence",
|
"TypeCompetence": "Compétence",
|
||||||
"TypeCompetencecreature": "Compétence de créature",
|
"TypeCompetencecreature": "Compétence de créature",
|
||||||
"TypeConteneur": "Conteneur",
|
|
||||||
"TypeDanse": "Danse",
|
|
||||||
"TypeExtraitpoetique": "Extrait poetique",
|
|
||||||
"TypeFaune": "Faune",
|
|
||||||
"TypeGemme": "Gemme",
|
|
||||||
"TypeHerbe": "Herbe",
|
|
||||||
"TypeIngredient": "Ingrédient",
|
|
||||||
"TypeJeu": "Jeu",
|
|
||||||
"TypeLivre": "Livre",
|
|
||||||
"TypeMaladie": "Maladie",
|
"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",
|
"TypePoison": "Poison",
|
||||||
"TypePossession": "Possession",
|
"TypeNombreastral": "Nombre astral",
|
||||||
|
"TypeTarot": "Carte de tarot",
|
||||||
|
"TypeCasetmr": "TMR spéciale",
|
||||||
|
"TypeRencontrestmr": "Rencontre TMR",
|
||||||
|
"TypeMunition": "Munition",
|
||||||
|
"TypeMonnaie": "Monnaie",
|
||||||
|
"TypeHerbe": "Herbe ou plante",
|
||||||
|
"TypeIngredient": "Ingrédient",
|
||||||
|
"TypeLivre": "Livre",
|
||||||
"TypePotion": "Potion",
|
"TypePotion": "Potion",
|
||||||
"TypeQueue": "Queue de Dragon",
|
"TypeArme": "Arme",
|
||||||
|
"TypeArmure": "Armure",
|
||||||
|
"TypeConteneur": "Conteneur",
|
||||||
|
"TypeNourritureboisson": "Nourriture & boisson",
|
||||||
|
"TypeChant": "Chant",
|
||||||
|
"TypeDanse": "Danse",
|
||||||
|
"TypeMusique": "Musique",
|
||||||
|
"TypeOeuvre": "Oeuvre",
|
||||||
|
"TypeTache": "Tâche",
|
||||||
|
"TypeJeu": "Jeu",
|
||||||
"TypeRecettealchimique": "Recette alchimique",
|
"TypeRecettealchimique": "Recette alchimique",
|
||||||
"TypeRecettecuisine": "Recette de cuisine",
|
"TypeRecettecuisine": "Recette de cuisine",
|
||||||
"TypeRencontre": "Rencontre TMR",
|
|
||||||
"TypeService": "Service",
|
|
||||||
"TypeSignedraconique": "Signe draconique",
|
|
||||||
"TypeSort": "Sort",
|
"TypeSort": "Sort",
|
||||||
"TypeSortreserve": "Sort en réserve",
|
"TypeMeditation": "Méditation",
|
||||||
|
"TypeSignedraconique": "Signe draconique",
|
||||||
|
"TypeQueue": "Queue de Dragon",
|
||||||
|
"TypeOmbre": "Ombre de Thanatos",
|
||||||
"TypeSouffle": "Souffle de Dragon",
|
"TypeSouffle": "Souffle de Dragon",
|
||||||
"TypeTache": "Tâche",
|
"TypeTete": "Tête de Dragon",
|
||||||
"TypeTarot": "Carte de tarot",
|
"TypePossession": "Possession"
|
||||||
"TypeTete": "Tête de Dragon"
|
|
||||||
},
|
},
|
||||||
"EFFECT": {
|
"EFFECT": {
|
||||||
"StatusStunned": "Sonné",
|
"StatusStunned": "Sonné",
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
import { RdDActorSheet } from "./actor-sheet.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend the basic ActorSheet with some very simple modifications
|
* Extend the basic ActorSheet with some very simple modifications
|
||||||
* @extends {ActorSheet}
|
* @extends {ActorSheet}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
import { RdDActorSheet } from "./actor-sheet.js";
|
||||||
|
import { RdDCarac } from "./rdd-carac.js";
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
export class RdDActorCreatureSheet extends RdDActorSheet {
|
export class RdDActorCreatureSheet extends RdDActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
@ -14,30 +20,60 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
|
|||||||
width: 640,
|
width: 640,
|
||||||
height: 720,
|
height: 720,
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async getData() {
|
||||||
|
let formData = await super.getData()
|
||||||
|
//console.log("Creature : ", formData, formData.system)
|
||||||
|
formData.calc = {
|
||||||
|
caracTotal: RdDCarac.computeTotal(formData.data.carac),
|
||||||
|
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
|
||||||
|
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
|
||||||
|
surEncombrementMessage: this.actor.getMessageSurEncombrement()
|
||||||
|
}
|
||||||
|
|
||||||
|
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||||
|
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||||
|
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||||
|
|
||||||
|
console.log("Creature : ", this.objetVersConteneur, formData);
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
// On competence change
|
// On competence change
|
||||||
this.html.find('.creature-carac').change(async event => {
|
html.find('.creature-carac').change(async event => {
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
||||||
});
|
});
|
||||||
this.html.find('.creature-niveau').change(async event => {
|
html.find('.creature-niveau').change(async event => {
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
|
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
|
||||||
});
|
});
|
||||||
this.html.find('.creature-dommages').change(async event => {
|
html.find('.creature-dommages').change(async event => {
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
|
_updateObject(event, formData) {
|
||||||
|
// Update the Actor
|
||||||
|
return this.object.update(formData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,65 +1,146 @@
|
|||||||
import { RdDActorSheet } from "./actor-sheet.js";
|
/**
|
||||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
* Extend the basic ActorSheet with some very simple modifications
|
||||||
|
* @extends {ActorSheet}
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
import { RdDUtility } from "./rdd-utility.js";
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
export class RdDActorEntiteSheet extends RdDActorSheet {
|
/* -------------------------------------------- */
|
||||||
|
export class RdDActorEntiteSheet extends ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
return mergeObject(super.defaultOptions, {
|
return mergeObject(super.defaultOptions, {
|
||||||
classes: ["rdd", "sheet", "actor"],
|
classes: ["rdd", "sheet", "actor"],
|
||||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
|
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
|
||||||
width: 640,
|
width: 640,
|
||||||
height: 720,
|
height: 720,
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac"}],
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
dragDrop: [{dragSelector: ".item-list .item", dropSelector: null}]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
async getData() {
|
async getData() {
|
||||||
let formData = await super.getData();
|
const objectData = this.object;
|
||||||
formData.resonances = this.actor.system.sante.resonnance.actors.map(actorId => game.actors.get(actorId))
|
let formData = {
|
||||||
.map(actor => { return { id: actor.id, name: actor.name, img: actor.img } })
|
title: this.title,
|
||||||
return formData
|
id: objectData.id,
|
||||||
|
type: objectData.type,
|
||||||
|
img: objectData.img,
|
||||||
|
name: objectData.name,
|
||||||
|
// actor: this.object,
|
||||||
|
editable: this.isEditable,
|
||||||
|
cssClass: this.isEditable ? "editable" : "locked",
|
||||||
|
data: foundry.utils.deepClone(this.actor.system),
|
||||||
|
effects: this.object.effects.map(e => foundry.utils.deepClone(e)),
|
||||||
|
// items: items,
|
||||||
|
limited: this.object.limited,
|
||||||
|
options: this.options,
|
||||||
|
owner: this.document.isOwner,
|
||||||
|
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i))),
|
||||||
|
};
|
||||||
|
|
||||||
|
formData.options.isGM = game.user.isGM;
|
||||||
|
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||||
|
|
||||||
|
|
||||||
|
return formData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
|
// Update Inventory Item
|
||||||
|
html.find('.item-edit').click(event => {
|
||||||
|
const li = $(event.currentTarget).parents(".item");
|
||||||
|
const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
|
||||||
|
item.sheet.render(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Delete Inventory Item
|
||||||
|
html.find('.item-delete').click(event => {
|
||||||
|
const li = $(event.currentTarget).parents(".item");
|
||||||
|
this.actor.deleteEmbeddedDocuments('Item', [li.data("itemId")]);
|
||||||
|
li.slideUp(200, () => this.render(false));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Roll Carac
|
||||||
|
html.find('.carac-label a').click(async event => {
|
||||||
|
let caracName = event.currentTarget.attributes.name.value;
|
||||||
|
this.actor.rollCarac( caracName.toLowerCase() );
|
||||||
|
});
|
||||||
|
|
||||||
// On competence change
|
// On competence change
|
||||||
this.html.find('.creature-carac').change(async event => {
|
html.find('.creature-carac').change(async event => {
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
this.actor.updateCreatureCompetence(compName, "carac_value", parseInt(event.target.value));
|
this.actor.updateCreatureCompetence( compName, "carac_value", parseInt(event.target.value) );
|
||||||
|
} );
|
||||||
|
html.find('.creature-niveau').change(async event => {
|
||||||
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
|
this.actor.updateCreatureCompetence( compName, "niveau", parseInt(event.target.value) );
|
||||||
|
} );
|
||||||
|
html.find('.creature-dommages').change(async event => {
|
||||||
|
let compName = event.currentTarget.attributes.compname.value;
|
||||||
|
this.actor.updateCreatureCompetence( compName, "dommages", parseInt(event.target.value) );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// Roll Skill
|
||||||
|
html.find('.competence-label a').click(async event => {
|
||||||
|
let compName = event.currentTarget.text;
|
||||||
|
this.actor.rollCompetence( compName );
|
||||||
});
|
});
|
||||||
this.html.find('.creature-niveau').change(async event => {
|
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
html.find('.endurance-plus').click(event => {
|
||||||
this.actor.updateCreatureCompetence(compName, "niveau", parseInt(event.target.value));
|
this.actor.santeIncDec("endurance", 1);
|
||||||
|
this.render(true);
|
||||||
});
|
});
|
||||||
this.html.find('.creature-dommages').change(async event => {
|
html.find('.endurance-moins').click(event => {
|
||||||
let compName = event.currentTarget.attributes.compname.value;
|
this.actor.santeIncDec("endurance", -1);
|
||||||
this.actor.updateCreatureCompetence(compName, "dommages", parseInt(event.target.value));
|
this.render(true);
|
||||||
});
|
});
|
||||||
this.html.find('.resonance-delete').click(async event => {
|
|
||||||
const li = RdDSheetUtility.getEventElement(event);
|
html.find('.encaisser-direct').click(event => {
|
||||||
const actorId = li.data("actor-id");
|
this.actor.encaisser();
|
||||||
if (actorId) {
|
});
|
||||||
const actorResonance = game.actors.get(actorId);
|
|
||||||
RdDUtility.confirmerSuppressionSubacteur(this, actorResonance, li, () => {
|
html.find('.remise-a-neuf').click(event => {
|
||||||
console.log('Delete : ', actorId);
|
if (game.user.isGM) {
|
||||||
this.removeSubacteur(actorId);
|
this.actor.remiseANeuf();
|
||||||
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 });
|
|
||||||
|
/** @override */
|
||||||
|
setPosition(options = {}) {
|
||||||
|
const position = super.setPosition(options);
|
||||||
|
const sheetHeader = this.element.find(".sheet-header");
|
||||||
|
const sheetTabs = this.element.find(".sheet-tabs");
|
||||||
|
const sheetBody = this.element.find(".sheet-body");
|
||||||
|
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
|
||||||
|
sheetBody.css("height", bodyHeight);
|
||||||
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
_updateObject(event, formData) {
|
||||||
|
// Update the Actor
|
||||||
|
return this.object.update(formData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Extend the basic ActorSheet with some very simple modifications
|
||||||
|
* @extends {ActorSheet}
|
||||||
|
*/
|
||||||
|
|
||||||
import { RdDUtility } from "./rdd-utility.js";
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
import { RdDActorSheet } from "./actor-sheet.js";
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
|
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class RdDActorVehiculeSheet extends RdDActorSheet {
|
export class RdDActorVehiculeSheet extends ActorSheet {
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
@ -14,26 +21,145 @@ export class RdDActorVehiculeSheet extends RdDActorSheet {
|
|||||||
width: 640,
|
width: 640,
|
||||||
height: 720,
|
height: 720,
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async getData() {
|
||||||
|
const objectData = this.object
|
||||||
|
let formData = {
|
||||||
|
title: this.title,
|
||||||
|
id: objectData.id,
|
||||||
|
type: objectData.type,
|
||||||
|
img: objectData.img,
|
||||||
|
name: objectData.name,
|
||||||
|
editable: this.isEditable,
|
||||||
|
cssClass: this.isEditable ? "editable" : "locked",
|
||||||
|
data: foundry.utils.deepClone(this.object.system),
|
||||||
|
effects: this.object.effects.map(e => foundry.utils.deepClone(e)),
|
||||||
|
limited: this.object.limited,
|
||||||
|
options: this.options,
|
||||||
|
owner: this.document.isOwner,
|
||||||
|
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i))),
|
||||||
|
};
|
||||||
|
|
||||||
|
RdDUtility.filterItemsPerTypeForSheet(formData);
|
||||||
|
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||||
|
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
|
||||||
|
|
||||||
|
formData.options.isGM = game.user.isGM;
|
||||||
|
|
||||||
|
formData.calc = {
|
||||||
|
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
|
||||||
|
surEncombrementMessage: this.actor.getMessageSurEncombrement()
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("DATA", formData);
|
||||||
|
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async computeMalusArmure() {
|
||||||
|
// pas de malus armure
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async _onDropItem(event, dragData) {
|
||||||
|
const destItemId = $(event.target)?.closest('.item').attr('data-item-id');
|
||||||
|
const dropParams = RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor.id, dragData, this.objetVersConteneur);
|
||||||
|
const callSuper = await this.actor.processDropItem(dropParams);
|
||||||
|
if (callSuper) {
|
||||||
|
await super._onDropItem(event, dragData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async createItem(name, type) {
|
||||||
|
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async 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, 'data.quantite': quantite }]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
|
||||||
|
|
||||||
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
this.html.find('.resistance-moins').click(async event => {
|
// Update Inventory Item
|
||||||
this.actor.vehicleIncDec("resistance", -1);
|
html.find('.item-edit').click(async event => {
|
||||||
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
|
item.sheet.render(true);
|
||||||
});
|
});
|
||||||
this.html.find('.resistance-plus').click(async event => {
|
// Delete Inventory Item
|
||||||
this.actor.vehicleIncDec("resistance", 1);
|
html.find('.item-delete').click(async event => {
|
||||||
|
const li = RdDSheetUtility.getEventElement(event);
|
||||||
|
RdDUtility.confirmerSuppression(this, li);
|
||||||
});
|
});
|
||||||
this.html.find('.structure-moins').click(async event => {
|
html.find('.item-vendre').click(async event => {
|
||||||
this.actor.vehicleIncDec("structure", -1);
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
|
item?.proposerVente();
|
||||||
});
|
});
|
||||||
this.html.find('.structure-plus').click(async event => {
|
html.find('.item-montrer').click(async event => {
|
||||||
this.actor.vehicleIncDec("structure", 1);
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
|
item?.postItem();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
html.find('.item-action').click(async event => {
|
||||||
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
|
this.actor.actionItem(item);
|
||||||
|
});
|
||||||
|
|
||||||
|
html.find('.creer-un-objet').click(async event => {
|
||||||
|
RdDUtility.selectObjetType(this);
|
||||||
|
});
|
||||||
|
html.find('#nettoyer-conteneurs').click(async event => {
|
||||||
|
this.actor.nettoyerConteneurs();
|
||||||
|
});
|
||||||
|
|
||||||
|
html.find('.monnaie-plus').click(async event => {
|
||||||
|
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), 1);
|
||||||
|
});
|
||||||
|
html.find('.monnaie-moins').click(async event => {
|
||||||
|
this.actor.monnaieIncDec(RdDSheetUtility.getItemId(event), -1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display info about queue
|
||||||
|
html.find('.conteneur-name a').click((event) => {
|
||||||
|
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
||||||
|
this.render(true);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
|
setPosition(options = {}) {
|
||||||
|
const position = super.setPosition(options);
|
||||||
|
const sheetHeader = this.element.find(".sheet-header");
|
||||||
|
const sheetTabs = this.element.find(".sheet-tabs");
|
||||||
|
const sheetBody = this.element.find(".sheet-body");
|
||||||
|
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
|
||||||
|
sheetBody.css("height", bodyHeight);
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
|
_updateObject(event, formData) {
|
||||||
|
// Update the Actor
|
||||||
|
return this.object.update(formData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
3162
module/actor.js
@ -1,301 +0,0 @@
|
|||||||
import { RdDUtility } from "../rdd-utility.js";
|
|
||||||
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, TYPES } from "../item.js";
|
|
||||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/**
|
|
||||||
* Extend the basic ActorSheet with some very simple modifications
|
|
||||||
* @extends {ActorSheet}
|
|
||||||
*/
|
|
||||||
export class RdDBaseActorSheet extends ActorSheet {
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
static get defaultOptions() {
|
|
||||||
RdDUtility.initAfficheContenu();
|
|
||||||
return mergeObject(super.defaultOptions, {
|
|
||||||
classes: ["rdd", "sheet", "actor"],
|
|
||||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
|
|
||||||
width: 550,
|
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
|
|
||||||
showCompNiveauBase: false,
|
|
||||||
vueDetaillee: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async getData() {
|
|
||||||
Monnaie.validerMonnaies(this.actor.itemTypes['monnaie']);
|
|
||||||
|
|
||||||
this.actor.recompute();
|
|
||||||
let formData = {
|
|
||||||
title: this.title,
|
|
||||||
id: this.actor.id,
|
|
||||||
type: this.actor.type,
|
|
||||||
img: this.actor.img,
|
|
||||||
name: this.actor.name,
|
|
||||||
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: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable)
|
|
||||||
}
|
|
||||||
|
|
||||||
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
|
||||||
formData.calc = {
|
|
||||||
fortune: Monnaie.toSolsDeniers(this.actor.getFortune()),
|
|
||||||
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
|
|
||||||
encTotal: await this.actor.computeEncTotal(),
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
_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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
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']);
|
|
||||||
formData.poisons = Misc.arrayOrEmpty(itemTypes['poison']);
|
|
||||||
formData.possessions = Misc.arrayOrEmpty(itemTypes['possession']);
|
|
||||||
formData.maladiesPoisons = formData.maladies.concat(formData.poisons);
|
|
||||||
formData.competences = (itemTypes['competence'] ?? []).concat(itemTypes['competencecreature'] ?? []);
|
|
||||||
formData.sortsReserve = Misc.arrayOrEmpty(itemTypes['sortreserve']);
|
|
||||||
|
|
||||||
formData.sorts = Misc.arrayOrEmpty(itemTypes['sort']);
|
|
||||||
formData.rencontres = Misc.arrayOrEmpty(itemTypes['rencontre']);
|
|
||||||
formData.casestmr = Misc.arrayOrEmpty(itemTypes['casetmr']);
|
|
||||||
formData.signesdraconiques = Misc.arrayOrEmpty(itemTypes['signedraconique']);
|
|
||||||
formData.queues = Misc.arrayOrEmpty(itemTypes['queue']);
|
|
||||||
formData.souffles = Misc.arrayOrEmpty(itemTypes['souffle']);
|
|
||||||
formData.ombres = Misc.arrayOrEmpty(itemTypes['ombre']);
|
|
||||||
formData.tetes = Misc.arrayOrEmpty(itemTypes['tete']);
|
|
||||||
formData.taches = Misc.arrayOrEmpty(itemTypes['tache']);
|
|
||||||
formData.meditations = Misc.arrayOrEmpty(itemTypes['meditation']);
|
|
||||||
formData.chants = Misc.arrayOrEmpty(itemTypes['chant']);
|
|
||||||
formData.danses = Misc.arrayOrEmpty(itemTypes['danse']);
|
|
||||||
formData.musiques = Misc.arrayOrEmpty(itemTypes['musique']);
|
|
||||||
formData.oeuvres = Misc.arrayOrEmpty(itemTypes['oeuvre']);
|
|
||||||
formData.jeux = Misc.arrayOrEmpty(itemTypes['jeu']);
|
|
||||||
|
|
||||||
formData.services = Misc.arrayOrEmpty(itemTypes['service']);
|
|
||||||
formData.conteneurs = Misc.arrayOrEmpty(itemTypes['conteneur']);
|
|
||||||
formData.materiel = Misc.arrayOrEmpty(itemTypes['objet']);
|
|
||||||
formData.armes = Misc.arrayOrEmpty(itemTypes['arme']);
|
|
||||||
formData.armures = Misc.arrayOrEmpty(itemTypes['armure']);
|
|
||||||
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.monnaies = Misc.arrayOrEmpty(itemTypes['monnaie']).sort(Monnaie.triValeurEntiere());
|
|
||||||
formData.objets = Misc.arrayOrEmpty(itemTypes['objet'])
|
|
||||||
|
|
||||||
formData.inventaires = RdDItem.getItemTypesInventaire('all')
|
|
||||||
.map(t => Misc.arrayOrEmpty(itemTypes[t]))
|
|
||||||
.reduce((a, b) => a.concat(b), [])
|
|
||||||
.sort(Misc.ascending(it => it.name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */ /** @override */
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
this.html = html;
|
|
||||||
|
|
||||||
this.html.find('.conteneur-name a').click(async event => {
|
|
||||||
RdDUtility.toggleAfficheContenu(this.getItemId(event));
|
|
||||||
this.render(true);
|
|
||||||
});
|
|
||||||
this.html.find('.item-edit').click(async event => this.getItem(event)?.sheet.render(true))
|
|
||||||
this.html.find('.item-montrer').click(async event => this.getItem(event)?.postItemToChat());
|
|
||||||
this.html.find('.actor-montrer').click(async event => this.actor.postActorToChat());
|
|
||||||
this.html.find('.recherche')
|
|
||||||
.each((index, field) => {
|
|
||||||
this._rechercheSelectArea(field);
|
|
||||||
})
|
|
||||||
.keyup(async event => this._rechercherKeyup(event))
|
|
||||||
.change(async event => this._rechercherKeyup(event));
|
|
||||||
this.html.find('.recherche').prop("disabled", false);
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
|
|
||||||
this.html.find('.item-split').click(async event => {
|
|
||||||
const item = this.getItem(event);
|
|
||||||
RdDSheetUtility.splitItem(item, this.actor);
|
|
||||||
});
|
|
||||||
this.html.find('.item-quantite-plus').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), 1));
|
|
||||||
this.html.find('.item-quantite-moins').click(async event => this.actor.itemQuantiteIncDec(this.getItemId(event), -1));
|
|
||||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, this.getItem(event)));
|
|
||||||
this.html.find('.item-vendre').click(async event => this.vendre(this.getItem(event)));
|
|
||||||
|
|
||||||
this.html.find('.creer-un-objet').click(async event => {
|
|
||||||
this.selectObjetTypeToCreate();
|
|
||||||
});
|
|
||||||
this.html.find('.nettoyer-conteneurs').click(async event => {
|
|
||||||
this.actor.nettoyerConteneurs();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_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) {
|
|
||||||
return RdDSheetUtility.getItemId(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
getItem(event) {
|
|
||||||
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();
|
|
||||||
buttons.unshift({
|
|
||||||
class: "montrer",
|
|
||||||
icon: "fas fa-comment",
|
|
||||||
onclick: ev => this.actor.postActorToChat()
|
|
||||||
});
|
|
||||||
return buttons
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async _onDropItem(event, dragData) {
|
|
||||||
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id')
|
|
||||||
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur)
|
|
||||||
if (dropParams) {
|
|
||||||
const callSuper = await this.actor.processDropItem(dropParams)
|
|
||||||
if (callSuper) {
|
|
||||||
await super._onDropItem(event, dragData)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async selectObjetTypeToCreate() {
|
|
||||||
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 types) {
|
|
||||||
content += `<option value="${typeName}">${Misc.typeName('Item', typeName)}</option>`
|
|
||||||
}
|
|
||||||
content += '</select>';
|
|
||||||
let d = new Dialog({
|
|
||||||
title: "Créer un équipement",
|
|
||||||
content: content,
|
|
||||||
buttons: {
|
|
||||||
create: {
|
|
||||||
icon: '<i class="fas fa-check"></i>',
|
|
||||||
label: "Créer l'objet",
|
|
||||||
callback: () => this.actor.createItem($(".item-type").val())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
d.render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTypesInventaire() {
|
|
||||||
return RdDItem.getItemTypesInventaire();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
setPosition(options = {}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetHeader = this.element.find(".sheet-header");
|
|
||||||
const sheetTabs = this.element.find(".sheet-tabs");
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
let bodyHeight = position.height - sheetHeader[0].clientHeight;
|
|
||||||
if (sheetTabs.length > 0) {
|
|
||||||
bodyHeight -= sheetTabs[0].clientHeight;
|
|
||||||
}
|
|
||||||
sheetBody.css("height", bodyHeight);
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
_updateObject(event, formData) {
|
|
||||||
// Update the Actor
|
|
||||||
return this.actor.update(formData);
|
|
||||||
}
|
|
||||||
|
|
||||||
async splitItem(item) {
|
|
||||||
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
|
|
||||||
dialog.render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onSplitItem(item, split) {
|
|
||||||
if (split >= 1 && split < item.system.quantite) {
|
|
||||||
await item.diminuerQuantite(split);
|
|
||||||
const splitItem = duplicate(item);
|
|
||||||
splitItem.system.quantite = split;
|
|
||||||
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vendre(item) {
|
|
||||||
item?.proposerVente(this.actor.getQuantiteDisponible(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,644 +0,0 @@
|
|||||||
import { ChatUtility } from "../chat-utility.js";
|
|
||||||
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 {
|
|
||||||
|
|
||||||
static getDefaultImg(itemType) {
|
|
||||||
return game.system.rdd.actorClasses[itemType]?.defaultIcon ?? defaultItemImg[itemType];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static init() {
|
|
||||||
Hooks.on("preUpdateItem", (item, change, options, id) => RdDBaseActor.getParentActor(item)?.onPreUpdateItem(item, change, options, id));
|
|
||||||
Hooks.on("createItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onCreateItem(item, options, id));
|
|
||||||
Hooks.on("deleteItem", (item, options, id) => RdDBaseActor.getParentActor(item)?.onDeleteItem(item, options, id));
|
|
||||||
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":
|
|
||||||
game.user.character.resetNombresAstraux();
|
|
||||||
game.system.rdd.calendrier.notifyChangeNombresAstraux();
|
|
||||||
return;
|
|
||||||
case "msg_refresh_nombre_astral":
|
|
||||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static remoteActorCall(callData, userId = undefined) {
|
|
||||||
userId = userId ?? Misc.firstConnectedGMId();
|
|
||||||
if (userId == game.user.id) {
|
|
||||||
RdDBaseActor.onRemoteActorCall(callData, userId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_remote_actor_call", data: callData, userId: userId });
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static onRemoteActorCall(callData, userId) {
|
|
||||||
if (userId == game.user.id) {
|
|
||||||
const actor = game.actors.get(callData?.actorId);
|
|
||||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM(actor)) { // Seul le joueur choisi effectue l'appel: le joueur courant si propriétaire de l'actor, ou le MJ sinon
|
|
||||||
const args = callData.args;
|
|
||||||
console.info(`RdDBaseActor.onRemoteActorCall: pour l'Actor ${callData.actorId}, appel de RdDBaseActor.${callData.method}(`, ...args, ')');
|
|
||||||
actor[callData.method](...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static getParentActor(document) {
|
|
||||||
return document?.parent instanceof Actor ? document.parent : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cet methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
|
|
||||||
* compétences et monnaies.
|
|
||||||
*
|
|
||||||
* @param {Object} actorData template d'acteur auquel ajouter des informations.
|
|
||||||
* @param {Object} options optionspour customiser la création
|
|
||||||
*/
|
|
||||||
static async create(actorData, options) {
|
|
||||||
// import depuis un compendium
|
|
||||||
if (actorData instanceof Array) {
|
|
||||||
return super.create(actorData, options);
|
|
||||||
}
|
|
||||||
// Création d'un acteur avec des items (uniquement en cas de duplication): pas besoin d'ajouter d'items
|
|
||||||
if (actorData.items) {
|
|
||||||
return await super.create(actorData, options);
|
|
||||||
}
|
|
||||||
actorData.items = [];
|
|
||||||
if (actorData.type == "personnage") {
|
|
||||||
const competences = await SystemCompendiums.getCompetences(actorData.type);
|
|
||||||
actorData.items = actorData.items.concat(competences.map(i => i.toObject()))
|
|
||||||
.concat(Monnaie.monnaiesStandard());
|
|
||||||
}
|
|
||||||
else if (actorData.type == "commerce") {
|
|
||||||
actorData.items = actorData.items.concat(Monnaie.monnaiesStandard());
|
|
||||||
}
|
|
||||||
return super.create(actorData, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(docData, context = {}) {
|
|
||||||
if (!context.rdd?.ready) {
|
|
||||||
mergeObject(context, { rdd: { ready: true } });
|
|
||||||
const ActorConstructor = game.system.rdd.actorClasses[docData.type];
|
|
||||||
if (ActorConstructor) {
|
|
||||||
if (!docData.img) {
|
|
||||||
docData.img = ActorConstructor.defaultIcon;
|
|
||||||
}
|
|
||||||
return new ActorConstructor(docData, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super(docData, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
isCreatureEntite() { return this.type == 'creature' || this.type == 'entite'; }
|
|
||||||
isCreature() { return this.type == 'creature'; }
|
|
||||||
isEntite() { return this.type == 'entite'; }
|
|
||||||
isPersonnage() { return this.type == 'personnage'; }
|
|
||||||
isVehicule() { return this.type == 'vehicule'; }
|
|
||||||
getItem(id, type = undefined) {
|
|
||||||
const item = this.items.get(id);
|
|
||||||
if (type == undefined || (item?.type == type)) {
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
listItems(type = undefined) { return (type ? this.itemTypes[type] : this.items); }
|
|
||||||
filterItems(filter, type = undefined) { return (type ? this.itemTypes[type] : this.items)?.filter(filter); }
|
|
||||||
findItemLike(idOrName, type) {
|
|
||||||
return this.getItem(idOrName, type)
|
|
||||||
?? Misc.findFirstLike(idOrName, this.listItems(type), { description: Misc.typeName('Item', type) });
|
|
||||||
}
|
|
||||||
|
|
||||||
getMonnaie(id) { return this.findItemLike(id, 'monnaie'); }
|
|
||||||
|
|
||||||
recompute() { }
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async onPreUpdateItem(item, change, options, id) { }
|
|
||||||
|
|
||||||
async onCreateItem(item, options, id) { }
|
|
||||||
|
|
||||||
async onDeleteItem(item, options, id) { }
|
|
||||||
|
|
||||||
async onUpdateActor(update, options, actorId) { }
|
|
||||||
|
|
||||||
async onTimeChanging(oldTimestamp, newTimestamp) {
|
|
||||||
this.items.filter(it => it.isFinPeriode(oldTimestamp, newTimestamp))
|
|
||||||
.forEach(async it => await it.onFinPeriodeTemporel(oldTimestamp, newTimestamp))
|
|
||||||
}
|
|
||||||
|
|
||||||
async creerObjetParMJ(object){
|
|
||||||
if (!Misc.isUniqueConnectedGM()) {
|
|
||||||
RdDBaseActor.remoteActorCall({
|
|
||||||
actorId: this.id,
|
|
||||||
method: 'creerObjetParMJ',
|
|
||||||
args: [object]
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.createEmbeddedDocuments('Item', [object])
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
getFortune() {
|
|
||||||
return Monnaie.getFortune(this.itemTypes['monnaie']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
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 }]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
computePrixTotalEquipement() {
|
|
||||||
return this.items.filter(it => it.isInventaire())
|
|
||||||
.filter(it => !it.isMonnaie())
|
|
||||||
.map(it => it.valeurTotale())
|
|
||||||
.reduce(Misc.sum(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
async payerSols(depense) {
|
|
||||||
depense = Number(depense);
|
|
||||||
if (depense == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let fortune = this.getFortune();
|
|
||||||
console.log("payer", game.user.character, depense, fortune);
|
|
||||||
let msg = "";
|
|
||||||
if (fortune >= depense) {
|
|
||||||
await Monnaie.optimiserFortune(this, fortune - depense);
|
|
||||||
msg = `Vous avez payé <strong>${depense} Sols</strong>, qui ont été soustraits de votre argent.`;
|
|
||||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
|
||||||
} else {
|
|
||||||
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = {
|
|
||||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
|
||||||
content: msg
|
|
||||||
};
|
|
||||||
ChatMessage.create(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
async depenserSols(sols) {
|
|
||||||
let reste = this.getFortune() - Number(sols);
|
|
||||||
if (reste >= 0) {
|
|
||||||
await Monnaie.optimiserFortune(this, reste);
|
|
||||||
}
|
|
||||||
return reste;
|
|
||||||
}
|
|
||||||
|
|
||||||
async ajouterSols(sols, fromActorId = undefined) {
|
|
||||||
sols = Number(sols);
|
|
||||||
if (sols == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (sols < 0) {
|
|
||||||
ui.notifications.error(`Impossible d'ajouter un gain de ${sols} <0`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (fromActorId && !game.user.isGM) {
|
|
||||||
RdDBaseActor.remoteActorCall({
|
|
||||||
userId: Misc.connectedGMOrUser(),
|
|
||||||
actorId: this.id,
|
|
||||||
method: 'ajouterSols', args: [sols, fromActorId]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const fromActor = game.actors.get(fromActorId)
|
|
||||||
await Monnaie.optimiserFortune(this, sols + this.getFortune());
|
|
||||||
|
|
||||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
|
||||||
ChatMessage.create({
|
|
||||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
|
||||||
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
|
|
||||||
getQuantiteDisponible(item) {
|
|
||||||
return item?.isService() ? undefined : item?.getQuantite();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async achatVente(achat) {
|
|
||||||
if (achat.vendeurId == achat.acheteurId) {
|
|
||||||
ui.notifications.info("Inutile de se vendre à soi-même");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!Misc.isUniqueConnectedGM()) {
|
|
||||||
RdDBaseActor.remoteActorCall({
|
|
||||||
actorId: achat.vendeurId ?? achat.acheteurId,
|
|
||||||
method: 'achatVente',
|
|
||||||
args: [achat]
|
|
||||||
});
|
|
||||||
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 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
|
|
||||||
}
|
|
||||||
if (acheteur && !acheteur.verifierFortune(cout)) {
|
|
||||||
ChatUtility.notifyUser(achat.userId, 'warn', `Vous n'avez pas assez d'argent pour payer ${Math.ceil(cout / 100)} sols !`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await this.decrementerVente(vendeur, itemVendu, quantite, cout);
|
|
||||||
if (acheteur) {
|
|
||||||
await acheteur.depenserSols(cout);
|
|
||||||
const createdItemId = await acheteur.creerQuantiteItem(itemVendu, quantite);
|
|
||||||
await acheteur.consommerNourritureAchetee(achat, achat.vente, createdItemId);
|
|
||||||
}
|
|
||||||
if (cout > 0) {
|
|
||||||
RdDAudio.PlayContextAudio("argent");
|
|
||||||
}
|
|
||||||
const chatAchatItem = duplicate(achat.vente);
|
|
||||||
chatAchatItem.quantiteTotal = quantite;
|
|
||||||
ChatMessage.create({
|
|
||||||
user: achat.userId,
|
|
||||||
speaker: { alias: (acheteur ?? vendeur).name },
|
|
||||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
|
||||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!achat.vente.quantiteIllimite) {
|
|
||||||
if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) {
|
|
||||||
ChatUtility.removeChatMessageId(achat.chatMessageIdVente);
|
|
||||||
}
|
|
||||||
else if (achat.chatMessageIdVente) {
|
|
||||||
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', achat.vente) });
|
|
||||||
messageVente.render(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async decrementerVente(vendeur, itemVendu, quantite, cout) {
|
|
||||||
if (vendeur) {
|
|
||||||
await vendeur.ajouterSols(cout);
|
|
||||||
await vendeur.decrementerQuantiteItem(itemVendu, quantite);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
verifierFortune(cout) {
|
|
||||||
return this.getFortune() >= cout;
|
|
||||||
}
|
|
||||||
|
|
||||||
verifierQuantite(item, quantiteDemande) {
|
|
||||||
const disponible = item?.getQuantite();
|
|
||||||
return disponible == undefined || disponible >= quantiteDemande;
|
|
||||||
}
|
|
||||||
|
|
||||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
|
||||||
if (achat.choix.consommer && vente.item.type == 'nourritureboisson' && createdItemId != undefined) {
|
|
||||||
achat.choix.doses = achat.choix.nombreLots;
|
|
||||||
await this.consommerNourritureboisson(createdItemId, achat.choix, vente.actingUserId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
|
|
||||||
if (item.isService()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let resteQuantite = (item.system.quantite ?? 1) - quantite;
|
|
||||||
if (resteQuantite <= 0) {
|
|
||||||
if (options.supprimerSiZero) {
|
|
||||||
await this.deleteEmbeddedDocuments("Item", [item.id]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': 0 }]);
|
|
||||||
}
|
|
||||||
if (resteQuantite < 0) {
|
|
||||||
ui.notifications.warn(`La quantité de ${item.name} était insuffisante, l'objet a donc été supprimé`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (resteQuantite > 0) {
|
|
||||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async creerQuantiteItem(item, quantite) {
|
|
||||||
if (this.canReceive(item)) {
|
|
||||||
const isItemEmpilable = "quantite" in item.system;
|
|
||||||
const baseItem = {
|
|
||||||
type: item.type,
|
|
||||||
img: item.img,
|
|
||||||
name: item.name,
|
|
||||||
system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined })
|
|
||||||
};
|
|
||||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
|
||||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
|
||||||
return items.length > 0 ? items[0].id : undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
computeMalusSurEncombrement() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEncombrementMax() {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async computeEncTotal() {
|
|
||||||
if (!this.pack) {
|
|
||||||
this.encTotal = this.items.map(it => it.getEncTotal()).reduce(Misc.sum(), 0);
|
|
||||||
return this.encTotal;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
async createItem(type, name = undefined) {
|
|
||||||
if (!name) {
|
|
||||||
name = 'Nouveau ' + Misc.typeName('Item', type);
|
|
||||||
}
|
|
||||||
await this.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
canReceive(item) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async processDropItem(params) {
|
|
||||||
const targetActorId = this.id;
|
|
||||||
const sourceActorId = params.sourceActorId;
|
|
||||||
const itemId = params.itemId;
|
|
||||||
const destId = params.destId;
|
|
||||||
const srcId = params.srcId;
|
|
||||||
if (sourceActorId && sourceActorId != targetActorId) {
|
|
||||||
console.log("Moving objects", sourceActorId, targetActorId, itemId);
|
|
||||||
this.moveItemsBetweenActors(itemId, sourceActorId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let result = true;
|
|
||||||
const item = this.getItem(itemId);
|
|
||||||
if (item?.isInventaire('all') && sourceActorId == targetActorId) {
|
|
||||||
// rangement
|
|
||||||
if (srcId != destId && itemId != destId) { // déplacement de l'objet
|
|
||||||
const src = this.getItem(srcId);
|
|
||||||
const dest = this.getItem(destId);
|
|
||||||
const cible = this.getContenantOrParent(dest);
|
|
||||||
const [empilable, message] = item.isInventaireEmpilable(dest);
|
|
||||||
if (empilable) {
|
|
||||||
await dest.empiler(item)
|
|
||||||
result = false;
|
|
||||||
}
|
|
||||||
// changer de conteneur
|
|
||||||
else if (!cible || this.conteneurPeutContenir(cible, item)) {
|
|
||||||
await this.enleverDeConteneur(item, src, params.onEnleverConteneur);
|
|
||||||
await this.ajouterDansConteneur(item, cible, params.onAjouterDansConteneur);
|
|
||||||
if (message && !dest.isConteneur()) {
|
|
||||||
ui.notifications.info(cible
|
|
||||||
? `${message}<br>${item.name} a été déplacé dans: ${cible.name}`
|
|
||||||
: `${message}<br>${item.name} a été sorti du conteneur`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.computeEncTotal();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
getContenantOrParent(dest) {
|
|
||||||
if (!dest || dest.isConteneur()) {
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
return this.getContenant(dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
getContenant(item) {
|
|
||||||
return this.itemTypes['conteneur'].find(it => it.system.contenu.includes(item.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
conteneurPeutContenir(dest, item) {
|
|
||||||
if (!dest) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!dest.isConteneur()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const destData = dest
|
|
||||||
if (this._isConteneurContenu(item, dest)) {
|
|
||||||
ui.notifications.warn(`Impossible de déplacer un conteneur parent (${item.name}) dans un de ses contenus ${destData.name} !`);
|
|
||||||
return false; // Loop detected !
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculer le total actuel des contenus
|
|
||||||
let encContenu = this.getRecursiveEnc(dest) - Number(destData.system.encombrement);
|
|
||||||
let newEnc = this.getRecursiveEnc(item); // Calculer le total actuel du nouvel objet
|
|
||||||
|
|
||||||
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
|
|
||||||
if (Number(destData.system.capacite) < encContenu + newEnc) {
|
|
||||||
ui.notifications.warn(
|
|
||||||
`Le conteneur ${dest.name} a une capacité de ${destData.system.capacite}, et contient déjà ${encContenu}.
|
|
||||||
Impossible d'y ranger: ${item.name} d'encombrement ${newEnc}!`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
_isConteneurContenu(item, conteneur) {
|
|
||||||
if (item?.isConteneur()) { // Si c'est un conteneur, il faut vérifier qu'on ne le déplace pas vers un sous-conteneur lui appartenant
|
|
||||||
for (let id of item.system.contenu) {
|
|
||||||
let subObjet = this.getItem(id);
|
|
||||||
if (subObjet?.id == conteneur.id) {
|
|
||||||
return true; // Loop detected !
|
|
||||||
}
|
|
||||||
if (subObjet?.isConteneur()) {
|
|
||||||
return this._isConteneurContenu(subObjet, conteneur);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
getRecursiveEnc(objet) {
|
|
||||||
if (!objet) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
const tplData = objet.system;
|
|
||||||
if (objet.type != 'conteneur') {
|
|
||||||
return Number(tplData.encombrement) * Number(tplData.quantite);
|
|
||||||
}
|
|
||||||
const encContenus = tplData.contenu.map(idContenu => this.getRecursiveEnc(this.getItem(idContenu)));
|
|
||||||
return encContenus.reduce(Misc.sum(), 0)
|
|
||||||
+ Number(tplData.encombrement) /* TODO? Number(tplData.quantite) -- on pourrait avoir plusieurs conteneurs...*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** Ajoute un item dans un conteneur, sur la base
|
|
||||||
* de leurs ID */
|
|
||||||
async ajouterDansConteneur(item, conteneur, onAjouterDansConteneur) {
|
|
||||||
if (!conteneur) {
|
|
||||||
// TODO: afficher
|
|
||||||
item.estContenu = false;
|
|
||||||
}
|
|
||||||
else if (conteneur.isConteneur()) {
|
|
||||||
item.estContenu = true;
|
|
||||||
await this.updateEmbeddedDocuments('Item', [{
|
|
||||||
_id: conteneur.id,
|
|
||||||
'system.contenu': [...conteneur.system.contenu, item.id]
|
|
||||||
}]);
|
|
||||||
onAjouterDansConteneur(item.id, conteneur.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** Fonction de remise à plat de l'équipement (ie vide les champs 'contenu') */
|
|
||||||
async nettoyerConteneurs() {
|
|
||||||
RdDConfirm.confirmer({
|
|
||||||
settingConfirmer: "confirmation-vider",
|
|
||||||
content: `<p>Etes vous certain de vouloir vider tous les conteneurs ?</p>`,
|
|
||||||
title: 'Vider les conteneurs',
|
|
||||||
buttonLabel: 'Vider',
|
|
||||||
onAction: async () => {
|
|
||||||
const corrections = [];
|
|
||||||
for (let item of this.items) {
|
|
||||||
if (item.estContenu) {
|
|
||||||
item.estContenu = undefined;
|
|
||||||
}
|
|
||||||
if (item.type == 'conteneur' && item.system.contenu.length > 0) {
|
|
||||||
corrections.push({ _id: item.id, 'system.contenu': [] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (corrections.length > 0) {
|
|
||||||
await this.updateEmbeddedDocuments('Item', corrections);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
buildSubConteneurObjetList(conteneurId, deleteList) {
|
|
||||||
let conteneur = this.getItem(conteneurId);
|
|
||||||
if (conteneur?.type == 'conteneur') { // Si c'est un conteneur
|
|
||||||
for (let subId of conteneur.system.contenu) {
|
|
||||||
let subObj = this.getItem(subId);
|
|
||||||
if (subObj) {
|
|
||||||
if (subObj.type == 'conteneur') {
|
|
||||||
this.buildSubConteneurObjetList(subId, deleteList);
|
|
||||||
}
|
|
||||||
deleteList.push({ id: subId, conteneurId: conteneurId });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async deleteAllConteneur(itemId, options) {
|
|
||||||
let list = [];
|
|
||||||
list.push({ id: itemId, conteneurId: undefined }); // Init list
|
|
||||||
this.buildSubConteneurObjetList(itemId, list);
|
|
||||||
await this.deleteEmbeddedDocuments('Item', list.map(it => it.id), options);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** Supprime un item d'un conteneur, sur la base
|
|
||||||
* de leurs ID */
|
|
||||||
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
|
|
||||||
if (conteneur?.isConteneur()) {
|
|
||||||
item.estContenu = false;
|
|
||||||
await this.updateEmbeddedDocuments('Item', [{
|
|
||||||
_id: conteneur.id,
|
|
||||||
'system.contenu': conteneur.system.contenu.filter(id => id != item.id)
|
|
||||||
}]);
|
|
||||||
onEnleverDeConteneur();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async moveItemsBetweenActors(itemId, sourceActorId) {
|
|
||||||
let itemsList = []
|
|
||||||
let sourceActor = game.actors.get(sourceActorId);
|
|
||||||
itemsList.push({ id: itemId, conteneurId: undefined }); // Init list
|
|
||||||
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
|
|
||||||
|
|
||||||
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
|
|
||||||
.map(it => duplicate(it))
|
|
||||||
.map(it => { it.system.contenu = []; return it; });
|
|
||||||
let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate);
|
|
||||||
|
|
||||||
let itemMap = this._buildMapOldNewId(itemsList, newItems);
|
|
||||||
|
|
||||||
for (let item of itemsList) { // Second boucle pour traiter la remise en conteneurs
|
|
||||||
// gestion conteneur/contenu
|
|
||||||
if (item.conteneurId) { // l'Objet était dans un conteneur
|
|
||||||
let newConteneurId = itemMap[item.conteneurId]; // Get conteneur
|
|
||||||
let newConteneur = this.getItem(newConteneurId);
|
|
||||||
|
|
||||||
let newItemId = itemMap[item.id]; // Get newItem
|
|
||||||
|
|
||||||
console.log('New conteneur filling!', newConteneur, newItemId, item);
|
|
||||||
let contenu = duplicate(newConteneur.system.contenu);
|
|
||||||
contenu.push(newItemId);
|
|
||||||
await this.updateEmbeddedDocuments('Item', [{ _id: newConteneurId, 'system.contenu': contenu }]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let item of itemsList) {
|
|
||||||
await sourceActor.deleteEmbeddedDocuments('Item', [item.id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_buildMapOldNewId(itemsList, newItems) {
|
|
||||||
let itemMap = {};
|
|
||||||
for (let i = 0; i < itemsList.length; i++) {
|
|
||||||
itemMap[itemsList[i].id] = newItems[i].id; // Pour garder le lien ancien / nouveau
|
|
||||||
}
|
|
||||||
return itemMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async postActorToChat(modeOverride) {
|
|
||||||
let chatData = {
|
|
||||||
doctype: 'Actor',
|
|
||||||
id: this.id,
|
|
||||||
type: this.type,
|
|
||||||
img: this.img,
|
|
||||||
pack: this.pack,
|
|
||||||
name: this.name,
|
|
||||||
system: { description: this.system.description }
|
|
||||||
}
|
|
||||||
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-actor.html', chatData)
|
|
||||||
.then(html => ChatMessage.create(RdDUtility.chatDataSetup(html, modeOverride)));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,95 +0,0 @@
|
|||||||
import { DialogItemAchat } from "../dialog-item-achat.js";
|
|
||||||
import { RdDItem } from "../item.js";
|
|
||||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
|
||||||
import { RdDUtility } from "../rdd-utility.js";
|
|
||||||
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
|
|
||||||
import { RdDCommerce } from "./commerce.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend the basic ActorSheet with some very simple modifications
|
|
||||||
* @extends {ActorSheet}
|
|
||||||
*/
|
|
||||||
export class RdDCommerceSheet extends RdDBaseActorSheet {
|
|
||||||
|
|
||||||
/** @override */
|
|
||||||
static get defaultOptions() {
|
|
||||||
return mergeObject(super.defaultOptions, {
|
|
||||||
classes: ["rdd", "sheet", "actor"],
|
|
||||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
|
|
||||||
width: 600,
|
|
||||||
height: 720,
|
|
||||||
tabs: [],
|
|
||||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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-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()));
|
|
||||||
await this.getItem(event)?.update({ "system.quantite": newQuantite });
|
|
||||||
})
|
|
||||||
this.html.find('input.item-cout').change(async event => {
|
|
||||||
const newCout = Math.max(0, Number(this.html.find(event.currentTarget).val()));
|
|
||||||
await this.getItem(event)?.update({ "system.cout": newCout });
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getTypesInventaire() {
|
|
||||||
return RdDItem.getItemTypesInventaire('all');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async vente(item) {
|
|
||||||
const acheteur = RdDUtility.getSelectedActor();
|
|
||||||
if (!acheteur) {
|
|
||||||
ui.notifications.warn(`Pas d'acheteur sélectionné`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const disponible = this.actor.getQuantiteDisponible(item)
|
|
||||||
if (disponible == 0) {
|
|
||||||
ui.notifications.warn(`${this.name} n'a plus de ${item.name} en vente`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await DialogItemAchat.onAcheter({
|
|
||||||
item,
|
|
||||||
vendeur: this.actor,
|
|
||||||
acheteur,
|
|
||||||
quantiteIllimite: disponible == undefined,
|
|
||||||
nbLots: disponible ?? 1,
|
|
||||||
tailleLot: 1,
|
|
||||||
prixLot: item.calculerPrixCommercant()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,53 +0,0 @@
|
|||||||
import { Misc } from "../misc.js";
|
|
||||||
import { RdDBaseActor } from "./base-actor.js";
|
|
||||||
|
|
||||||
export class RdDCommerce extends RdDBaseActor {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/services/commerce.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareData() {
|
|
||||||
super.prepareData();
|
|
||||||
}
|
|
||||||
prepareDerivedData() {
|
|
||||||
super.prepareDerivedData();
|
|
||||||
}
|
|
||||||
|
|
||||||
canReceive(item) {
|
|
||||||
if (item.isInventaire('all')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.canReceive(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
getQuantiteDisponible(item) {
|
|
||||||
return (this.system.illimite || item?.isService()) ? undefined : item.getQuantite();
|
|
||||||
}
|
|
||||||
|
|
||||||
verifierFortune(cout) {
|
|
||||||
return this.system.illimite || super.verifierFortune(cout);
|
|
||||||
}
|
|
||||||
async depenserSols(cout) {
|
|
||||||
if (this.system.illimite) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
await super.depenserSols(cout)
|
|
||||||
}
|
|
||||||
|
|
||||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
|
||||||
// ne pas consommer pour un commerce
|
|
||||||
}
|
|
||||||
|
|
||||||
async decrementerQuantiteItem(item, quantite) {
|
|
||||||
if (this.system.illimite) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await super.decrementerQuantiteItem(item, quantite, { supprimerSiZero: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
calculerPrix(item) {
|
|
||||||
const pourcentage = this.system.pourcentage ?? 100;
|
|
||||||
return Misc.keepDecimals(Math.ceil(item.system.cout * pourcentage) / 100, 2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import { Misc } from "./misc.js";
|
import { Misc } from "./misc.js";
|
||||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||||
|
|
||||||
|
export const MESSAGE_DATA = 'message-data';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class providing helper methods to get the list of users, and
|
* Class providing helper methods to get the list of users, and
|
||||||
@ -18,50 +19,61 @@ export class ChatUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static notifyUser(userId, level = 'info', message) {
|
static notifyUser(userId, level = 'info', message) {
|
||||||
const socketData = {
|
const data = {
|
||||||
userId: userId, level: level, message: message
|
userId: userId, level: level, message: message
|
||||||
};
|
};
|
||||||
if (game.user.id == userId) {
|
if (game.user.id == userId) {
|
||||||
ChatUtility.onNotifyUser(socketData);
|
ChatUtility.onNotifyUser(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||||
msg: "msg_user_ui_notifications", data: socketData
|
msg: "msg_user_ui_notifications", data: data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static onNotifyUser(socketData) {
|
static onNotifyUser(data) {
|
||||||
if (game.user.id == socketData.userId) {
|
if (game.user.id == data.userId) {
|
||||||
switch (socketData.level) {
|
switch (data.level) {
|
||||||
case 'warn': ui.notifications.warn(socketData.message); break;
|
case 'warn': ui.notifications.warn(data.message); break;
|
||||||
case 'error': ui.notifications.error(socketData.message); break;
|
case 'error': ui.notifications.error(data.message); break;
|
||||||
default: ui.notifications.info(socketData.message); break;
|
default: ui.notifications.info(data.message); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static onRemoveMessages(socketData) {
|
static onRemoveMessages(data) {
|
||||||
if (Misc.isUniqueConnectedGM()) {
|
if (Misc.isUniqueConnectedGM()) {
|
||||||
if (socketData.part) {
|
if (data.part) {
|
||||||
const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
|
const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
|
||||||
toDelete.forEach(it => it.delete());
|
toDelete.forEach(it => it.delete());
|
||||||
}
|
}
|
||||||
if (socketData.messageId) {
|
if (data.messageId) {
|
||||||
game.messages.get(socketData.messageId)?.delete();
|
game.messages.get(data.messageId)?.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static onRemoveMessages(data) {
|
||||||
|
if (Misc.isUniqueConnectedGM()) {
|
||||||
|
if (data.part) {
|
||||||
|
const toDelete = game.messages.filter(it => it.content.includes(data.part));
|
||||||
|
toDelete.forEach(it => it.delete());
|
||||||
|
}
|
||||||
|
if (data.messageId) {
|
||||||
|
game.messages.get(data.messageId)?.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
static removeMessages(socketData) {
|
static removeMessages(data) {
|
||||||
if (Misc.isUniqueConnectedGM()) {
|
if (Misc.isUniqueConnectedGM()) {
|
||||||
ChatUtility.onRemoveMessages(socketData);
|
ChatUtility.onRemoveMessages(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: socketData });
|
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_delete_chat_message", data: data });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,7 +90,11 @@ export class ChatUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async createChatWithRollMode(name, chatOptions) {
|
static async createChatWithRollMode(name, chatOptions) {
|
||||||
let rollMode = game.settings.get("core", "rollMode")
|
return await ChatUtility.createChatMessage(name, game.settings.get("core", "rollMode"), chatOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static async createChatMessage(name, rollMode, chatOptions) {
|
||||||
switch (rollMode) {
|
switch (rollMode) {
|
||||||
case "blindroll": // GM only
|
case "blindroll": // GM only
|
||||||
if (!game.user.isGM) {
|
if (!game.user.isGM) {
|
||||||
@ -125,7 +141,7 @@ export class ChatUtility {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getUsers(filter) {
|
static getUsers(filter) {
|
||||||
return game.users.filter(filter).map(user => user.id);
|
return Misc.getUsers().filter(filter).map(user => user.data._id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -138,17 +154,17 @@ export class ChatUtility {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static handleGMChatMessage(socketData) {
|
static handleGMChatMessage(data) {
|
||||||
console.log("blindMessageToGM", socketData);
|
console.log("blindMessageToGM", data);
|
||||||
if (game.user.isGM) { // message privé pour GM only
|
if (game.user.isGM) { // message privé pour GM only
|
||||||
socketData.user = game.user.id;
|
data.user = game.user.id;
|
||||||
ChatMessage.create(socketData);
|
ChatMessage.create(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async setMessageData(chatMessage, key, flag) {
|
static async setMessageData(chatMessage, key, data) {
|
||||||
if (flag) {
|
if (data) {
|
||||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag));
|
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
|
export const SYSTEM_RDD = 'foundryvtt-reve-de-dragon';
|
||||||
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
|
export const SYSTEM_SOCKET_ID = 'system.foundryvtt-reve-de-dragon';
|
||||||
export const LOG_HEAD = 'RdD | ';
|
|
||||||
|
|
||||||
export const HIDE_DICE = 'hide';
|
export const HIDE_DICE = 'hide';
|
||||||
export const SHOW_DICE = 'show';
|
export const SHOW_DICE = 'show';
|
||||||
|
@ -1,143 +0,0 @@
|
|||||||
import { SYSTEM_RDD } from "./constants.js";
|
|
||||||
import { Grammar } from "./grammar.js";
|
|
||||||
import { HtmlUtility } from "./html-utility.js";
|
|
||||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
|
||||||
|
|
||||||
|
|
||||||
const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
|
|
||||||
|
|
||||||
export class DialogChronologie extends Dialog {
|
|
||||||
|
|
||||||
static init() {
|
|
||||||
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
|
|
||||||
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
|
|
||||||
scope: "client",
|
|
||||||
config: false,
|
|
||||||
default: "",
|
|
||||||
type: String
|
|
||||||
});
|
|
||||||
}
|
|
||||||
static async create() {
|
|
||||||
const dialogData = {
|
|
||||||
auteur: game.user.name,
|
|
||||||
isGM: game.user.isGM,
|
|
||||||
information: "",
|
|
||||||
journalId: game.settings.get(SYSTEM_RDD, LATEST_USED_JOURNAL_ID),
|
|
||||||
journaux: game.journal.filter(it => it.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)),
|
|
||||||
timestamp: game.system.rdd.calendrier.timestamp,
|
|
||||||
dateReel: game.system.rdd.calendrier.dateReel()
|
|
||||||
};
|
|
||||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-chronologie.html", dialogData);
|
|
||||||
const dialog = new DialogChronologie(html, dialogData);
|
|
||||||
dialog.render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(html, dialogData) {
|
|
||||||
const options = {
|
|
||||||
classes: ["DialogChronologie"],
|
|
||||||
width: 500,
|
|
||||||
height: 'fit-content',
|
|
||||||
'z-index': 99999
|
|
||||||
};
|
|
||||||
const timeData = dialogData.timestamp.toCalendrier()
|
|
||||||
const conf = {
|
|
||||||
title: `Chronologie - ${timeData.jourDuMois} ${timeData.mois.label} - Heure ${timeData.heure.label}`,
|
|
||||||
content: html,
|
|
||||||
buttons: {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
super(conf, options);
|
|
||||||
this.dialogData = dialogData;
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
if (journalEntry?.canUserModify(game.user)) {
|
|
||||||
const journalParameters = this.extractJournalParameters();
|
|
||||||
|
|
||||||
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() {
|
|
||||||
await this.html.find("form.rdddialogchrono :input").change();
|
|
||||||
}
|
|
||||||
|
|
||||||
findJournal() {
|
|
||||||
const journalId = this.html.find("form.rdddialogchrono :input[name='journalId']").val();
|
|
||||||
const journalEntry = game.journal.get(journalId);
|
|
||||||
return { journalId, journalEntry };
|
|
||||||
}
|
|
||||||
|
|
||||||
async prepareChronologieEntry(journalParameters) {
|
|
||||||
return await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chronologie-entry.html", journalParameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
extractJournalParameters() {
|
|
||||||
return {
|
|
||||||
auteur: this.html.find("form.rdddialogchrono :input[name='auteur']").val(),
|
|
||||||
information: this.html.find("form.rdddialogchrono :input[name='information']").val(),
|
|
||||||
dateRdD: {
|
|
||||||
jour: this.html.find("form.rdddialogchrono :input[name='chronologie.jourDuMois']").val(),
|
|
||||||
mois: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.mois']").val()),
|
|
||||||
annee: this.html.find("form.rdddialogchrono :input[name='chronologie.annee']").val(),
|
|
||||||
heure: RdDTimestamp.definition(this.html.find("form.rdddialogchrono :input[name='chronologie.heure']").val()),
|
|
||||||
minute: this.html.find("form.rdddialogchrono :input[name='chronologie.minute']").val(),
|
|
||||||
},
|
|
||||||
dateReel: this.html.find("form.rdddialogchrono :input[name='dateReel']").val()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addContentToJournal(journalEntry, section, content) {
|
|
||||||
let page = journalEntry.pages.find(p => p.type == 'text' && Grammar.equalsInsensitive(p.name, section));
|
|
||||||
if (page) {
|
|
||||||
page.update({ 'text.content': page.text.content + '\n' + content });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
journalEntry.createEmbeddedDocuments('JournalEntryPage', [this.newPageChronologie(section, content)]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newPageChronologie(section, content) {
|
|
||||||
return new JournalEntryPage({
|
|
||||||
name: section,
|
|
||||||
type: 'text',
|
|
||||||
title: { show: true, level: 1 },
|
|
||||||
text: { content: content, format: 1 }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
storeLatestUsedJournalEntry(journalId) {
|
|
||||||
game.settings.set(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, journalId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,6 +1,7 @@
|
|||||||
import { ChatUtility } from "./chat-utility.js";
|
import { ChatUtility } from "./chat-utility.js";
|
||||||
import { HtmlUtility } from "./html-utility.js";
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
|
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
import { TMRUtility } from "./tmr-utility.js";
|
import { TMRUtility } from "./tmr-utility.js";
|
||||||
|
|
||||||
export class DialogCreateSigneDraconique extends Dialog {
|
export class DialogCreateSigneDraconique extends Dialog {
|
||||||
@ -9,13 +10,12 @@ export class DialogCreateSigneDraconique extends Dialog {
|
|||||||
const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
||||||
let dialogData = {
|
let dialogData = {
|
||||||
signe: signe,
|
signe: signe,
|
||||||
tmrs: TMRUtility.buildSelectionTypesTMR(signe.system.typesTMR),
|
tmrs: TMRUtility.listSelectedTMR(signe.data.typesTMR ?? []),
|
||||||
actors: game.actors.filter(actor => actor.isPersonnage() && actor.isHautRevant())
|
actors: game.actors.filter(actor => actor.isHautRevant()).map(actor => {
|
||||||
.map(actor => ({
|
let actorData = duplicate(actor);
|
||||||
id: actor.id,
|
actorData.selected = actor.hasPlayerOwner;
|
||||||
name: actor.name,
|
return actorData;
|
||||||
selected: true
|
})
|
||||||
}))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
|
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
|
||||||
@ -23,11 +23,12 @@ export class DialogCreateSigneDraconique extends Dialog {
|
|||||||
.render(true);
|
.render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(dialogData, html) {
|
constructor(dialogData, html, callback) {
|
||||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
|
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||||
let conf = {
|
let conf = {
|
||||||
title: "Créer un signe",
|
title: "Créer un signe",
|
||||||
content: html,
|
content: html,
|
||||||
|
default: "Ajouter aux haut-rêvants",
|
||||||
buttons: {
|
buttons: {
|
||||||
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
|
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
|
||||||
}
|
}
|
||||||
@ -37,12 +38,11 @@ export class DialogCreateSigneDraconique extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _onCreerSigneActeurs() {
|
async _onCreerSigneActeurs() {
|
||||||
await this.html.find("[name='signe.system.ephemere']").change();
|
await $("[name='signe.data.ephemere']").change();
|
||||||
await this.html.find(".signe-xp-sort").change();
|
await $(".signe-xp-sort").change();
|
||||||
this.validerSigne();
|
this.validerSigne();
|
||||||
this.dialogData.actors.filter(it => it.selected)
|
this.dialogData.actors.filter(it => it.selected).map(it => game.actors.get(it._id))
|
||||||
.map(it => game.actors.get(it.id))
|
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
|
||||||
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async _createSigneForActor(actor, signe) {
|
async _createSigneForActor(actor, signe) {
|
||||||
@ -57,72 +57,62 @@ export class DialogCreateSigneDraconique extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validerSigne() {
|
validerSigne() {
|
||||||
this.dialogData.signe.name = this.html.find("[name='signe.name']").val();
|
this.dialogData.signe.name = $("[name='signe.name']").val();
|
||||||
this.dialogData.signe.system.valeur.norm = this.html.find("[name='signe.system.valeur.norm']").val();
|
this.dialogData.signe.data.valeur.norm = $("[name='signe.data.valeur.norm']").val();
|
||||||
this.dialogData.signe.system.valeur.sign = this.html.find("[name='signe.system.valeur.sign']").val();
|
this.dialogData.signe.data.valeur.sign = $("[name='signe.data.valeur.sign']").val();
|
||||||
this.dialogData.signe.system.valeur.part = this.html.find("[name='signe.system.valeur.part']").val();
|
this.dialogData.signe.data.valeur.part = $("[name='signe.data.valeur.part']").val();
|
||||||
this.dialogData.signe.system.difficulte = this.html.find("[name='signe.system.difficulte']").val();
|
this.dialogData.signe.data.difficulte = $("[name='signe.data.difficulte']").val();
|
||||||
this.dialogData.signe.system.ephemere = this.html.find("[name='signe.system.ephemere']").prop("checked");
|
this.dialogData.signe.data.ephemere = $("[name='signe.data.ephemere']").prop("checked");
|
||||||
this.dialogData.signe.system.duree = this.html.find("[name='signe.system.duree']").val();
|
this.dialogData.signe.data.duree = $("[name='signe.data.duree']").val();
|
||||||
this.dialogData.signe.system.typesTMR = TMRUtility.buildListTypesTMRSelection(this.dialogData.tmrs);
|
this.dialogData.signe.data.typesTMR = $(".select-tmr").val();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
this.html = html;
|
this.setEphemere(this.dialogData.signe.data.ephemere);
|
||||||
this.setEphemere(this.dialogData.signe.system.ephemere);
|
|
||||||
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
||||||
html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
|
html.find("[name='signe.data.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
|
||||||
|
html.find(".select-actor").change((event) => this.onSelectActor(event));
|
||||||
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
|
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
|
||||||
html.find("input.select-actor").change((event) => this.onSelectActor(event));
|
|
||||||
html.find("input.select-tmr").change((event) => this.onSelectTmr(event));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async setSigneAleatoire() {
|
async setSigneAleatoire() {
|
||||||
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
|
||||||
|
|
||||||
this.html.find("[name='signe.name']").val(newSigne.name);
|
$("[name='signe.name']").val(newSigne.name);
|
||||||
this.html.find("[name='signe.system.valeur.norm']").val(newSigne.system.valeur.norm);
|
$("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
|
||||||
this.html.find("[name='signe.system.valeur.sign']").val(newSigne.system.valeur.sign);
|
$("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
|
||||||
this.html.find("[name='signe.system.valeur.part']").val(newSigne.system.valeur.part);
|
$("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
|
||||||
this.html.find("[name='signe.system.difficulte']").val(newSigne.system.difficulte);
|
$("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
|
||||||
this.html.find("[name='signe.system.duree']").val(newSigne.system.duree);
|
$("[name='signe.data.duree']").val(newSigne.data.duree);
|
||||||
this.html.find("[name='signe.system.ephemere']").prop("checked", newSigne.system.ephemere);
|
$("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
|
||||||
this.dialogData.tmrs = TMRUtility.buildSelectionTypesTMR(newSigne.system.typesTMR);
|
$(".select-tmr").val(newSigne.data.typesTMR);
|
||||||
this.dialogData.tmrs.forEach(t => {
|
this.setEphemere(newSigne.data.ephemere);
|
||||||
this.html.find(`[data-tmr-name='${t.name}']`).prop( "checked", t.selected);
|
|
||||||
})
|
|
||||||
this.setEphemere(newSigne.system.ephemere);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async setEphemere(ephemere) {
|
async setEphemere(ephemere) {
|
||||||
this.dialogData.signe.system.ephemere = ephemere;
|
this.dialogData.signe.data.ephemere = ephemere;
|
||||||
HtmlUtility.showControlWhen(this.html.find(".signe-system-duree"), ephemere);
|
HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSelectActor(event) {
|
async onSelectActor(event) {
|
||||||
const actorId = this.html.find(event.currentTarget)?.data("actor-id");
|
event.preventDefault();
|
||||||
const actor = this.dialogData.actors.find(it => it.id == actorId);
|
const options = event.currentTarget.options;
|
||||||
if (actor) {
|
for (var i = 0; i < options.length; i++) { // looping over the options
|
||||||
actor.selected = event.currentTarget.checked;
|
const actorId = options[i].attributes["data-actor-id"].value;
|
||||||
}
|
const actor = this.dialogData.actors.find(it => it._id == actorId);
|
||||||
|
if (actor) {
|
||||||
|
actor.selected = options[i].selected;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onSelectTmr(event) {
|
|
||||||
const tmrName = this.html.find(event.currentTarget)?.data("tmr-name");
|
|
||||||
const onTmr = this.tmrs.find(it => it.name == tmrName);
|
|
||||||
if (onTmr){
|
|
||||||
onTmr.selected = event.currentTarget.checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
onValeurXpSort(event) {
|
onValeurXpSort(event) {
|
||||||
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
|
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
|
||||||
const xp = Number(event.currentTarget.value);
|
const xp = Number(event.currentTarget.value);
|
||||||
const oldValeur = this.dialogData.signe.system.valeur;
|
const oldValeur = this.dialogData.signe.data.valeur;
|
||||||
this.dialogData.signe.system.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -5,42 +5,37 @@ import { RdDUtility } from "./rdd-utility.js";
|
|||||||
export class DialogFabriquerPotion extends Dialog {
|
export class DialogFabriquerPotion extends Dialog {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static async create(actor, item, onActionItem) {
|
static async create(actor, item, dialogConfig) {
|
||||||
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!`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let potionData = DialogFabriquerPotion.prepareData(actor, item);
|
let potionData = DialogFabriquerPotion.prepareData(actor, item);
|
||||||
|
|
||||||
const html = await renderTemplate( 'systems/foundryvtt-reve-de-dragon/templates/dialog-fabriquer-potion-base.html', potionData);
|
let conf = {
|
||||||
|
title: `Fabriquer une potion de ${potionData.data.categorie}`,
|
||||||
|
content: await renderTemplate(dialogConfig.html, potionData),
|
||||||
|
default: potionData.buttonName,
|
||||||
|
};
|
||||||
|
|
||||||
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
|
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
|
||||||
new DialogFabriquerPotion(actor, potionData, onActionItem, html, options).render(true);
|
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
|
||||||
|
|
||||||
|
const dialog = new DialogFabriquerPotion(actor, potionData, conf, options);
|
||||||
|
dialog.render(true);
|
||||||
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static prepareData(actor, item) {
|
static prepareData(actor, item) {
|
||||||
let potionData = duplicate(item)
|
let potionData = duplicate(item)
|
||||||
potionData.nbBrinsSelect = RdDUtility.buildListOptions(
|
potionData.nbBrinsSelect = RdDUtility.buildListOptions(1, potionData.data.quantite);
|
||||||
DialogFabriquerPotion.nombreBrinsMinimum(item),
|
potionData.nbBrins = Math.min(potionData.data.quantite, DialogFabriquerPotion.getNombreBrinOptimal(potionData));
|
||||||
DialogFabriquerPotion.nombreBrinsOptimal(item));
|
|
||||||
potionData.nbBrins = Math.min(potionData.system.quantite, DialogFabriquerPotion.nombreBrinsOptimal(potionData));
|
|
||||||
potionData.herbebonus = item.system.niveau;
|
|
||||||
potionData.buttonName = "Fabriquer";
|
potionData.buttonName = "Fabriquer";
|
||||||
return potionData;
|
return potionData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
constructor(actor, potionData, onActionItem, html, options) {
|
constructor(actor, potionData, conf, options) {
|
||||||
const conf = {
|
conf.buttons = {
|
||||||
title: `Fabriquer une potion de ${potionData.system.categorie}`,
|
[potionData.buttonName]: {
|
||||||
content: html,
|
label: potionData.buttonName, callback: it => this.onFabriquer(it)
|
||||||
default: 'fabriquer',
|
|
||||||
buttons: {
|
|
||||||
'fabriquer': {
|
|
||||||
label: potionData.buttonName, callback: it => this.onFabriquer()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -48,41 +43,29 @@ export class DialogFabriquerPotion extends Dialog {
|
|||||||
|
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
this.potionData = potionData;
|
this.potionData = potionData;
|
||||||
this.onActionItem = onActionItem;
|
}
|
||||||
|
|
||||||
|
static getNombreBrinOptimal(herbeData) {
|
||||||
|
switch (herbeData.data.categorie ?? '') {
|
||||||
|
case "Soin": return 12 - herbeData.data.niveau;
|
||||||
|
case "Repos": return 7 - herbeData.data.niveau;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
this.html = html;
|
|
||||||
this.html.find("[name='nbBrins']").change(event => {
|
html.find("#nbBrins").change(event => {
|
||||||
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
|
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
|
||||||
const brinsManquants = Math.max(0, DialogFabriquerPotion.nombreBrinsOptimal(this.potionData) - this.potionData.nbBrins);
|
|
||||||
this.potionData.herbebonus = Math.max(0, this.potionData.system.niveau - brinsManquants)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async onFabriquer() {
|
async onFabriquer(it) {
|
||||||
await this.html.find("[name='nbBrins']").change();
|
await $("#nbBrins").change();
|
||||||
await this.actor.fabriquerPotion(this.potionData);
|
this.actor.fabriquerPotion(this.potionData);
|
||||||
this.close();
|
this.close();
|
||||||
await this.onActionItem()
|
|
||||||
}
|
|
||||||
|
|
||||||
static nombreBrinsMinimum(herbeData) {
|
|
||||||
switch (herbeData.system.categorie ?? '') {
|
|
||||||
case "Soin": return 1 + Math.max(0, 12 - 2 * herbeData.system.niveau);
|
|
||||||
case "Repos": return 1 + Math.max(0, 7 - 2 * herbeData.system.niveau);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static nombreBrinsOptimal(herbeData) {
|
|
||||||
switch (herbeData.system.categorie ?? '') {
|
|
||||||
case "Soin": return 12 - herbeData.system.niveau;
|
|
||||||
case "Repos": return 7 - herbeData.system.niveau;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,101 +1,90 @@
|
|||||||
|
|
||||||
import { Misc } from "./misc.js";
|
import { Misc } from "./misc.js";
|
||||||
import { RdDUtility } from "./rdd-utility.js";
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
export class DialogItemAchat extends Dialog {
|
export class DialogItemAchat extends Dialog {
|
||||||
|
|
||||||
static preparerAchat(chatButton) {
|
static async onButtonAcheter(event) {
|
||||||
const vendeurId = chatButton.attributes['data-vendeurId']?.value;
|
const buttonAcheter = event.currentTarget;
|
||||||
|
if (!buttonAcheter.attributes['data-jsondata']?.value) {
|
||||||
|
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const chatMessageIdVente = RdDUtility.findChatMessageId(buttonAcheter);
|
||||||
|
|
||||||
|
const vendeurId = buttonAcheter.attributes['data-vendeurId']?.value;
|
||||||
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
|
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
|
||||||
const acheteur = RdDUtility.getSelectedActor();
|
const acheteur = RdDUtility.getSelectedActor();
|
||||||
const json = chatButton.attributes['data-jsondata']?.value;
|
|
||||||
if (!acheteur && !vendeur) {
|
if (!acheteur && !vendeur) {
|
||||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||||
return undefined;
|
return;
|
||||||
}
|
|
||||||
if (!json) {
|
|
||||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
let venteData = DialogItemAchat.prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur);
|
||||||
item: JSON.parse(json),
|
|
||||||
vendeur,
|
|
||||||
acheteur,
|
|
||||||
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
|
|
||||||
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
|
|
||||||
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
|
|
||||||
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
|
|
||||||
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
|
|
||||||
const venteData = {
|
|
||||||
item,
|
|
||||||
actingUserId: game.user.id,
|
|
||||||
vendeur,
|
|
||||||
acheteur,
|
|
||||||
tailleLot,
|
|
||||||
quantiteIllimite,
|
|
||||||
quantiteNbLots: nbLots,
|
|
||||||
choix: { seForcer: false, supprimerSiZero: true },
|
|
||||||
prixLot,
|
|
||||||
isVente: prixLot > 0,
|
|
||||||
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
|
|
||||||
chatMessageIdVente
|
|
||||||
};
|
|
||||||
|
|
||||||
DialogItemAchat.changeNombreLots(venteData, 1);
|
|
||||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
|
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
|
||||||
new DialogItemAchat(html, venteData).render(true);
|
const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
|
||||||
|
dialog.render(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static changeNombreLots(venteData, nombreLots) {
|
constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
|
||||||
venteData.choix.nombreLots = nombreLots;
|
const isConsommable = venteData.item.type == 'nourritureboisson';
|
||||||
venteData.prixTotal = (nombreLots * venteData.prixLot).toFixed(2);
|
let options = { classes: ["dialogachat"], width: 400, height: isConsommable ? 450 : 350, 'z-index': 99999 };
|
||||||
if (venteData.isConsommable) {
|
|
||||||
const doses = nombreLots * venteData.tailleLot;
|
|
||||||
venteData.totalSust = Misc.keepDecimals(doses * (venteData.item.system.sust ?? 0), 2);
|
|
||||||
venteData.totalDesaltere = venteData.item.system.boisson
|
|
||||||
? Misc.keepDecimals(doses * (venteData.item.system.desaltere ?? 0), 2)
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(html, venteData) {
|
|
||||||
let options = { classes: ["dialogachat"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
|
||||||
|
|
||||||
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
|
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
|
||||||
const buttons = {};
|
const buttons = {};
|
||||||
if (venteData.isConsommable) {
|
if (isConsommable) {
|
||||||
buttons["consommer"] = { label: venteData.item.system.boisson ? "Boire" : "Manger", callback: it => this.onAchatConsommer() }
|
buttons["consommer"] = { label: venteData.item.data.boisson ? "Boire" : "Manger", callback: it => { this.onAchatConsommer(); } }
|
||||||
}
|
}
|
||||||
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
|
buttons[actionAchat] = { label: actionAchat, callback: it => { this.onAchat(); } };
|
||||||
buttons["decliner"] = { label: "Décliner", callback: it => { } };
|
buttons["decliner"] = { label: "Décliner", callback: it => { } };
|
||||||
const acheteur = venteData.acheteur?.name ?? 'Un acheteur';
|
|
||||||
const vendeur = venteData.vendeur?.name ?? 'Un vendeur';
|
|
||||||
let conf = {
|
let conf = {
|
||||||
title: `${acheteur} - ${actionAchat} à ${vendeur}`,
|
title: venteData.acheteur? venteData.acheteur.name + " - " + actionAchat : actionAchat,
|
||||||
content: html,
|
content: html,
|
||||||
default: actionAchat,
|
default: actionAchat,
|
||||||
buttons: buttons
|
buttons: buttons
|
||||||
};
|
};
|
||||||
|
|
||||||
super(conf, options);
|
super(conf, options);
|
||||||
|
|
||||||
|
this.vendeur = vendeur;
|
||||||
|
this.acheteur = acheteur;
|
||||||
|
this.chatMessageIdVente = chatMessageIdVente;
|
||||||
this.venteData = venteData;
|
this.venteData = venteData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) {
|
||||||
|
const jsondata = buttonAcheter.attributes['data-jsondata']?.value;
|
||||||
|
const prixLot = parseInt(buttonAcheter.attributes['data-prixLot']?.value ?? 0);
|
||||||
|
let venteData = {
|
||||||
|
item: JSON.parse(jsondata),
|
||||||
|
vendeurId: vendeurId,
|
||||||
|
vendeur: vendeur,
|
||||||
|
acheteur:acheteur,
|
||||||
|
tailleLot: parseInt(buttonAcheter.attributes['data-tailleLot']?.value ?? 1),
|
||||||
|
quantiteIllimite: buttonAcheter.attributes['data-quantiteIllimite']?.value == 'true',
|
||||||
|
quantiteNbLots: parseInt(buttonAcheter.attributes['data-quantiteNbLots']?.value),
|
||||||
|
choix: {
|
||||||
|
nombreLots: 1,
|
||||||
|
seForcer: false,
|
||||||
|
supprimerSiZero: true
|
||||||
|
},
|
||||||
|
prixLot: prixLot,
|
||||||
|
prixTotal: prixLot,
|
||||||
|
isVente: prixLot > 0
|
||||||
|
};
|
||||||
|
return venteData;
|
||||||
|
}
|
||||||
|
|
||||||
async onAchat() {
|
async onAchat() {
|
||||||
await this.html.find(".nombreLots").change();
|
await $(".nombreLots").change();
|
||||||
(this.venteData.vendeur ?? this.venteData.acheteur).achatVente({
|
(this.vendeur ?? this.acheteur).achatVente({
|
||||||
userId: game.user.id,
|
userId: game.user.id,
|
||||||
vendeurId: this.venteData.vendeur?.id,
|
vendeurId: this.vendeur?.id,
|
||||||
acheteurId: this.venteData.acheteur?.id,
|
acheteurId: this.acheteur?.id,
|
||||||
prixTotal: this.venteData.prixTotal,
|
prixTotal: this.venteData.prixTotal,
|
||||||
chatMessageIdVente: this.venteData.chatMessageIdVente,
|
chatMessageIdVente: this.chatMessageIdVente,
|
||||||
choix: this.venteData.choix,
|
choix: this.venteData.choix
|
||||||
vente: this.venteData
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +96,9 @@ export class DialogItemAchat extends Dialog {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
this.html = html;
|
|
||||||
this.html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
|
html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
|
||||||
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
|
html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||||
}
|
}
|
||||||
|
|
||||||
setSeForcer(event) {
|
setSeForcer(event) {
|
||||||
@ -117,21 +106,9 @@ export class DialogItemAchat extends Dialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setNombreLots(nombreLots) {
|
setNombreLots(nombreLots) {
|
||||||
|
this.venteData.choix.nombreLots = nombreLots;
|
||||||
if (!this.venteData.quantiteIllimite) {
|
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
|
||||||
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) {
|
$(".prixTotal").text(this.venteData.prixTotal);
|
||||||
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`)
|
|
||||||
}
|
|
||||||
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogItemAchat.changeNombreLots(this.venteData, nombreLots);
|
|
||||||
|
|
||||||
this.html.find(".nombreLots").val(nombreLots);
|
|
||||||
this.html.find(".prixTotal").text(this.venteData.prixTotal);
|
|
||||||
this.html.find("span.total-sust").text(this.venteData.totalSust);
|
|
||||||
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -2,14 +2,14 @@ import { Misc } from "./misc.js";
|
|||||||
|
|
||||||
export class DialogConsommer extends Dialog {
|
export class DialogConsommer extends Dialog {
|
||||||
|
|
||||||
static async create(actor, item, onActionItem = async () => { }) {
|
static async create(actor, item, onActionItem = async ()=>{}) {
|
||||||
const consommerData = DialogConsommer.prepareData(actor, item);
|
const consommerData = DialogConsommer.prepareData(actor, item);
|
||||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData);
|
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html', consommerData);
|
||||||
return new DialogConsommer(actor, item, consommerData, html, onActionItem)
|
return new DialogConsommer(actor, item, consommerData, html, onActionItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(actor, item, consommerData, html, onActionItem = async () => { }) {
|
constructor(actor, item, consommerData, html, onActionItem = async ()=>{}) {
|
||||||
const options = { classes: ["dialogconsommer"], width: 350, height: 'fit-content', 'z-index': 99999 };
|
const options = { classes: ["dialogconsommer"], width: 350, height: 450, 'z-index': 99999 };
|
||||||
let conf = {
|
let conf = {
|
||||||
title: consommerData.title,
|
title: consommerData.title,
|
||||||
content: html,
|
content: html,
|
||||||
@ -17,9 +17,8 @@ export class DialogConsommer extends Dialog {
|
|||||||
buttons: {
|
buttons: {
|
||||||
[consommerData.buttonName]: {
|
[consommerData.buttonName]: {
|
||||||
label: consommerData.buttonName, callback: async it => {
|
label: consommerData.buttonName, callback: async it => {
|
||||||
await this.onConsommer();
|
await this.onConsommer(it);
|
||||||
await onActionItem();
|
await onActionItem();}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -31,71 +30,51 @@ export class DialogConsommer extends Dialog {
|
|||||||
this.consommerData = consommerData;
|
this.consommerData = consommerData;
|
||||||
}
|
}
|
||||||
|
|
||||||
activateListeners(html) {
|
async onConsommer(event) {
|
||||||
super.activateListeners(html);
|
await $(".se-forcer").change();
|
||||||
this.html = html;
|
await $(".consommer-doses").change();
|
||||||
this.html.find(".se-forcer").change(event => this.setSeForcer(event));
|
|
||||||
this.html.find(".consommer-doses").change(event => this.selectDoses(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
async onConsommer() {
|
|
||||||
await this.html.find(".se-forcer").change();
|
|
||||||
await this.html.find(".consommer-doses").change();
|
|
||||||
await this.actor.consommer(this.item, this.consommerData.choix);
|
await this.actor.consommer(this.item, this.consommerData.choix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static prepareData(actor, item) {
|
static prepareData(actor, item) {
|
||||||
|
const itemData = duplicate(item);
|
||||||
let consommerData = {
|
let consommerData = {
|
||||||
item: duplicate(item),
|
item: itemData,
|
||||||
cuisine: actor.getCompetence('cuisine'),
|
cuisine: actor.getCompetence('cuisine'),
|
||||||
choix: {
|
choix: {
|
||||||
doses: 1,
|
doses: 1,
|
||||||
seForcer: false,
|
seForcer: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (item.type) {
|
switch (itemData.type) {
|
||||||
case 'herbe': case 'faune':
|
|
||||||
consommerData.title = 'Manger une portion crue: ';
|
|
||||||
consommerData.buttonName = "Manger";
|
|
||||||
break;
|
|
||||||
case 'nourritureboisson':
|
case 'nourritureboisson':
|
||||||
consommerData.title = item.system.boisson ? 'Boire une dose: ' : 'Manger une portion: ';
|
consommerData.title = itemData.data.boisson ? `${itemData.name}: boire une dose` : `${itemData.name}: manger une portion`;
|
||||||
consommerData.buttonName = item.system.boisson ? "Boire" : "Manger";
|
consommerData.buttonName = itemData.data.boisson ? "Boire" : "Manger";
|
||||||
break;
|
break;
|
||||||
case 'potion':
|
case 'potion':
|
||||||
consommerData.title = 'Boire la potion: ';
|
consommerData.title = `${itemData.name}: boire la potion`;
|
||||||
consommerData.buttonName = "Boire";
|
consommerData.buttonName = "Boire";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
consommerData.title += item.name;
|
DialogConsommer.calculDoses(consommerData, consommerData.choix.doses)
|
||||||
DialogConsommer.calculDoses(consommerData, item)
|
|
||||||
return consommerData;
|
return consommerData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static calculDoses(consommer, item) {
|
static calculDoses(consommerData) {
|
||||||
const doses = consommer.choix.doses;
|
const doses = consommerData.choix.doses;
|
||||||
switch (item.type) {
|
consommerData.totalSust = Misc.keepDecimals(doses * (consommerData.item.data.sust ?? 0), 2);
|
||||||
case 'herbe': case 'faune':
|
consommerData.totalDesaltere = consommerData.item.data.boisson
|
||||||
consommer.totalSust = doses;
|
? Misc.keepDecimals(doses * (consommerData.item.data.desaltere ?? 0), 2)
|
||||||
consommer.totalDesaltere = 0;
|
: 0;
|
||||||
consommer.choix.sust = 1;
|
}
|
||||||
consommer.choix.quantite = 0;
|
|
||||||
consommer.choix.encombrement = Misc.keepDecimals(consommer.item.system.encombrement / item.system.sust, 2);
|
|
||||||
return;
|
/* -------------------------------------------- */
|
||||||
case 'nourritureboisson':
|
activateListeners(html) {
|
||||||
consommer.choix.sust = consommer.item.system.sust;
|
super.activateListeners(html);
|
||||||
consommer.choix.quantite = doses;
|
html.find(".se-forcer").change(event => this.setSeForcer(event));
|
||||||
consommer.choix.encombrement = 0
|
html.find(".consommer-doses").change(event => this.selectDoses(event));
|
||||||
consommer.totalSust = Misc.keepDecimals(doses * (consommer.item.system.sust ?? 0), 2);
|
|
||||||
consommer.totalDesaltere = consommer.item.system.boisson
|
|
||||||
? Misc.keepDecimals(doses * (consommer.item.system.desaltere ?? 0), 2)
|
|
||||||
: 0;
|
|
||||||
break;
|
|
||||||
case 'potion':
|
|
||||||
consommer.totalSust = 0
|
|
||||||
consommer.totalDesaltere = 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,8 +84,8 @@ export class DialogConsommer extends Dialog {
|
|||||||
|
|
||||||
selectDoses(event) {
|
selectDoses(event) {
|
||||||
this.consommerData.choix.doses = Number(event.currentTarget.value);
|
this.consommerData.choix.doses = Number(event.currentTarget.value);
|
||||||
DialogConsommer.calculDoses(this.consommerData, this.item);
|
DialogConsommer.calculDoses(this.consommerData);
|
||||||
this.html.find(".total-sust").text(this.consommerData.totalSust);
|
$(".total-sust").text(this.consommerData.totalSust);
|
||||||
this.html.find(".total-desaltere").text(this.consommerData.totalDesaltere);
|
$(".total-desaltere").text(this.consommerData.totalDesaltere);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,30 +1,31 @@
|
|||||||
import { HtmlUtility } from "./html-utility.js";
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
|
|
||||||
export class DialogItemVente extends Dialog {
|
export class DialogItemVente extends Dialog {
|
||||||
|
|
||||||
static async display({ item, callback, quantiteMax = undefined }) {
|
static async create(item, callback) {
|
||||||
const quantite = quantiteMax ?? item.getQuantite() ?? 1;
|
const itemData = item
|
||||||
const isOwned = item.parent;
|
const quantite = item.isConteneur() ? 1 : itemData.system.quantite;
|
||||||
const venteData = {
|
const venteData = {
|
||||||
item: item,
|
item: itemData,
|
||||||
alias: item.actor?.name ?? game.user.name,
|
alias: item.actor?.name ?? game.user.name,
|
||||||
vendeurId: item.actor?.id,
|
vendeurId: item.actor?.id,
|
||||||
prixOrigine: item.calculerPrixCommercant(),
|
prixOrigine: itemData.system.cout,
|
||||||
prixUnitaire: item.calculerPrixCommercant(),
|
prixUnitaire: itemData.system.cout,
|
||||||
prixLot: item.calculerPrixCommercant(),
|
prixLot: itemData.system.cout,
|
||||||
tailleLot: 1,
|
tailleLot: 1,
|
||||||
quantiteNbLots: quantite,
|
quantiteNbLots: quantite,
|
||||||
quantiteMaxLots: quantite,
|
quantiteMaxLots: quantite,
|
||||||
quantiteMax: quantite,
|
quantiteMax: quantite ,
|
||||||
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned,
|
quantiteIllimite: !item.isOwned,
|
||||||
isOwned: isOwned,
|
isOwned: item.isOwned,
|
||||||
};
|
};
|
||||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
|
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
|
||||||
return new DialogItemVente(venteData, html, callback).render(true);
|
return new DialogItemVente(venteData, html, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(venteData, html, callback) {
|
constructor(venteData, html, callback) {
|
||||||
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 };
|
||||||
|
|
||||||
let conf = {
|
let conf = {
|
||||||
title: "Proposer",
|
title: "Proposer",
|
||||||
@ -38,65 +39,57 @@ export class DialogItemVente extends Dialog {
|
|||||||
this.venteData = venteData;
|
this.venteData = venteData;
|
||||||
}
|
}
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
this.html = html;
|
|
||||||
this.html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
|
||||||
this.html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
|
||||||
this.html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
|
|
||||||
this.html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
|
|
||||||
|
|
||||||
this.setQuantiteIllimite(this.venteData.quantiteIllimite);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onProposer(it) {
|
async onProposer(it) {
|
||||||
this.updateVente(this.getChoixVente());
|
await $(".tailleLot").change();
|
||||||
|
await $(".quantiteNbLots").change();
|
||||||
|
await $(".quantiteIllimite").change();
|
||||||
|
await $(".prixLot").change();
|
||||||
this.callback(this.venteData);
|
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())
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||||
|
|
||||||
|
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
|
||||||
|
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
|
||||||
|
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
|
||||||
|
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
|
||||||
|
}
|
||||||
|
|
||||||
setPrixLot(prixLot) {
|
setPrixLot(prixLot) {
|
||||||
this.venteData.prixLot = prixLot;
|
this.venteData.prixLot = prixLot;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTailleLot(tailleLot) {
|
setTailleLot(tailleLot) {
|
||||||
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
// recalculer le prix du lot
|
||||||
this.updateVente({
|
if (tailleLot != this.venteData.tailleLot) {
|
||||||
tailleLot,
|
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
|
||||||
quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots),
|
$(".prixLot").val(this.venteData.prixLot);
|
||||||
quantiteMaxLots: maxLots,
|
}
|
||||||
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
|
this.venteData.tailleLot = tailleLot;
|
||||||
});
|
if (this.venteData.isOwned) {
|
||||||
|
// recalculer le nombre de lots max
|
||||||
this.html.find(".prixLot").val(this.venteData.prixLot);
|
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
||||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
|
||||||
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||||
|
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setNbLots(nbLots) {
|
setNbLots(nbLots) {
|
||||||
this.updateVente({
|
if (this.venteData.isOwned) {
|
||||||
quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots
|
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
|
||||||
})
|
}
|
||||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
this.venteData.quantiteNbLots = nbLots;
|
||||||
|
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||||
}
|
}
|
||||||
|
|
||||||
setQuantiteIllimite(checked) {
|
setQuantiteIllimite(checked) {
|
||||||
this.updateVente({ quantiteIllimite: checked })
|
this.venteData.quantiteIllimite = checked;
|
||||||
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
$(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
||||||
HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||||
}
|
}
|
||||||
}
|
}
|
56
module/dialog-repos.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Misc } from "./misc.js";
|
||||||
|
|
||||||
|
export class DialogRepos extends Dialog {
|
||||||
|
|
||||||
|
static async create(actor) {
|
||||||
|
let actorData = actor
|
||||||
|
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-repos.html", actorData);
|
||||||
|
new DialogRepos(html, actor).render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(html, actor) {
|
||||||
|
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 400, '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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async repos() {
|
||||||
|
await $("[name='nb-heures']").change();
|
||||||
|
await $("[name='nb-jours']").change();
|
||||||
|
const selection = await $("[name='repos']:checked").val();
|
||||||
|
const nbHeures = Number.parseInt(await $("[name='nb-heures']").val());
|
||||||
|
const nbJours = Number.parseInt(await $("[name='nb-jours']").val());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
|
|
||||||
export class DialogSelectTarget extends Dialog {
|
|
||||||
constructor(html, onSelectTarget, targets) {
|
|
||||||
const options = {
|
|
||||||
classes: ["rdd-dialog-select-target"],
|
|
||||||
width: 'fit-content',
|
|
||||||
height: 'fit-content',
|
|
||||||
'max-height': 600,
|
|
||||||
'z-index': 99999
|
|
||||||
};
|
|
||||||
const conf = {
|
|
||||||
title: "Choisir une cible",
|
|
||||||
content: html,
|
|
||||||
buttons: {}
|
|
||||||
};
|
|
||||||
super(conf, options);
|
|
||||||
this.onSelectTarget = onSelectTarget;
|
|
||||||
this.targets = targets;
|
|
||||||
}
|
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
this.html = html;
|
|
||||||
this.html.find("li.select-target").click((event) => {
|
|
||||||
this.targetSelected(this.html.find(event.currentTarget)?.data("token-id"));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
targetSelected(tokenId) {
|
|
||||||
const target = this.targets.find(it => it.id == tokenId);
|
|
||||||
this.close();
|
|
||||||
if (target) {
|
|
||||||
this.onSelectTarget(target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -3,24 +3,31 @@ import { Misc } from "./misc.js";
|
|||||||
export class DialogSplitItem extends Dialog {
|
export class DialogSplitItem extends Dialog {
|
||||||
|
|
||||||
static async create(item, callback) {
|
static async create(item, callback) {
|
||||||
|
const itemData = item
|
||||||
const splitData = {
|
const splitData = {
|
||||||
item: item,
|
item: itemData,
|
||||||
choix: { quantite: 1, max: item.system.quantite - 1 }
|
choix: { quantite: 1, max: itemData.data.quantite - 1 }
|
||||||
};
|
};
|
||||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
|
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
|
||||||
return new DialogSplitItem(item, splitData, html, callback)
|
return new DialogSplitItem(item, splitData, html, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(item, splitData, html, callback) {
|
constructor(item, splitData, html, callback) {
|
||||||
let options = { classes: ["dialogsplit"], width: 300, height: 'fit-content', 'z-index': 99999 };
|
let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
|
||||||
|
|
||||||
let conf = {
|
let conf = {
|
||||||
title: "Séparer en deux",
|
title: "Séparer en deux",
|
||||||
content: html,
|
content: html,
|
||||||
default: "separer",
|
default: "separer",
|
||||||
buttons: {
|
buttons: {
|
||||||
"separer": { label: "Séparer", callback: it => this.onSplit() }
|
"separer": {
|
||||||
|
label: "Séparer", callback: it => {
|
||||||
|
this.onSplit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
super(conf, options);
|
super(conf, options);
|
||||||
|
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
@ -28,18 +35,18 @@ export class DialogSplitItem extends Dialog {
|
|||||||
this.splitData = splitData;
|
this.splitData = splitData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async onSplit(){
|
||||||
|
await $(".choix-quantite").change();
|
||||||
|
this.callback(this.item, this.splitData.choix.quantite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
this.html = html;
|
|
||||||
this.html.find(".choix-quantite").change(event => {
|
html.find(".choix-quantite").change(event => {
|
||||||
this.splitData.choix.quantite = Number(event.currentTarget.value);
|
this.splitData.choix.quantite = Number(event.currentTarget.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async onSplit() {
|
|
||||||
await this.html.find(".choix-quantite").change();
|
|
||||||
this.callback(this.item, this.splitData.choix.quantite);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
72
module/dialog-stress.js
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Misc } from "./misc.js";
|
||||||
|
|
||||||
|
export class DialogStress extends Dialog {
|
||||||
|
|
||||||
|
static async distribuerStress() {
|
||||||
|
let dialogData = {
|
||||||
|
motif: "Motif",
|
||||||
|
stress: 10,
|
||||||
|
immediat: false,
|
||||||
|
actors: game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage())
|
||||||
|
.map(actor => {
|
||||||
|
let actorData = duplicate(actor);
|
||||||
|
actorData.selected = actor.hasPlayerOwner;
|
||||||
|
return actorData;
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-stress.html", dialogData);
|
||||||
|
new DialogStress(dialogData, html)
|
||||||
|
.render(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(dialogData, html) {
|
||||||
|
let options = { classes: ["DialogStress"], width: 400, height: 320, 'z-index': 99999 };
|
||||||
|
let conf = {
|
||||||
|
title: "Donner du stress",
|
||||||
|
content: html,
|
||||||
|
buttons: {
|
||||||
|
"Stress": { label: "Stress !", callback: it => { this._onStress(); } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
super(conf, options);
|
||||||
|
this.dialogData = dialogData;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _onStress() {
|
||||||
|
this.validerStress();
|
||||||
|
const compteur = this.dialogData.immediat ? 'experience' : 'stress';
|
||||||
|
const stress = this.dialogData.stress;
|
||||||
|
const motif = this.dialogData.motif;
|
||||||
|
|
||||||
|
this.dialogData.actors.filter(it => it.selected)
|
||||||
|
.map(it => game.actors.get(it._id))
|
||||||
|
.forEach(actor => actor.distribuerStress(compteur, stress, motif));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
validerStress() {
|
||||||
|
this.dialogData.motif = $("form.rdddialogstress input[name='motif']").val();
|
||||||
|
this.dialogData.stress = $("form.rdddialogstress input[name='stress']").val();
|
||||||
|
this.dialogData.immediat = $("form.rdddialogstress input[name='immediat']").prop("checked");;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
html.find(".select-actor").change((event) => this.onSelectActor(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
async onSelectActor(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const options = event.currentTarget.options;
|
||||||
|
for (var i = 0; i < options.length; i++) { // looping over the options
|
||||||
|
const actorId = options[i].attributes["data-actor-id"].value;
|
||||||
|
const actor = this.dialogData.actors.find(it => it._id == actorId);
|
||||||
|
if (actor) {
|
||||||
|
actor.selected = options[i].selected;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,72 +0,0 @@
|
|||||||
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
|
|
||||||
import { RdDUtility } from "./rdd-utility.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend the base Dialog entity by defining a custom window to perform roll.
|
|
||||||
* @extends {Dialog}
|
|
||||||
*/
|
|
||||||
export class DialogValidationEncaissement extends Dialog {
|
|
||||||
|
|
||||||
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,
|
|
||||||
rollData: rollData,
|
|
||||||
encaissement: encaissement,
|
|
||||||
show: show
|
|
||||||
});
|
|
||||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser);
|
|
||||||
dialog.render(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
constructor(html, actor, rollData, armure, encaissement, show, attackerId, onEncaisser) {
|
|
||||||
// Common conf
|
|
||||||
let buttons = {
|
|
||||||
"valider": { label: "Valider", callback: html => this.onValider() },
|
|
||||||
"annuler": { label: "Annuler", callback: html => { } },
|
|
||||||
};
|
|
||||||
|
|
||||||
let dialogConf = {
|
|
||||||
title: "Validation d'encaissement",
|
|
||||||
content: html,
|
|
||||||
buttons: buttons,
|
|
||||||
default: "valider"
|
|
||||||
}
|
|
||||||
|
|
||||||
let dialogOptions = {
|
|
||||||
classes: ["rdd-roll-dialog"],
|
|
||||||
width: 350,
|
|
||||||
height: 290
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select proper roll dialog template and stuff
|
|
||||||
super(dialogConf, dialogOptions);
|
|
||||||
|
|
||||||
this.actor = actor
|
|
||||||
this.rollData = rollData;
|
|
||||||
this.armure = armure;
|
|
||||||
this.encaissement = encaissement;
|
|
||||||
this.show = show;
|
|
||||||
this.attackerId = attackerId;
|
|
||||||
this.onEncaisser = onEncaisser;
|
|
||||||
this.forceDiceResult = {total: encaissement.roll.result };
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
this.html = html;
|
|
||||||
this.html.find('input.encaissement-roll-result').keyup(async event => {
|
|
||||||
this.forceDiceResult.total = event.currentTarget.value;
|
|
||||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
|
||||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
|
||||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async onValider() {
|
|
||||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
|
||||||
this.onEncaisser(this.encaissement, this.show, this.attackerId)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
import { SYSTEM_RDD } from "./constants.js";
|
|
||||||
import { Grammar } from "./grammar.js";
|
|
||||||
import { Misc } from "./misc.js";
|
|
||||||
import { CompendiumTableHelpers, CompendiumTable, SystemCompendiums } from "./settings/system-compendiums.js";
|
|
||||||
|
|
||||||
|
|
||||||
const COMPENDIUMS_RECHERCHE = 'compendiums-recherche';
|
|
||||||
|
|
||||||
export class Environnement {
|
|
||||||
static init() {
|
|
||||||
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: false,
|
|
||||||
type: Object
|
|
||||||
});
|
|
||||||
|
|
||||||
game.system.rdd.environnement = new Environnement();
|
|
||||||
Hooks.once('ready', () => game.system.rdd.environnement.onReady());
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.compendiums = [];
|
|
||||||
this.compendiumTables = [];
|
|
||||||
this.mapMilieux = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
async onReady() {
|
|
||||||
await this.$prepareCompendiums()
|
|
||||||
}
|
|
||||||
|
|
||||||
async milieux() {
|
|
||||||
return Object.values(this.mapMilieux);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveCompendiums(compendiumIds) {
|
|
||||||
game.settings.set(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, compendiumIds);
|
|
||||||
await this.$prepareCompendiums();
|
|
||||||
}
|
|
||||||
|
|
||||||
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 milieuxExistants = item.getMilieux().map(it => Grammar.toLowerCaseNoAccent(it));
|
|
||||||
return Object.keys(this.mapMilieux)
|
|
||||||
.filter(it => !milieuxExistants.includes(it))
|
|
||||||
.map(it => this.mapMilieux[it]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getElements(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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -19,14 +19,10 @@ export class Grammar {
|
|||||||
return word.match(/^[aeiouy]/i)
|
return word.match(/^[aeiouy]/i)
|
||||||
}
|
}
|
||||||
|
|
||||||
static equalsInsensitive(a, b) {
|
|
||||||
return Grammar.toLowerCaseNoAccent(a) == Grammar.toLowerCaseNoAccent(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
static includesLowerCaseNoAccent(value, content) {
|
static includesLowerCaseNoAccent(value, content) {
|
||||||
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
|
return Grammar.toLowerCaseNoAccent(value).includes(Grammar.toLowerCaseNoAccent(content));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static toLowerCaseNoAccent(words) {
|
static toLowerCaseNoAccent(words) {
|
||||||
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
|
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
|
||||||
|
9
module/hook-renderChatLog.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* -------------------------------------------- */
|
||||||
|
import { RdDUtility } from "./rdd-utility.js";
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
// Activate chat listeners defined
|
||||||
|
// Hooks.on('renderChatLog', (log, html, data) => {
|
||||||
|
// RdDUtility.chatListeners(html);
|
||||||
|
// });
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
export class HtmlUtility{
|
export class HtmlUtility{
|
||||||
static showControlWhen(jQuerySelector, condition) {
|
static _showControlWhen(control, condition) {
|
||||||
if (condition) {
|
if (condition) {
|
||||||
jQuerySelector.show();
|
control.show();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
jQuerySelector.hide();
|
control.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
||||||
import { TYPES } from "./item.js";
|
import { Misc } from "./misc.js";
|
||||||
import { RdDCombatManager } from "./rdd-combat.js";
|
import { RdDCombatManager } from "./rdd-combat.js";
|
||||||
|
|
||||||
const nomCategorieParade = {
|
const nomCategorieParade = {
|
||||||
@ -19,16 +19,18 @@ const nomCategorieParade = {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
export class RdDItemArme extends Item {
|
export class RdDItemArme extends Item {
|
||||||
|
|
||||||
static isArme(item) {
|
static isArme(itemData) {
|
||||||
return RdDItemCompetenceCreature.getCategorieAttaque(item) || item.type == 'arme';
|
itemData = itemData
|
||||||
|
return (itemData.type == 'competencecreature' && itemData.system.iscombat) || itemData.type == 'arme';
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getArme(arme) {
|
static getArmeData(armeData) {
|
||||||
switch (arme ? arme.type : '') {
|
armeData = armeData
|
||||||
case 'arme': return arme;
|
switch (armeData ? armeData.type : '') {
|
||||||
|
case 'arme': return armeData;
|
||||||
case 'competencecreature':
|
case 'competencecreature':
|
||||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
return RdDItemCompetenceCreature.toActionArme(armeData);
|
||||||
}
|
}
|
||||||
return RdDItemArme.mainsNues();
|
return RdDItemArme.mainsNues();
|
||||||
}
|
}
|
||||||
@ -158,18 +160,18 @@ export class RdDItemArme extends Item {
|
|||||||
return armeData;
|
return armeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
static isArmeUtilisable(arme) {
|
static isArmeUtilisable(itemData) {
|
||||||
return arme.type == 'arme' && arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0);
|
return itemData.type == 'arme' && itemData.system.equipe && (itemData.system.resistance > 0 || itemData.system.portee_courte > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ajoutCorpsACorps(armes, competences, carac) {
|
static ajoutCorpsACorps(armes, competences, carac) {
|
||||||
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
|
let corpsACorps = competences.find(it => it.name == 'Corps à corps') ?? { system: { niveau: -6 } };
|
||||||
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
|
let init = RdDCombatManager.calculInitiative(corpsACorps.system.niveau, carac['melee'].value);
|
||||||
armes.push(RdDItemArme.mainsNues({ niveau: corpsACorps.system.niveau, initiative: init }));
|
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.data.niveau, initiative: init }));
|
||||||
}
|
}
|
||||||
|
|
||||||
static corpsACorps(mainsNuesActor) {
|
static corpsACorps(actorData) {
|
||||||
const corpsACorps = {
|
const corpsACorps = {
|
||||||
name: 'Corps à corps',
|
name: 'Corps à corps',
|
||||||
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
|
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
|
||||||
@ -177,27 +179,27 @@ export class RdDItemArme extends Item {
|
|||||||
equipe: true,
|
equipe: true,
|
||||||
rapide: true,
|
rapide: true,
|
||||||
force: 0,
|
force: 0,
|
||||||
dommages: "0",
|
dommages: 0,
|
||||||
dommagesReels: 0,
|
dommagesReels: 0,
|
||||||
mortalite: 'non-mortel',
|
mortalite: 'non-mortel',
|
||||||
competence: 'Corps à corps',
|
competence: 'Corps à corps',
|
||||||
categorie_parade: 'sans-armes'
|
categorie_parade: 'sans-armes'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mergeObject(corpsACorps.system, mainsNuesActor ?? {}, { overwrite: false });
|
mergeObject(corpsACorps.system, actorData ?? {}, { overwrite: false });
|
||||||
return corpsACorps;
|
return corpsACorps;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mainsNues(mainsNuesActor) {
|
static mainsNues(actorData) {
|
||||||
const mainsNues = RdDItemArme.corpsACorps(mainsNuesActor)
|
const mainsNues = RdDItemArme.corpsACorps(actorData)
|
||||||
mainsNues.name = 'Mains nues'
|
mainsNues.name = 'Mains nues'
|
||||||
mainsNues.system.cac = 'pugilat'
|
mainsNues.system.cac = 'pugilat'
|
||||||
mainsNues.system.baseInit = 4
|
mainsNues.system.baseInit = 4
|
||||||
return mainsNues;
|
return mainsNues;
|
||||||
}
|
}
|
||||||
|
|
||||||
static empoignade(mainsNuesActor) {
|
static empoignade(actorData) {
|
||||||
const empoignade = RdDItemArme.corpsACorps(mainsNuesActor)
|
const empoignade = RdDItemArme.corpsACorps(actorData)
|
||||||
empoignade.name = 'Empoignade'
|
empoignade.name = 'Empoignade'
|
||||||
empoignade.system.cac = 'empoignade'
|
empoignade.system.cac = 'empoignade'
|
||||||
empoignade.system.baseInit = 3
|
empoignade.system.baseInit = 3
|
||||||
|
@ -8,22 +8,22 @@ const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20,
|
|||||||
const niveau_max = xp_par_niveau.length - 10;
|
const niveau_max = xp_par_niveau.length - 10;
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
const limitesArchetypes = [
|
const limitesArchetypes = [
|
||||||
{ "niveau": 0, "nombreMax": 100, "reste": 100 },
|
{ "niveau": 0, "nombreMax": 100, "nombre": 0 },
|
||||||
{ "niveau": 1, "nombreMax": 10, "reste": 10 },
|
{ "niveau": 1, "nombreMax": 10, "nombre": 0 },
|
||||||
{ "niveau": 2, "nombreMax": 9, "reste": 9 },
|
{ "niveau": 2, "nombreMax": 9, "nombre": 0 },
|
||||||
{ "niveau": 3, "nombreMax": 8, "reste": 8 },
|
{ "niveau": 3, "nombreMax": 8, "nombre": 0 },
|
||||||
{ "niveau": 4, "nombreMax": 7, "reste": 7 },
|
{ "niveau": 4, "nombreMax": 7, "nombre": 0 },
|
||||||
{ "niveau": 5, "nombreMax": 6, "reste": 6 },
|
{ "niveau": 5, "nombreMax": 6, "nombre": 0 },
|
||||||
{ "niveau": 6, "nombreMax": 5, "reste": 5 },
|
{ "niveau": 6, "nombreMax": 5, "nombre": 0 },
|
||||||
{ "niveau": 7, "nombreMax": 4, "reste": 4 },
|
{ "niveau": 7, "nombreMax": 4, "nombre": 0 },
|
||||||
{ "niveau": 8, "nombreMax": 3, "reste": 3 },
|
{ "niveau": 8, "nombreMax": 3, "nombre": 0 },
|
||||||
{ "niveau": 9, "nombreMax": 2, "reste": 2 },
|
{ "niveau": 9, "nombreMax": 2, "nombre": 0 },
|
||||||
{ "niveau": 10, "nombreMax": 1, "reste": 1 },
|
{ "niveau": 10, "nombreMax": 1, "nombre": 0 },
|
||||||
{ "niveau": 11, "nombreMax": 1, "reste": 1 }
|
{ "niveau": 11, "nombreMax": 1, "nombre": 0 }
|
||||||
];
|
];
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
const categoriesCompetences = {
|
const categorieCompetences = {
|
||||||
"generale": { base: -4, label: "Générales" },
|
"generale": { base: -4, label: "Générales" },
|
||||||
"particuliere": { base: -8, label: "Particulières" },
|
"particuliere": { base: -8, label: "Particulières" },
|
||||||
"specialisee": { base: -11, label: "Spécialisées" },
|
"specialisee": { base: -11, label: "Spécialisées" },
|
||||||
@ -34,6 +34,13 @@ const categoriesCompetences = {
|
|||||||
"lancer": { base: -8, label: "Lancer" }
|
"lancer": { base: -8, label: "Lancer" }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const compendiumCompetences = {
|
||||||
|
"personnage": "foundryvtt-reve-de-dragon.competences",
|
||||||
|
"creature": "foundryvtt-reve-de-dragon.competences-creatures",
|
||||||
|
"entite": "foundryvtt-reve-de-dragon.competences-entites"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function _buildCumulXP() {
|
function _buildCumulXP() {
|
||||||
let cumulXP = { "-11": 0 };
|
let cumulXP = { "-11": 0 };
|
||||||
let cumul = 0;
|
let cumul = 0;
|
||||||
@ -48,17 +55,23 @@ function _buildCumulXP() {
|
|||||||
const competence_xp_cumul = _buildCumulXP();
|
const competence_xp_cumul = _buildCumulXP();
|
||||||
|
|
||||||
export class RdDItemCompetence extends Item {
|
export class RdDItemCompetence extends Item {
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getCategories() {
|
static actorCompendium(actorType) {
|
||||||
return categoriesCompetences;
|
return compendiumCompetences[actorType];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static getCategorieCompetences() {
|
||||||
|
return categorieCompetences;
|
||||||
|
}
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static getNiveauBase(category) {
|
||||||
|
return categorieCompetences[category].base;
|
||||||
}
|
}
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getLabelCategorie(category) {
|
static getLabelCategorie(category) {
|
||||||
return categoriesCompetences[category].label;
|
return categorieCompetences[category].label;
|
||||||
}
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
static getNiveauBase(category, categories = categoriesCompetences) {
|
|
||||||
return categories[category]?.base ?? 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -71,36 +84,27 @@ export class RdDItemCompetence extends Item {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getVoieDraconic(competences, voie) {
|
static getVoieDraconic(competences, voie) {
|
||||||
return RdDItemCompetence.findFirstItem(competences, voie, {
|
return RdDItemCompetence.findCompetence(competences.filter(it => RdDItemCompetence.isDraconic(it)), voie);
|
||||||
preFilter: it => it.isCompetence() && RdDItemCompetence.isDraconic(it),
|
|
||||||
description: 'Draconic',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static isCompetenceArme(competence) {
|
static isCompetenceArme(competence) {
|
||||||
if (competence.isCompetence()) {
|
switch (competence.system.categorie) {
|
||||||
switch (competence.system.categorie) {
|
case 'melee':
|
||||||
case 'melee':
|
return competence.name != 'Esquive';
|
||||||
return !Grammar.toLowerCaseNoAccent(competence.name).includes('esquive');
|
case 'tir':
|
||||||
case 'tir':
|
case 'lancer':
|
||||||
case 'lancer':
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static isArmeUneMain(competence) {
|
static isArmeUneMain(competence) {
|
||||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("1 main");
|
return competence.name.toLowerCase().includes("1 main");
|
||||||
}
|
}
|
||||||
static isArme2Main(competence) {
|
static isArme2Main(competence) {
|
||||||
return RdDItemCompetence.isCompetenceArme(competence) && competence.name.toLowerCase().includes("2 main");
|
return competence.name.toLowerCase().includes("2 main");
|
||||||
}
|
|
||||||
|
|
||||||
static isThanatos(competence) {
|
|
||||||
return competence.isCompetencePersonnage() && Grammar.toLowerCaseNoAccent(competence.name).includes('thanatos');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -129,7 +133,7 @@ export class RdDItemCompetence extends Item {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static computeXP(competence) {
|
static computeXP(competence) {
|
||||||
const factor = RdDItemCompetence.isThanatos(competence) ? 2 : 1; // Thanatos compte double !
|
const factor = competence.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
|
||||||
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.system.base, competence.system.niveau ?? competence.system.base);
|
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.system.base, competence.system.niveau ?? competence.system.base);
|
||||||
const xp = competence.system.xp ?? 0;
|
const xp = competence.system.xp ?? 0;
|
||||||
const xpSort = competence.system.xp_sort ?? 0;
|
const xpSort = competence.system.xp_sort ?? 0;
|
||||||
@ -179,56 +183,51 @@ export class RdDItemCompetence extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static levelUp(item, stressTransforme) {
|
static levelUp(itemData, stressTransforme) {
|
||||||
item.system.xpNext = RdDItemCompetence.getCompetenceNextXp(item.system.niveau);
|
itemData.system.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.system.niveau);
|
||||||
const xpManquant = item.system.xpNext - item.system.xp;
|
const xpManquant = itemData.system.xpNext - itemData.system.xp;
|
||||||
item.system.isLevelUp = xpManquant <= 0;
|
itemData.system.isLevelUp = xpManquant <= 0;
|
||||||
item.system.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && item.system.niveau < item.system.niveau_archetype);
|
itemData.system.isStressLevelUp = (xpManquant > 0 && stressTransforme >= xpManquant && itemData.system.niveau < itemData.system.niveau_archetype);
|
||||||
item.system.stressXpMax = 0;
|
itemData.system.stressXpMax = 0;
|
||||||
if (xpManquant > 0 && stressTransforme > 0 && item.system.niveau < item.system.niveau_archetype) {
|
if (xpManquant > 0 && stressTransforme > 0 && itemData.system.niveau < itemData.system.niveau_archetype) {
|
||||||
item.system.stressXpMax = Math.min(xpManquant, stressTransforme);
|
itemData.system.stressXpMax = Math.min(xpManquant , stressTransforme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static isNiveauBase(item) {
|
static isVisible(itemData) {
|
||||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.getCategories());
|
return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
|
||||||
|
}
|
||||||
|
|
||||||
|
static nomContientTexte(itemData, texte) {
|
||||||
|
return Grammar.toLowerCaseNoAccent(itemData.name).includes(Grammar.toLowerCaseNoAccent(texte))
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
static isNiveauBase(itemData) {
|
||||||
|
return Number(itemData.system.niveau) == RdDItemCompetence.getNiveauBase(itemData.system.categorie);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static findCompetence(list, idOrName, options = {}) {
|
static findCompetence(list, idOrName, options = {}) {
|
||||||
if (idOrName == undefined || idOrName == "") {
|
if (idOrName == undefined) {
|
||||||
return RdDItemCompetence.sansCompetence();
|
return undefined;
|
||||||
}
|
}
|
||||||
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false });
|
options = mergeObject(options, {
|
||||||
return RdDItemCompetence.findFirstItem(list, idOrName, options);
|
preFilter: it => RdDItemCompetence.isCompetence(it),
|
||||||
|
description: 'compétence',
|
||||||
|
});
|
||||||
|
return list.find(it => it.id == idOrName && RdDItemCompetence.isCompetence(it))
|
||||||
|
?? Misc.findFirstLike(idOrName, list, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static findCompetences(list, name) {
|
static findCompetences(list, name) {
|
||||||
return Misc.findAllLike(name, list, { filter: it => it.isCompetence(), description: 'compétence' });
|
return Misc.findAllLike(name, list, { filter: it => RdDItemCompetence.isCompetence(it), description: 'compétence' });
|
||||||
}
|
}
|
||||||
|
|
||||||
static sansCompetence() {
|
static isCompetence(item) {
|
||||||
return {
|
return item.type == 'competence' || item.type == 'competencecreature';
|
||||||
name: "Sans compétence",
|
|
||||||
type: "competence",
|
|
||||||
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.webp",
|
|
||||||
system: {
|
|
||||||
niveau: 0,
|
|
||||||
default_diffLibre: 0,
|
|
||||||
base: 0,
|
|
||||||
categorie: "Aucune",
|
|
||||||
description: "",
|
|
||||||
descriptionmj: "",
|
|
||||||
defaut_carac: "",
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static findFirstItem(list, idOrName, options) {
|
|
||||||
return list.find(it => it.id == idOrName && options.preFilter(it))
|
|
||||||
?? Misc.findFirstLike(idOrName, list, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
@ -258,47 +257,18 @@ export class RdDItemCompetence extends Item {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static computeResumeArchetype(competences) {
|
static computeResumeArchetype(competences) {
|
||||||
const computed = duplicate(limitesArchetypes);
|
const archetype = RdDItemCompetence.getLimitesArchetypes();
|
||||||
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
||||||
.filter(n => n > 0)
|
.forEach(niveau => {
|
||||||
.forEach(n => {
|
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
|
||||||
computed[n] = computed[n] ?? { niveau: n, nombreMax: 0, reste: 0 };
|
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
|
||||||
computed[n].reste = computed[n].reste - 1;
|
|
||||||
});
|
});
|
||||||
return computed.filter(it => it.reste > 0 && it.niveau > 0);
|
return archetype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static triVisible(competences) {
|
static getLimitesArchetypes() {
|
||||||
return competences.filter(it => !it.system.isHidden)
|
return duplicate(limitesArchetypes);
|
||||||
.sort((a, b) => RdDItemCompetence.compare(a, b))
|
|
||||||
}
|
|
||||||
|
|
||||||
static $positionTri(comp) {
|
|
||||||
if (comp.name.startsWith("Survie")) {
|
|
||||||
if (comp.name.includes("Cité")) return 0;
|
|
||||||
if (comp.name.includes("Extérieur")) return 1;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
if (comp.system.categorie.startsWith("melee")) {
|
|
||||||
if (comp.name.includes("Corps")) return 0;
|
|
||||||
if (comp.name.includes("Dague")) return 1;
|
|
||||||
if (comp.name.includes("Esquive")) return 2;
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
if (comp.system.categorie.startsWith("draconic")) {
|
|
||||||
if (comp.name.includes("Oniros")) return 0;
|
|
||||||
if (comp.name.includes("Hypnos")) return 1;
|
|
||||||
if (comp.name.includes("Narcos")) return 2;
|
|
||||||
if (comp.name.includes("Thanatos")) return 3;
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static compare(a, b) {
|
|
||||||
const diff = RdDItemCompetence.$positionTri(a) - RdDItemCompetence.$positionTri(b);
|
|
||||||
return diff ? diff : a.name.localeCompare(b.name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,99 +1,51 @@
|
|||||||
|
import { Misc } from "./misc.js";
|
||||||
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 {
|
export class RdDItemCompetenceCreature extends Item {
|
||||||
|
|
||||||
static getCategories() {
|
|
||||||
return categories;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static setRollDataCreature(rollData) {
|
static setRollDataCreature(rollData) {
|
||||||
|
rollData.competence = rollData.competence
|
||||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||||
rollData.competence.system.defaut_carac = "carac_creature"
|
rollData.competence.system.defaut_carac = "carac_creature"
|
||||||
rollData.selectedCarac = rollData.carac.carac_creature
|
rollData.competence.system.categorie = "creature"
|
||||||
rollData.arme = RdDItemCompetenceCreature.armeCreature(rollData.competence);
|
rollData.selectedCarac = rollData.carac.carac_creature
|
||||||
|
if (rollData.competence.system.iscombat) {
|
||||||
|
rollData.arme = RdDItemCompetenceCreature.toActionArme(rollData.competence);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static armeCreature(item) {
|
static toActionArme(item) {
|
||||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
if (RdDItemCompetenceCreature.isCompetenceAttaque(item)) {
|
||||||
if (categorieAttaque != undefined) {
|
// si c'est un Item compétence: cloner pour ne pas modifier lma compétence
|
||||||
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
|
let arme = (item instanceof Item) ? item.clone(): item;
|
||||||
let arme = item.clone();
|
mergeObject(arme.system,
|
||||||
mergeObject(arme,
|
|
||||||
{
|
{
|
||||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
competence: arme.name,
|
||||||
system: {
|
resistance: 100,
|
||||||
competence: arme.name,
|
equipe: true,
|
||||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
dommagesReels: arme.system.dommages,
|
||||||
niveau: item.system.niveau,
|
penetration: 0,
|
||||||
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
|
force: 0,
|
||||||
equipe: true,
|
rapide: true,
|
||||||
resistance: 100,
|
action: 'attaque'
|
||||||
dommagesReels: arme.system.dommages,
|
|
||||||
penetration: 0,
|
|
||||||
force: 0,
|
|
||||||
rapide: true,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
return arme;
|
return arme;
|
||||||
}
|
}
|
||||||
|
console.error("RdDItemCompetenceCreature.toActionArme(", item, ") : impossible de transformer l'Item en arme");
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getCategorieAttaque(item) {
|
static isCompetenceAttaque(itemData) {
|
||||||
if (item.type == TYPES.competencecreature) {
|
itemData = itemData
|
||||||
switch (item.system.categorie) {
|
return itemData.type == 'competencecreature' && itemData.system.iscombat;
|
||||||
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) {
|
static isCompetenceParade(itemData) {
|
||||||
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
|
itemData = itemData
|
||||||
|
return itemData.type == 'competencecreature' && itemData.system.isparade;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,113 +1,59 @@
|
|||||||
import { Misc } from "./misc.js";
|
import { Misc } from "./misc.js";
|
||||||
import { LOG_HEAD } from "./constants.js";
|
|
||||||
|
|
||||||
const MONNAIE_ETAIN = {
|
const monnaiesData = [
|
||||||
name: "Denier (étain)", type: 'monnaie',
|
{
|
||||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
|
name: "Etain (1 denier)", type: 'monnaie',
|
||||||
system: { quantite: 0, cout: 0.01, encombrement: 0.001, description: "" }
|
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
|
||||||
};
|
data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
|
||||||
const MONNAIE_BRONZE = {
|
},
|
||||||
name: "Sou (bronze)", type: 'monnaie',
|
{
|
||||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
|
name: "Bronze (10 deniers)", type: 'monnaie',
|
||||||
system: { quantite: 0, cout: 0.10, encombrement: 0.002, description: "" }
|
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
|
||||||
};
|
data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
|
||||||
const MONNAIE_ARGENT = {
|
},
|
||||||
name: "Sol (argent)", type: 'monnaie',
|
{
|
||||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
|
name: "Argent (1 sol)", type: 'monnaie',
|
||||||
system: { quantite: 0, cout: 1, encombrement: 0.003, description: "" }
|
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
|
||||||
};
|
data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
|
||||||
const MONNAIE_OR = {
|
},
|
||||||
name: "Dragon (or)", type: 'monnaie',
|
{
|
||||||
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
|
name: "Or (10 sols)", type: 'monnaie',
|
||||||
system: { quantite: 0, cout: 10, encombrement: 0.004, description: "" }
|
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
|
||||||
};
|
data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
|
||||||
|
}
|
||||||
const MONNAIES_STANDARD = [MONNAIE_ETAIN, MONNAIE_BRONZE, MONNAIE_ARGENT, MONNAIE_OR];
|
]
|
||||||
const VALEUR_DENIERS = sols => Math.max(Math.floor((sols ?? 0) * 100), 0);
|
|
||||||
|
|
||||||
export class Monnaie {
|
export class Monnaie {
|
||||||
|
|
||||||
static monnaiesStandard() {
|
static isSystemMonnaie(item) {
|
||||||
return MONNAIES_STANDARD;
|
let present = monnaiesData.find(monnaie => monnaie.system.valeur_deniers == item?.system?.valeur_deniers);
|
||||||
|
return present;
|
||||||
}
|
}
|
||||||
|
|
||||||
static monnaiesManquantes(actor) {
|
static monnaiesData() {
|
||||||
const disponibles = actor.itemTypes['monnaie'];
|
return monnaiesData;
|
||||||
const manquantes = MONNAIES_STANDARD.filter(standard => !disponibles.find(disponible => Monnaie.deValeur(disponible, standard.system?.cout)));
|
|
||||||
if (manquantes.length > 0) {
|
|
||||||
console.error(`${LOG_HEAD} monnaiesManquantes pour ${actor.name}`, manquantes, ' avec monnaies', disponibles, MONNAIES_STANDARD);
|
|
||||||
}
|
|
||||||
return manquantes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static deValeur(monnaie, valeur) {
|
static filtrerMonnaies(items) {
|
||||||
return VALEUR_DENIERS(valeur) == VALEUR_DENIERS(monnaie.system.cout)
|
return items.filter(it => it.type == 'monnaie');
|
||||||
}
|
}
|
||||||
|
|
||||||
static triValeurEntiere() {
|
static monnaiesManquantes(items) {
|
||||||
return Misc.ascending(item => VALEUR_DENIERS(item.system.cout))
|
const valeurs = Monnaie.filtrerMonnaies(items)
|
||||||
|
.map(it => it.system.valeur_deniers);
|
||||||
|
const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != monnaie.system?.valeur_deniers))
|
||||||
|
return []; //manquantes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static async creerMonnaiesStandard(actor) {
|
static deValeur(monnaie, v) {
|
||||||
await actor.createEmbeddedDocuments('Item', MONNAIES_STANDARD, { renderSheet: false });
|
return v != monnaie.system.valeur_deniers
|
||||||
}
|
}
|
||||||
|
|
||||||
static async creerMonnaiesDeniers(actor, fortune) {
|
static arrondiDeniers(sols) {
|
||||||
await actor.createEmbeddedDocuments('Item', [Monnaie.creerDeniers(fortune)], { renderSheet: false });
|
return sols.toFixed(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static creerDeniers(fortune) {
|
static triValeurDenier() {
|
||||||
const deniers = duplicate(MONNAIE_ETAIN);
|
return Misc.ascending(item => item.system.valeur_deniers)
|
||||||
deniers.system.quantite = fortune;
|
|
||||||
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))
|
|
||||||
.reduce(Misc.sum(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async optimiserFortune(actor, fortune) {
|
|
||||||
let resteEnDeniers = Math.round(fortune * 100);
|
|
||||||
let monnaies = actor.itemTypes['monnaie'];
|
|
||||||
let updates = [];
|
|
||||||
Monnaie.validerMonnaies(monnaies, actor);
|
|
||||||
|
|
||||||
let parValeur = Misc.classifyFirst(monnaies, it => VALEUR_DENIERS(it.system.cout));
|
|
||||||
for (let valeurDeniers of [1000, 100, 10, 1]) {
|
|
||||||
const itemPiece = parValeur[valeurDeniers];
|
|
||||||
if (itemPiece) {
|
|
||||||
const quantite = Math.floor(resteEnDeniers / valeurDeniers);
|
|
||||||
if (quantite != itemPiece.system.quantite) {
|
|
||||||
updates.push({ _id: parValeur[valeurDeniers].id, 'system.quantite': quantite });
|
|
||||||
}
|
|
||||||
resteEnDeniers -= quantite * valeurDeniers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log('Monnaie.optimiserFortune', actor.name, 'total', fortune, 'parValeur', parValeur, 'updates', updates, 'reste', resteEnDeniers);
|
|
||||||
if (updates.length > 0) {
|
|
||||||
await actor.updateEmbeddedDocuments('Item', updates);
|
|
||||||
}
|
|
||||||
if (resteEnDeniers > 0) {
|
|
||||||
// créer le reste en deniers fortune en deniers
|
|
||||||
await Monnaie.creerMonnaiesDeniers(actor, resteEnDeniers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static validerMonnaies(monnaies, actor = undefined) {
|
|
||||||
monnaies.filter(it => VALEUR_DENIERS(it.system.cout) == 0)
|
|
||||||
.map(it => `La monnaie ${it.name} de l'acteur ${actor?.name ?? 'sélectionné'} a une valeur de 0!`)
|
|
||||||
.forEach(message => {
|
|
||||||
ui.notifications.warn(message);
|
|
||||||
console.warn(message);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,72 +4,45 @@ import { RdDAlchimie } from "./rdd-alchimie.js";
|
|||||||
import { RdDItemCompetence } from "./item-competence.js";
|
import { RdDItemCompetence } from "./item-competence.js";
|
||||||
import { RdDHerbes } from "./rdd-herbes.js";
|
import { RdDHerbes } from "./rdd-herbes.js";
|
||||||
import { RdDGemme } from "./rdd-gemme.js";
|
import { RdDGemme } from "./rdd-gemme.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
import { HtmlUtility } from "./html-utility.js";
|
import { HtmlUtility } from "./html-utility.js";
|
||||||
import { ReglesOptionelles } from "./settings/regles-optionelles.js";
|
import { ReglesOptionelles } from "./regles-optionelles.js";
|
||||||
import { SYSTEM_RDD } from "./constants.js";
|
import { SYSTEM_RDD } from "./constants.js";
|
||||||
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
import { RdDSheetUtility } from "./rdd-sheet-utility.js";
|
||||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
|
||||||
import { Misc } from "./misc.js";
|
|
||||||
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
|
* Extend the basic ItemSheet with some very simple modifications
|
||||||
|
* @extends {ItemSheet}
|
||||||
*/
|
*/
|
||||||
export class RdDItemSheet extends ItemSheet {
|
export class RdDItemSheet extends ItemSheet {
|
||||||
|
|
||||||
static get ITEM_TYPE() {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
static defaultTemplate(type) {
|
|
||||||
return type ?
|
|
||||||
`systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html` :
|
|
||||||
"systems/foundryvtt-reve-de-dragon/templates/item-sheet.html";
|
|
||||||
}
|
|
||||||
|
|
||||||
static register(sheetClass) {
|
|
||||||
Items.registerSheet(SYSTEM_RDD, sheetClass, {
|
|
||||||
label: Misc.typeName('Item', sheetClass.ITEM_TYPE),
|
|
||||||
types: [sheetClass.ITEM_TYPE],
|
|
||||||
makeDefault: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
static get defaultOptions() {
|
static get defaultOptions() {
|
||||||
return mergeObject(super.defaultOptions, {
|
return mergeObject(super.defaultOptions, {
|
||||||
classes: [SYSTEM_RDD, "sheet", "item"],
|
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||||
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
|
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
|
||||||
width: 550,
|
width: 550,
|
||||||
height: 550
|
height: 550
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
get template() {
|
|
||||||
return RdDItemSheet.defaultTemplate(this.item.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
get title() {
|
|
||||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
_getHeaderButtons() {
|
_getHeaderButtons() {
|
||||||
let buttons = super._getHeaderButtons();
|
let buttons = super._getHeaderButtons();
|
||||||
if (this.item.isInventaire() && this.item.isVideOuNonConteneur()) {
|
// Add "Post to chat" button
|
||||||
|
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
|
||||||
|
if ("cout" in this.object.system && this.object.isVideOuNonConteneur()) {
|
||||||
buttons.unshift({
|
buttons.unshift({
|
||||||
class: "vendre",
|
class: "vendre",
|
||||||
icon: "fas fa-comments-dollar",
|
icon: "fas fa-comments-dollar",
|
||||||
onclick: ev => this.item.proposerVente(1)
|
onclick: ev => this.item.proposerVente()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
buttons.unshift({
|
buttons.unshift({
|
||||||
class: "montrer",
|
class: "montrer",
|
||||||
icon: "fas fa-comment",
|
icon: "fas fa-comment",
|
||||||
onclick: ev => this.item.postItemToChat()
|
onclick: ev => this.item.postItem()
|
||||||
});
|
});
|
||||||
return buttons
|
return buttons
|
||||||
}
|
}
|
||||||
@ -88,225 +61,231 @@ export class RdDItemSheet extends ItemSheet {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async getData() {
|
async getData() {
|
||||||
let formData = {
|
let formData = {
|
||||||
title: this.item.name,
|
id: this.object.id,
|
||||||
id: this.item.id,
|
title: this.object.name,
|
||||||
type: this.item.type,
|
type: this.object.type,
|
||||||
img: this.item.img,
|
img: this.object.img,
|
||||||
name: this.item.name,
|
name: this.object.name,
|
||||||
system: this.item.system,
|
data: this.object.system,
|
||||||
|
isGM: game.user.isGM,
|
||||||
actorId: this.actor?.id,
|
actorId: this.actor?.id,
|
||||||
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
|
owner: this.document.isOwner,
|
||||||
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
|
editable: this.isEditable,
|
||||||
isComestible: this.item.getUtilisationCuisine(),
|
cssClass: this.isEditable ? "editable" : "locked",
|
||||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable)
|
isSoins: false
|
||||||
}
|
}
|
||||||
if (this.item.type == TYPES.competencecreature) {
|
if (this.actor) {
|
||||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
formData.isOwned = true;
|
||||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
if (this.object.type == 'conteneur') {
|
||||||
|
this.prepareConteneurData(formData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const competences = await SystemCompendiums.getCompetences('personnage');
|
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences()
|
||||||
formData.categories = this.item.getCategories()
|
if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
|
||||||
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
|
|
||||||
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
||||||
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
||||||
formData.competences = competences;
|
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences')
|
||||||
}
|
}
|
||||||
if (this.item.type == 'arme') {
|
if (formData.type == 'arme') {
|
||||||
formData.competences = competences.filter(it => RdDItemCompetence.isCompetenceArme(it))
|
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
|
||||||
|
console.log(formData.competences)
|
||||||
}
|
}
|
||||||
if (['sort', 'sortreserve'].includes(this.item.type)) {
|
if (formData.type == 'recettealchimique') {
|
||||||
formData.competences = competences.filter(it => RdDItemCompetence.isDraconic(it));
|
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
|
||||||
}
|
}
|
||||||
if (this.item.type == 'recettecuisine') {
|
if (formData.type == 'gemme') {
|
||||||
formData.ingredients = await TextEditor.enrichHTML(this.object.system.ingredients, { async: true })
|
|
||||||
}
|
|
||||||
if (this.item.type == 'extraitpoetique') {
|
|
||||||
formData.extrait = await TextEditor.enrichHTML(this.object.system.extrait, { async: true })
|
|
||||||
formData.texte = await TextEditor.enrichHTML(this.object.system.texte, { async: true })
|
|
||||||
}
|
|
||||||
if (this.item.type == 'recettealchimique') {
|
|
||||||
RdDAlchimie.processManipulation(this.item, this.actor && this.actor.id);
|
|
||||||
formData.manipulation_update = await TextEditor.enrichHTML(this.object.system.manipulation_update, { async: true })
|
|
||||||
formData.utilisation = await TextEditor.enrichHTML(this.object.system.utilisation, { async: true })
|
|
||||||
formData.enchantement = await TextEditor.enrichHTML(this.object.system.enchantement, { async: true })
|
|
||||||
formData.sureffet = await TextEditor.enrichHTML(this.object.system.sureffet, { async: true })
|
|
||||||
}
|
|
||||||
if (this.item.type == 'gemme') {
|
|
||||||
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
|
formData.gemmeTypeList = RdDGemme.getGemmeTypeOptionList();
|
||||||
RdDGemme.calculDataDerivees(this.item);
|
RdDGemme.calculDataDerivees(formData.data);
|
||||||
}
|
}
|
||||||
if (this.item.type == 'potion') {
|
if (formData.type == 'potion') {
|
||||||
await RdDHerbes.addPotionFormData(formData);
|
if (this.dateUpdated) {
|
||||||
|
formData.data.prdate = this.dateUpdated;
|
||||||
|
this.dateUpdated = undefined;
|
||||||
|
}
|
||||||
|
RdDHerbes.updatePotionData(formData);
|
||||||
}
|
}
|
||||||
if (formData.options.isOwned && this.item.type == 'herbe' && (formData.system.categorie == 'Soin' || formData.system.categorie == 'Repos')) {
|
if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
|
||||||
formData.isIngredientPotionBase = true;
|
formData.isIngredientPotionBase = true;
|
||||||
}
|
}
|
||||||
if (this.item.type == 'sortreserve') {
|
|
||||||
const sortId = this.item.system.sortid;
|
|
||||||
formData.sort = formData.options.isOwned ? this.item.actor.items.get(sortId) : game.items.get(sortId);
|
|
||||||
}
|
|
||||||
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
|
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
|
||||||
|
|
||||||
return formData;
|
return formData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
prepareConteneurData(formData) {
|
||||||
|
formData.itemsByType = Misc.classify(this.actor.items.map(i => foundry.utils.deepClone(i)))
|
||||||
|
RdDUtility.filterEquipementParType(formData)
|
||||||
|
|
||||||
|
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
|
||||||
|
formData.subItems = formData.conteneurs.find(it => it._id == this.object.id)?.subItems;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/** @override */
|
/** @override */
|
||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
this.html = html;
|
|
||||||
|
|
||||||
HtmlUtility.showControlWhen(this.html.find(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs')
|
if (this.object.type == 'conteneur') {
|
||||||
|| game.user.isGM
|
this.form.ondragstart = (event) => this._onDragStart(event);
|
||||||
|| !this.item.isOwned);
|
this.form.ondrop = (event) => this._onDrop(event);
|
||||||
HtmlUtility.showControlWhen(this.html.find(".item-magique"), this.item.isMagique());
|
}
|
||||||
|
|
||||||
|
let itemSheetDialog = this;
|
||||||
|
|
||||||
|
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
|
||||||
|
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
|
||||||
|
|
||||||
// Everything below here is only needed if the sheet is editable
|
// Everything below here is only needed if the sheet is editable
|
||||||
if (!this.options.editable) return;
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
this.form.ondragstart = (event) => this._onDragStart(event);
|
|
||||||
this.form.ondrop = (event) => this._onDrop(event);
|
|
||||||
|
|
||||||
// Select competence categorie
|
// Select competence categorie
|
||||||
this.html.find(".categorie").change(event => this._onSelectCategorie(event));
|
html.find(".categorie").change(event => this._onSelectCategorie(event));
|
||||||
|
|
||||||
this.html.find('.sheet-competence-xp').change((event) => {
|
html.find('.sheet-competence-xp').change((event) => {
|
||||||
if (this.item.isCompetencePersonnage()) {
|
if (this.object.data.type == 'competence') {
|
||||||
RdDUtility.checkThanatosXP(this.item.name);
|
RdDUtility.checkThanatosXP(this.object.data.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.html.find(".item-cout input[name='system.cout']").change(event => {
|
|
||||||
if (this.item.isMonnaie()) {
|
|
||||||
const value = event.currentTarget.value;
|
|
||||||
if (Number(value) == 0) {
|
|
||||||
ui.notifications.error(`${this.actor?.name ?? 'Monnaie'}: La monnaie ${this.item.name} a maintenant une valeur de 0, et ne peut plus être utilisée pour payer!`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
this.html.find('.date-enchantement').change((event) => {
|
html.find('.enchanteDate').change((event) => {
|
||||||
const jour = Number(this.html.find('input.date-enchantement[name="enchantement.jour"]').val());
|
let jour = Number($('#jourMois').val());
|
||||||
const mois = RdDTimestamp.definition(this.html.find('select.date-enchantement[name="enchantement.mois"]').val());
|
let mois = $('#nomMois').val();
|
||||||
const indexDate = game.system.rdd.calendrier.getIndexFromDate(jour, mois.heure);
|
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
|
||||||
this.item.update({ 'system.prdate': indexDate });
|
|
||||||
console.warn(`Date d'enchantement modifiée ${jour}/${mois.heure}: ${indexDate}`)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.html.find('.creer-tache-livre').click((event) => this._getEventActor(event).creerTacheDepuisLivre(this.item));
|
html.find('.creer-tache-livre').click((event) => {
|
||||||
this.html.find('.consommer-potion').click((event) => this._getEventActor(event).consommerPotion(this.item, this.getActionRenderItem()));
|
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||||
this.html.find('.creer-potion-base').click((event) => this._getEventActor(event).dialogFabriquerPotion(this.item));
|
let actor = game.actors.get(actorId);
|
||||||
|
actor.creerTacheDepuisLivre(this.item);
|
||||||
|
});
|
||||||
|
html.find('.consommer-potion').click((event) => {
|
||||||
|
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||||
|
let actor = game.actors.get(actorId);
|
||||||
|
actor.consommerPotion(this.item);
|
||||||
|
});
|
||||||
|
html.find('.creer-potion-base').click((event) => {
|
||||||
|
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||||
|
let actor = game.actors.get(actorId);
|
||||||
|
actor.dialogFabriquerPotion(this.item);
|
||||||
|
});
|
||||||
|
|
||||||
this.html.find('.alchimie-tache a').click((event) => {
|
html.find('.alchimie-tache a').click((event) => {
|
||||||
let actor = this._getEventActor(event);
|
let actorId = event.currentTarget.attributes['data-actor-id'].value;
|
||||||
|
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
||||||
|
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
||||||
|
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
||||||
|
let actor = game.actors.get(actorId);
|
||||||
if (actor) {
|
if (actor) {
|
||||||
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
|
|
||||||
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
|
|
||||||
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
|
|
||||||
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
|
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
|
||||||
} else {
|
} else {
|
||||||
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
|
ui.notifications.info("Impossible trouver un acteur pour réaliser cette tache Alchimique.");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.actor) {
|
html.find('.item-split').click(async event => {
|
||||||
this.html.find('.item-split').click(async event => RdDSheetUtility.splitItem(RdDSheetUtility.getItem(event, this.actor), this.actor, this.getActionRenderItem()));
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
this.html.find('.item-edit').click(async event => RdDSheetUtility.getItem(event, this.actor)?.sheet.render(true));
|
await RdDSheetUtility.splitItem(item, this.actor, async () => itemSheetDialog.render(true));
|
||||||
this.html.find('.item-delete').click(async event => RdDUtility.confirmActorItemDelete(this, RdDSheetUtility.getItem(event, this.actor)));
|
});
|
||||||
this.html.find('.item-vendre').click(async event => RdDSheetUtility.getItem(event, this.actor)?.proposerVente());
|
html.find('.item-edit').click(async event => {
|
||||||
this.html.find('.item-montrer').click(async event => RdDSheetUtility.getItem(event, this.actor)?.postItemToChat());
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
this.html.find('.item-action').click(async event => RdDSheetUtility.getItem(event, this.actor)?.actionPrincipale(this.actor, this.getActionRenderItem()));
|
item.sheet.render(true);
|
||||||
|
});
|
||||||
this.html.find('.item-quantite-plus').click(async event => {
|
html.find('.item-delete').click(async event => {
|
||||||
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), 1)
|
const li = RdDSheetUtility.getEventElement(event);
|
||||||
this.render();
|
RdDUtility.confirmerSuppression(this, li);
|
||||||
});
|
});
|
||||||
this.html.find('.item-quantite-moins').click(async event => {
|
html.find('.item-vendre').click(async event => {
|
||||||
await this.actor.itemQuantiteIncDec(RdDSheetUtility.getItemId(event), -1)
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
this.render();
|
item?.proposerVente();
|
||||||
});
|
});
|
||||||
}
|
html.find('.item-montrer').click(async event => {
|
||||||
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: duplicate(timestamp) })
|
item?.postItem();
|
||||||
|
});
|
||||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp);
|
html.find('.item-action').click(async event => {
|
||||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp);
|
const item = RdDSheetUtility.getItem(event, this.actor);
|
||||||
|
this.actor.actionItem(item, async () => itemSheetDialog.render(true));
|
||||||
|
});
|
||||||
|
html.find('.conteneur-name a').click(async event => {
|
||||||
|
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
||||||
|
this.render(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
return actor;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
async _onSelectCategorie(event) {
|
async _onSelectCategorie(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if (this.item.isCompetence()) {
|
if (this.object.isCompetence()) {
|
||||||
const categorie = event.currentTarget.value;
|
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
|
||||||
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.getCategories());
|
this.object.system.base = level;
|
||||||
this.item.system.base = level;
|
$("#base").val(level);
|
||||||
this.html.find('[name="system.base"]').val(level);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
|
get template() {
|
||||||
|
let type = this.object.type
|
||||||
|
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
_updateObject(event, formData) {
|
_updateObject(event, formData) { // Deprecated en v0.8 à clarifier
|
||||||
if (this.item.type == 'sort') {
|
// Données de bonus de cases ?
|
||||||
// Données de bonus de cases ?
|
formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
|
||||||
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue);
|
|
||||||
}
|
return this.object.update(formData);
|
||||||
return this.item.update(formData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async _onDragStart(event) {
|
async _onDragStart(event) {
|
||||||
|
console.log("_onDragStart", event);
|
||||||
|
if (event.target.classList.contains("entity-link")) return;
|
||||||
|
|
||||||
|
const itemId = event.srcElement?.attributes["data-item-id"].value;
|
||||||
|
const item = this.actor.items.get(itemId);
|
||||||
|
// Create drag data
|
||||||
|
const dragData = {
|
||||||
|
actorId: this.actor.id,
|
||||||
|
type: "Item",
|
||||||
|
data: item.data
|
||||||
|
};
|
||||||
|
|
||||||
|
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onDrop(event) {
|
async _onDrop(event) {
|
||||||
// Try to extract the dragData
|
// Try to extract the data
|
||||||
let dragData = RdDItemSheet.$extractDragData(event);
|
let data;
|
||||||
if (!dragData) return false;
|
try {
|
||||||
const allowed = Hooks.call("dropActorSheetData", this.actor, this, dragData);
|
data = JSON.parse(event.dataTransfer.getData('text/plain'));
|
||||||
if (allowed === false) return false;
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle different dragData types
|
const allowed = Hooks.call("dropActorSheetData", this.actor, this, data);
|
||||||
switch (dragData.type) {
|
if (allowed === false) return;
|
||||||
|
|
||||||
|
// Handle different data types
|
||||||
|
switch (data.type) {
|
||||||
case "Item":
|
case "Item":
|
||||||
return this._onDropItem(event, dragData);
|
return this._onDropItem(event, data);
|
||||||
case "Actor":
|
|
||||||
return this._onDropActor(event, dragData);
|
|
||||||
}
|
}
|
||||||
return super._onDrop(event);
|
return super._onDrop(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static $extractDragData(event) {
|
/* -------------------------------------------- */
|
||||||
try {
|
|
||||||
const eventData = event?.dataTransfer?.getData('text/plain');
|
|
||||||
if (eventData) {
|
|
||||||
return JSON.parse(eventData);
|
|
||||||
}
|
|
||||||
} catch (err) { }
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDropItem(event, dragData) {
|
async _onDropItem(event, dragData) {
|
||||||
|
if (this.actor) {
|
||||||
|
const dropParams = RdDSheetUtility.prepareItemDropParameters(this.object.id, this.actor.id, dragData, this.objetVersConteneur);
|
||||||
|
await this.actor.processDropItem(dropParams);
|
||||||
|
await this.render(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onDropActor(event, dragData) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
96
module/item-signedraconique-sheet.js
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { SYSTEM_RDD } from "./constants.js";
|
||||||
|
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
|
||||||
|
import { Misc } from "./misc.js";
|
||||||
|
import { TMRType, TMRUtility } from "./tmr-utility.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Item sheet pour signes draconiques
|
||||||
|
* @extends {ItemSheet}
|
||||||
|
*/
|
||||||
|
export class RdDSigneDraconiqueItemSheet extends ItemSheet {
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static get defaultOptions() {
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||||
|
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
|
||||||
|
width: 550,
|
||||||
|
height: 550
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
_getHeaderButtons() {
|
||||||
|
let buttons = super._getHeaderButtons();
|
||||||
|
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
|
||||||
|
return buttons;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
|
setPosition(options = {}) {
|
||||||
|
const position = super.setPosition(options);
|
||||||
|
const sheetHeader = this.element.find(".sheet-header");
|
||||||
|
const sheetBody = this.element.find(".sheet-body");
|
||||||
|
const bodyHeight = position.height - sheetHeader[0].clientHeight;
|
||||||
|
sheetBody.css("height", bodyHeight);
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
async getData() {
|
||||||
|
const formData = duplicate(this.object);
|
||||||
|
mergeObject(formData, {
|
||||||
|
title: formData.name,
|
||||||
|
isGM: game.user.isGM,
|
||||||
|
owner: this.document.isOwner,
|
||||||
|
isOwned: this.actor ? true : false,
|
||||||
|
actorId: this.actor?.id,
|
||||||
|
editable: this.isEditable,
|
||||||
|
cssClass: this.isEditable ? "editable" : "locked",
|
||||||
|
});
|
||||||
|
formData.tmrs = TMRUtility.listSelectedTMR(formData.data.typesTMR ?? []);
|
||||||
|
return formData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/** @override */
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
if (!this.options.editable) return;
|
||||||
|
|
||||||
|
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
||||||
|
html.find(".select-tmr").change((event) => this.onSelectTmr(event));
|
||||||
|
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
async setSigneAleatoire() {
|
||||||
|
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
|
||||||
|
this.object.update(newSigne);
|
||||||
|
}
|
||||||
|
|
||||||
|
async onSelectTmr(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const selectedTMR = $(".select-tmr").val();
|
||||||
|
this.object.update({ 'data.typesTMR': selectedTMR });
|
||||||
|
}
|
||||||
|
|
||||||
|
async onValeurXpSort(event) {
|
||||||
|
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
|
||||||
|
const xp = Number(event.currentTarget.value);
|
||||||
|
const oldValeur = this.object.system.valeur;
|
||||||
|
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
|
||||||
|
await this.object.update({ 'data.valeur': newValeur });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
get template() {
|
||||||
|
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get title() {
|
||||||
|
return `Signe draconique: ${this.object.name}`;
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import { RdDItem, defaultItemImg } from "../item.js";
|
import { defaultItemImg } from "./item.js";
|
||||||
import { Misc } from "../misc.js";
|
import { Misc } from "./misc.js";
|
||||||
import { RdDDice } from "../rdd-dice.js";
|
import { RdDDice } from "./rdd-dice.js";
|
||||||
import { RdDRollTables } from "../rdd-rolltables.js";
|
import { RdDRollTables } from "./rdd-rolltables.js";
|
||||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
import { TMRType, TMRUtility } from "./tmr-utility.js";
|
||||||
import { TMRType, TMRUtility } from "../tmr-utility.js";
|
|
||||||
|
|
||||||
const tableSignesIndicatifs = [
|
const tableSignesIndicatifs = [
|
||||||
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
|
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
|
||||||
@ -16,25 +15,16 @@ const tableSignesIndicatifs = [
|
|||||||
|
|
||||||
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
|
const DIFFICULTE_LECTURE_SIGNE_MANQUE = +11;
|
||||||
|
|
||||||
export class RdDItemSigneDraconique extends RdDItem {
|
export class RdDItemSigneDraconique {
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
// TODO
|
|
||||||
return RdDTimestamp.formulesDuree().find(it => it.code == "").calcul(debut, this.actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
static prepareSigneDraconiqueMeditation(meditation, rolled) {
|
static prepareSigneDraconiqueMeditation(meditation, rolled) {
|
||||||
|
meditation = meditation
|
||||||
return {
|
return {
|
||||||
name: "de la " + meditation.name,
|
name: "de la " + meditation.name,
|
||||||
type: "signedraconique",
|
type: "signedraconique",
|
||||||
img: meditation.img,
|
img: meditation.img,
|
||||||
system: {
|
data: {
|
||||||
typesTMR: [TMRUtility.typeTmrName(meditation.system.tmr)],
|
typesTMR: [TMRUtility.typeTmrName(meditation.data.tmr)],
|
||||||
difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE,
|
difficulte: rolled.isSuccess ? RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code) : DIFFICULTE_LECTURE_SIGNE_MANQUE,
|
||||||
ephemere: true,
|
ephemere: true,
|
||||||
duree: "1 round",
|
duree: "1 round",
|
||||||
@ -85,7 +75,7 @@ export class RdDItemSigneDraconique extends RdDItem {
|
|||||||
name: await RdDItemSigneDraconique.randomSigneDescription(),
|
name: await RdDItemSigneDraconique.randomSigneDescription(),
|
||||||
type: "signedraconique",
|
type: "signedraconique",
|
||||||
img: defaultItemImg.signedraconique,
|
img: defaultItemImg.signedraconique,
|
||||||
system: {
|
data: {
|
||||||
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
|
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
|
||||||
ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere,
|
ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere,
|
||||||
duree: "1 round",
|
duree: "1 round",
|
||||||
@ -107,6 +97,6 @@ export class RdDItemSigneDraconique extends RdDItem {
|
|||||||
|
|
||||||
static async randomSigneDescription() {
|
static async randomSigneDescription() {
|
||||||
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
|
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
/* -------------------------------------------- */
|
||||||
import { Misc } from "./misc.js";
|
import { Misc } from "./misc.js";
|
||||||
import { TMRUtility } from "./tmr-utility.js";
|
import { TMRUtility } from "./tmr-utility.js";
|
||||||
|
|
||||||
@ -6,16 +7,16 @@ export class RdDItemSort extends Item {
|
|||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static isDifficulteVariable(sort) {
|
static isDifficulteVariable(sort) {
|
||||||
return sort && (sort.system.difficulte.toLowerCase() == "variable");
|
return sort && (sort.data.difficulte.toLowerCase() == "variable");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static isCoutVariable(sort) {
|
static isCoutVariable(sort) {
|
||||||
return sort && (sort.system.ptreve.toLowerCase() == "variable" || sort.system.ptreve.indexOf("+") >= 0);
|
return sort && (sort.data.ptreve.toLowerCase() == "variable" || sort.data.ptreve.indexOf("+") >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static setCoutReveReel(sort) {
|
static setCoutReveReel(sort){
|
||||||
if (sort) {
|
if (sort) {
|
||||||
sort.system.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.system.ptreve;
|
sort.system.ptreve_reel = this.isCoutVariable(sort) ? 1 : sort.system.ptreve;
|
||||||
}
|
}
|
||||||
@ -24,91 +25,99 @@ export class RdDItemSort extends Item {
|
|||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getDifficulte(sort, variable) {
|
static getDifficulte(sort, variable) {
|
||||||
if (sort && !RdDItemSort.isDifficulteVariable(sort)) {
|
if (sort && !RdDItemSort.isDifficulteVariable(sort)) {
|
||||||
return Misc.toInt(sort.system.difficulte);
|
return Misc.toInt(sort.data.difficulte);
|
||||||
}
|
}
|
||||||
return variable;
|
return variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static buildBonusCaseList(bonuscase, newCase) {
|
static buildBonusCaseList( caseBonusString, newCase ) {
|
||||||
const list = RdDItemSort._bonuscaseStringToList(bonuscase)
|
if (caseBonusString == undefined) {
|
||||||
if (newCase) {
|
return [];
|
||||||
return list.concat({ case: "Nouvelle", bonus: 0 });
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
/**
|
/**
|
||||||
* Retourne une liste de bonus/case pour un item-sheet
|
* Retourne une liste de bonus/case pour un item-sheet
|
||||||
* @param {} item
|
* @param {} item
|
||||||
*/
|
*/
|
||||||
static getBonusCaseList(item, newCase = false) {
|
static getBonusCaseList( item, newCase = false ) {
|
||||||
// Gestion spéciale case bonus
|
// Gestion spéciale case bonus
|
||||||
if (item.type == 'sort') {
|
if ( item.type == 'sort') {
|
||||||
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
|
return this.buildBonusCaseList(item.data.bonuscase, newCase );
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
/** Met à jour les données de formulaire
|
/** Met à jour les données de formulaire
|
||||||
* si static des bonus de cases sont présents
|
* si static des bonus de cases sont présents
|
||||||
* */
|
* */
|
||||||
static buildBonuscaseFromArrays(bonuses, coords) {
|
static buildBonusCaseStringFromFormData( formData ) {
|
||||||
if (bonuses) {
|
if ( formData.bonusValue ) {
|
||||||
const list = [];
|
let list = [];
|
||||||
const caseCheck = {};
|
let caseCheck = {};
|
||||||
for (let i = 0; i < bonuses.length && i < coords.length; i++) {
|
for(let i=0; i<formData.bonusValue.length; i++) {
|
||||||
const coord = coords[i] == 'Fleuve' ? 'Fleuve' : (coords[i]?.toUpperCase() ?? 'A1');
|
let coord = formData.caseValue[i] || 'A1';
|
||||||
const bonus = bonuses[i] || 0;
|
coord = coord.toUpperCase();
|
||||||
if (TMRUtility.verifyTMRCoord(coord) && bonus > 0 && caseCheck[coord] == undefined) {
|
if ( TMRUtility.verifyTMRCoord( coord ) ) { // Sanity check
|
||||||
caseCheck[coord] = bonus;
|
let bonus = formData.bonusValue[i] || 0;
|
||||||
list.push({ case: coord, bonus: bonus });
|
if ( bonus > 0 && caseCheck[coord] == undefined ) {
|
||||||
|
caseCheck[coord] = bonus;
|
||||||
|
list.push( coord+":"+bonus );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
formData.bonusValue = undefined;
|
||||||
|
formData.caseValue = undefined;
|
||||||
|
formData['data.bonuscase'] = list.toString(); // Reset
|
||||||
}
|
}
|
||||||
return RdDItemSort._bonuscaseListToString(list);
|
return formData;
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static incrementBonusCase(actor, sort, coord) {
|
static incrementBonusCase( actor, sort, coord ) {
|
||||||
if (TMRUtility.getTMR(coord).type == "fleuve") {
|
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
|
||||||
coord = 'Fleuve';
|
//console.log("ITEMSORT", sort, bonusCaseList);
|
||||||
}
|
|
||||||
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(
|
let found = false;
|
||||||
list.filter(it => it.case != coord).concat(modified)
|
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
|
// Sauvegarde/update
|
||||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
|
let bonuscase = StringList.toString();
|
||||||
|
//console.log("Bonus cae :", bonuscase);
|
||||||
|
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'data.bonuscase': bonuscase }] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
/* -------------------------------------------- */
|
||||||
static getCaseBonus(sort, coord) {
|
static getCaseBonus( sort, coord) {
|
||||||
const isFleuve = TMRUtility.getTMR(coord).type == "fleuve";
|
let bonusCaseList = this.buildBonusCaseList(sort.data.bonuscase, false);
|
||||||
|
for( let bc of bonusCaseList) {
|
||||||
let bc = RdDItemSort.buildBonusCaseList(sort.system.bonuscase, false)
|
if (bc.case == coord) { // Case existante
|
||||||
.filter(it => it.case == coord || (isFleuve && it.case == 'Fleuve'))
|
return Number(bc.bonus);
|
||||||
.find(it => true)
|
}
|
||||||
return Number(bc?.bonus ?? 0);
|
}
|
||||||
}
|
return 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] };
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
4
module/item-tache.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export class RdDItemTache extends Item {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
938
module/item.js
@ -1,51 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
import { Misc } from "../misc.js";
|
|
||||||
import { ReglesOptionelles } from "../settings/regles-optionelles.js";
|
|
||||||
|
|
||||||
export class RdDItemArmure extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
deteriorerArmure(dmg) {
|
|
||||||
if (!ReglesOptionelles.isUsing('deteriorationArmure') || this.system.protection == '0') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let deterioration = (this.system.deterioration ?? 0) + dmg;
|
|
||||||
let protection = this.system.protection;
|
|
||||||
|
|
||||||
if (deterioration >= 10) {
|
|
||||||
deterioration -= 10;
|
|
||||||
protection = this.calculProtectionDeterioree();
|
|
||||||
ChatMessage.create({ content: `Votre armure ${this.name} s'est détériorée, elle protège maintenant de ${protection}` });
|
|
||||||
}
|
|
||||||
this.update({
|
|
||||||
system: {
|
|
||||||
deterioration: deterioration,
|
|
||||||
protection: protection
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
calculProtectionDeterioree() {
|
|
||||||
const protectionCourante = this.system.protection;
|
|
||||||
let res = /(\d+)?d(\d+)(\-\d+)?/.exec(protectionCourante);
|
|
||||||
if (res) {
|
|
||||||
let protection = Misc.toInt(res[2]);
|
|
||||||
let malus = Misc.toInt(res[3]) - 1;
|
|
||||||
if (protection + malus <= 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return `1d${protection}${malus}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (/\d+/.exec(protectionCourante)) {
|
|
||||||
return `1d${protectionCourante}`;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ui.notifications.warn(`La valeur d'armure de votre ${this.name} est incorrecte`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,199 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
import { Misc } from "../misc.js";
|
|
||||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
|
||||||
|
|
||||||
const BASE_TACHE_SOIN_BLESSURE = {
|
|
||||||
type: "tache",
|
|
||||||
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_chirurgie.webp',
|
|
||||||
system: { carac: "dexterite", competence: "Chirurgie", periodicite: "1 round", fatigue: 0, }
|
|
||||||
}
|
|
||||||
const TACHES_SOIN_BLESSURE = {
|
|
||||||
6: { name: 'Blessure critique', system: { difficulte: -6, points_de_tache: 6 } },
|
|
||||||
4: { name: 'Blessure grave', system: { difficulte: -4, points_de_tache: 4 } },
|
|
||||||
2: { name: 'Blessure légère', system: { difficulte: -2, points_de_tache: 2 } },
|
|
||||||
}
|
|
||||||
|
|
||||||
const definitionsBlessures = [
|
|
||||||
{ type: "contusion", gravite: 0, label: 'Contusion/éraflure', max: 100, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/eraflure.webp" },
|
|
||||||
{ type: "legere", gravite: 2, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
|
||||||
{ type: "grave", gravite: 4, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
|
||||||
{ type: "critique", gravite: 6, label: 'Critique', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
|
||||||
{ type: "mort", gravite: 8, label: 'Mort', max: 1, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/mort.webp" }
|
|
||||||
]
|
|
||||||
|
|
||||||
export class RdDItemBlessure extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
prepareDerivedData() {
|
|
||||||
super.prepareDerivedData();
|
|
||||||
this.system.label = this.getLabelGravite()
|
|
||||||
}
|
|
||||||
|
|
||||||
static prepareTacheSoin(gravite) {
|
|
||||||
const tache = TACHES_SOIN_BLESSURE[gravite]
|
|
||||||
if (!tache) {
|
|
||||||
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return mergeObject(duplicate(BASE_TACHE_SOIN_BLESSURE), tache)
|
|
||||||
}
|
|
||||||
static async createBlessure(actor, gravite, localisation = '', attacker) {
|
|
||||||
const definition = RdDItemBlessure.getDefinition(gravite)
|
|
||||||
const blessure = {
|
|
||||||
name: definition.label,
|
|
||||||
type: 'blessure',
|
|
||||||
img: definition.icon,
|
|
||||||
system: {
|
|
||||||
gravite: gravite,
|
|
||||||
difficulte: - gravite,
|
|
||||||
localisation: localisation,
|
|
||||||
origine: attacker?.name ?? ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
|
|
||||||
return blessures[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
static async createTacheSoinBlessure(actor, gravite) {
|
|
||||||
const tache = RdDItemBlessure.prepareTacheSoin(gravite)
|
|
||||||
if (tache) {
|
|
||||||
const taches = await actor.createEmbeddedDocuments('Item', [tache], { renderSheet: false });
|
|
||||||
return taches[0];
|
|
||||||
}
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateTacheSoinBlessure(tache) {
|
|
||||||
if (tache) {
|
|
||||||
await tache.update({
|
|
||||||
system: {
|
|
||||||
itemId: this.id,
|
|
||||||
difficulte: Math.min(this.system.difficulte, tache.system.difficulte),
|
|
||||||
points_de_tache_courant: Math.max(0, this.system.premierssoins.tache)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async setSoinsBlessure(systemUpdate = {}) {
|
|
||||||
systemUpdate = mergeObject(systemUpdate, this.system, { overwrite: false }),
|
|
||||||
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
|
|
||||||
await this.update({
|
|
||||||
img: this.getImgSoins(systemUpdate.gravite, systemUpdate.soinscomplets.done),
|
|
||||||
system: systemUpdate
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async recuperationBlessure({ actor, timestamp, message, isMaladeEmpoisonne, blessures }) {
|
|
||||||
if (this.parent != actor || actor == undefined) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (new RdDTimestamp(this.system.temporel.fin).compare(timestamp) > 0) {
|
|
||||||
// attente periode
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (this.system.gravite > 0) {
|
|
||||||
const update = { system: { premierssoins: { bonus: 0 }, soinscomplets: { bonus: 0 } } }
|
|
||||||
const gravite = this.system.gravite;
|
|
||||||
const graviteMoindre = gravite - 2;
|
|
||||||
const moindres = blessures.filter(it => it.system.gravite == graviteMoindre, 'blessures').length
|
|
||||||
const label = this.getLabelGravite();
|
|
||||||
|
|
||||||
let rolled = await actor.jetRecuperationConstitution(this.system.soinscomplets.bonus, message);
|
|
||||||
|
|
||||||
if (rolled.isETotal) {
|
|
||||||
message.content += ` -- une blessure ${label} s'infecte (temps de guérison augmenté de ${gravite} jours, perte de vie)`;
|
|
||||||
await actor.santeIncDec("vie", -1);
|
|
||||||
mergeObject(update, {
|
|
||||||
system: { fin: { indexDate: timestamp.addJours(gravite).indexDate } }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!isMaladeEmpoisonne && rolled.isSuccess && this.peutRetrograder(graviteMoindre, moindres)) {
|
|
||||||
message.content += ` -- une blessure ${label} cicatrise`;
|
|
||||||
mergeObject(update, {
|
|
||||||
system: { gravite: graviteMoindre, fin: { indexDate: timestamp.addJours(graviteMoindre).indexDate } }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
message.content += ` -- une blessure ${label} reste stable`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await this.update(update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
peutRetrograder(graviteMoindre, moindres) {
|
|
||||||
return moindres < RdDItemBlessure.getDefinition(graviteMoindre).max
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.nouveauJour().addJours(this.system.gravite);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
|
||||||
if (this.system.gravite <= 0) {
|
|
||||||
await super.onFinPeriode(oldTimestamp, newTimestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getImgSoins(gravite, soins) {
|
|
||||||
let img = 'blessure'
|
|
||||||
if (gravite > 6) {
|
|
||||||
img = 'mort'
|
|
||||||
}
|
|
||||||
if (gravite <= 0) {
|
|
||||||
img = 'eraflure'
|
|
||||||
}
|
|
||||||
return `systems/foundryvtt-reve-de-dragon/icons/sante/${soins ? 'blessure-soins' : img}.webp`
|
|
||||||
}
|
|
||||||
|
|
||||||
getLabelGravite() {
|
|
||||||
return RdDItemBlessure.getDefinition(this.system.gravite).label
|
|
||||||
}
|
|
||||||
|
|
||||||
static getDefinition(gravite) {
|
|
||||||
return definitionsBlessures.sort(Misc.ascending(it => it.gravite))
|
|
||||||
.find(it => it.gravite >= gravite);
|
|
||||||
}
|
|
||||||
static maxBlessures(gravite) {
|
|
||||||
return RdDItemBlessure.getDefinition(gravite).max
|
|
||||||
}
|
|
||||||
|
|
||||||
isContusion() {
|
|
||||||
return this.system.gravite <= 0
|
|
||||||
}
|
|
||||||
isLegere() {
|
|
||||||
return this.system.gravite > 0 && this.system.gravite <= 2
|
|
||||||
}
|
|
||||||
isGrave() {
|
|
||||||
return this.system.gravite > 2 && this.system.gravite <= 4
|
|
||||||
}
|
|
||||||
isCritique() {
|
|
||||||
return this.system.gravite > 4 && this.system.gravite <= 6
|
|
||||||
}
|
|
||||||
isMort() {
|
|
||||||
return this.system.gravite > 6
|
|
||||||
}
|
|
||||||
|
|
||||||
getProprietes() {
|
|
||||||
return [
|
|
||||||
RdDItem.propertyIfDefined('Causée par', this.system.origine, this.system.origine),
|
|
||||||
`<b>Heure et Date</b>: ${new RdDTimestamp(this.system.temporel.debut).formatDateHeure()}`,
|
|
||||||
RdDItem.propertyIfDefined('Blessé', this.parent?.name, this.parent),
|
|
||||||
`<b>Localisation</b>: ${this.system.localisation}`,
|
|
||||||
`<b>Gravité</b>: ${RdDItemBlessure.getDefinition(this.system.gravite).label}`,
|
|
||||||
`<b>Difficulté des soins</b>: ${this.system.difficulte}`,
|
|
||||||
(this.system.soinscomplets.done ?
|
|
||||||
`<b>Bonus soins complets</b>: ${this.system.soinscomplets.bonus}` :
|
|
||||||
(this.system.premierssoins.done ?
|
|
||||||
`<b>Bonus premiers soins</b>: ${this.system.premierssoins.bonus}` :
|
|
||||||
`<b>Points de tâche</b>: ${this.system.premierssoins.tache}`
|
|
||||||
)
|
|
||||||
),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
import { Misc } from "../misc.js";
|
|
||||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
|
||||||
|
|
||||||
export class RdDItemMaladie extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
|
||||||
await RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
|
|
||||||
}
|
|
||||||
|
|
||||||
static async notifierMaladiePoison(mal, oldTimestamp, newTimestamp) {
|
|
||||||
if (mal.actor) {
|
|
||||||
const souffrance = mal.system.identifie
|
|
||||||
? `de ${mal.name}`
|
|
||||||
: `d'un mal inconnu`
|
|
||||||
ChatMessage.create({ content: `${mal.actor.name} souffre ${souffrance} (${Misc.typeName('Item', mal.type)}): vérifiez que les effets ne se sont pas aggravés !` });
|
|
||||||
mal.postItemToChat('gmroll');
|
|
||||||
await RdDItemMaladie.prolongerPeriode(mal,oldTimestamp, newTimestamp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static async prolongerPeriode(mal, oldTimestamp, newTimestamp) {
|
|
||||||
if (mal.actor) {
|
|
||||||
// TODO: déterminer le nombre de périodes écoulées
|
|
||||||
console.log(`${mal.actor.name}: le mal ${mal.name} a atteint la fin de sa période et été prolongé`);
|
|
||||||
const current = newTimestamp;
|
|
||||||
const finPeriode = new RdDTimestamp(mal.system.temporel.fin)
|
|
||||||
const periodeSuivante = (finPeriode.compare(current) > 0 ? finPeriode : current);
|
|
||||||
const timestampFin = await mal.calculerFinPeriodeTemporel(periodeSuivante);
|
|
||||||
|
|
||||||
await mal.actor.updateEmbeddedDocuments('Item', [{
|
|
||||||
_id: mal.id,
|
|
||||||
'system.temporel.fin': duplicate(timestampFin),
|
|
||||||
}])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
|
|
||||||
export class RdDItemOmbre extends RdDItem {
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.appliquerDuree(this.system.duree, this.parent);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
import { RdDItemMaladie } from "./maladie.js";
|
|
||||||
|
|
||||||
export class RdDItemPoison extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.addPeriode(this.system.periode.nombre, this.system.periode.unite) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
async onFinPeriode(oldTimestamp, newTimestamp) {
|
|
||||||
RdDItemMaladie.notifierMaladiePoison(this, oldTimestamp, newTimestamp)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
|
|
||||||
export class RdDItemQueue extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.appliquerDuree(this.system.duree, this.parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
|
|
||||||
const RARETE_COMMUNE = { code: 'Commune', label: 'Commune', frequence: 54, min: 27, max: 108 };
|
|
||||||
const RARETE_FREQUENTE = { code: 'Frequente', label: 'Fréquente', frequence: 18, min: 9, max: 36 };
|
|
||||||
const RARETE_RARE = { code: 'Rare', label: 'Rare', frequence: 6, min: 3, max: 12 };
|
|
||||||
const RARETE_RARISSIME = { code: 'Rarissime', label: 'Rarissime', frequence: 2, min: 1, max: 4 };
|
|
||||||
const RARETE_INEXISTANT = { code: 'Inexistant', label: 'Inexistant', frequence: 0, min: 0, max: 0 };
|
|
||||||
const RARETE_EGALE = { code: 'eqal', label: 'Egal', frequence: 1, min: 1, max: 1 };
|
|
||||||
|
|
||||||
const RARETES = [
|
|
||||||
RARETE_COMMUNE,
|
|
||||||
RARETE_FREQUENTE,
|
|
||||||
RARETE_RARE,
|
|
||||||
RARETE_RARISSIME,
|
|
||||||
RARETE_INEXISTANT,
|
|
||||||
]
|
|
||||||
|
|
||||||
export class RdDRaretes {
|
|
||||||
|
|
||||||
static rareteFrequente() { return RARETE_FREQUENTE; }
|
|
||||||
static rareteEgale() { return RARETE_EGALE; }
|
|
||||||
static raretes() { return RARETES; }
|
|
||||||
|
|
||||||
static byCode(code = undefined) {
|
|
||||||
return RARETES.find(it => it.code == code) ?? RARETE_FREQUENTE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static getChamp(rarete, field = undefined) {
|
|
||||||
return RdDRaretes.byCode(rarete)[field ?? 'frequence'];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,80 +0,0 @@
|
|||||||
import { EffetsRencontre } from "../tmr/effets-rencontres.js";
|
|
||||||
import { RdDItem } from "../item.js";
|
|
||||||
|
|
||||||
const tableEffets = [
|
|
||||||
{ code: "messager", resultat: "succes", description: "Envoie un message à (force) cases", method: EffetsRencontre.messager },
|
|
||||||
{ code: "passeur", resultat: "succes", description: "Déplacer le demi-rêve à (force) cases", method: EffetsRencontre.passeur},
|
|
||||||
{ code: "reve+f", resultat: "succes", description: "Gain de (force) points de rêve" , method: EffetsRencontre.reve_plus_force},
|
|
||||||
{ code: "teleport", resultat: "succes", description: "Déplacer le demi-rêve (même type)", method: EffetsRencontre.teleportation_typecase },
|
|
||||||
{ code: "part+tete", resultat: "succes", description: "Tête de dragon sur réussite particulière", method: EffetsRencontre.rdd_part_tete },
|
|
||||||
{ code: "part+xp", resultat: "succes", description: "Expérience sur réussite particulière", method: EffetsRencontre.experience_particuliere },
|
|
||||||
{ code: "seuil", resultat: "succes", description: "Récupération de seuil de rêve", method: EffetsRencontre.regain_seuil },
|
|
||||||
|
|
||||||
{ code: "reve-1", resultat: "echec", description: "Perte de 1 point de rêve", method: EffetsRencontre.reve_moins_1 },
|
|
||||||
{ code: "reve-f", resultat: "echec", description: "Perte de (force) points de rêve", method: EffetsRencontre.reve_moins_force },
|
|
||||||
{ code: "vie-1", resultat: "echec", description: "Perte de 1 point de vie", method: EffetsRencontre.vie_moins_1 },
|
|
||||||
{ code: "reinsere", resultat: "echec", description: "Réinsertion aléatoire", method: EffetsRencontre.reinsertion },
|
|
||||||
{ code: "persistant", resultat: "echec", description: "Bloque le demi-rêve", method: EffetsRencontre.rencontre_persistante },
|
|
||||||
{ code: "teleport-aleatoire", resultat: "echec", description: "Déplacement aléatoire (même type)", method: EffetsRencontre.teleportation_aleatoire_typecase },
|
|
||||||
{ code: "aleatoire", resultat: "echec", description: "Déplacement aléatoire", method: EffetsRencontre.deplacement_aleatoire },
|
|
||||||
{ code: "sort-aleatoire", resultat: "echec", description: "Déclenche un sort en réserve aléatoire", method: EffetsRencontre.sort_aleatoire },
|
|
||||||
{ code: "rompu", resultat: "echec", description: "Demi-rêve interrompu", method: EffetsRencontre.demireve_rompu },
|
|
||||||
{ code: "echec-queue", resultat: "echec", description: "Queue(s) de dragon sur échec", method: EffetsRencontre.rdd_echec_queue },
|
|
||||||
|
|
||||||
{ code: "reve+1", resultat: "succes", description: "Gain de 1 point de rêve", method: EffetsRencontre.reve_plus_1 },
|
|
||||||
{ code: "vie-f", resultat: "echec", description: "Perte de (force) points de vie", method: EffetsRencontre.vie_moins_force },
|
|
||||||
{ code: "moral+1", resultat: "succes", description: "Gain de 1 point de moral", method: EffetsRencontre.moral_plus_1 },
|
|
||||||
{ code: "moral-1", resultat: "echec", description: "Perte de 1 point de moral", method: EffetsRencontre.moral_moins_1 },
|
|
||||||
{ code: "xpsort+f", resultat: "succes", description: "Gain de (force) xp sort", method: EffetsRencontre.xp_sort_force },
|
|
||||||
{ code: "endurance-1", resultat: "echec", description: "Perte de 1 point d'endurance", method: EffetsRencontre.end_moins_1 },
|
|
||||||
{ code: "endurance-f", resultat: "echec", description: "Perte de (force) points d'endurance", method: EffetsRencontre.end_moins_force },
|
|
||||||
{ code: "fatigue+1", resultat: "echec", description: "Coup de fatigue de 1 point", method: EffetsRencontre.fatigue_plus_1},
|
|
||||||
{ code: "fatigue+f", resultat: "echec", description: "Coup de fatigue de 1 (force) points", method: EffetsRencontre.fatigue_plus_force },
|
|
||||||
{ code: "fatigue-1", resultat: "succes", description: "Récupération de 1 point de fatigue", method: EffetsRencontre.fatigue_moins_1},
|
|
||||||
{ code: "fatigue-f", resultat: "succes", description: "Récupération de 1 (force) points de fatigue", method: EffetsRencontre.fatigue_moins_force },
|
|
||||||
{ code: "perte-chance", resultat: "echec", description: "Perte de chance actuelle", method: EffetsRencontre.perte_chance },
|
|
||||||
{ code: "stress+1", resultat: "succes", description: "Gain de 1 point de stress", method: EffetsRencontre.stress_plus_1 },
|
|
||||||
// { code: "epart-souffle", resultat: "echec", description: "Souffle de dragon sur échec particulier" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export class RdDRencontre extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
static getEffetsSucces() { return RdDRencontre.getEffets("succes"); }
|
|
||||||
static getEffetsEchec() { return RdDRencontre.getEffets("echec"); }
|
|
||||||
static getEffets(resultat) {
|
|
||||||
return tableEffets.filter(e => resultat == e.resultat);
|
|
||||||
}
|
|
||||||
|
|
||||||
static mapEffets(liste) {
|
|
||||||
return liste.map(it => RdDRencontre.getEffet(it));
|
|
||||||
}
|
|
||||||
|
|
||||||
static getListeEffets(item, reussite) {
|
|
||||||
if (reussite == 'echec') {
|
|
||||||
return [...item.system.echec.effets];
|
|
||||||
}
|
|
||||||
if (reussite == 'succes') {
|
|
||||||
return [...item.system.succes.effets];
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
static getEffet(code) {
|
|
||||||
return tableEffets.find(it => code == it.code)
|
|
||||||
}
|
|
||||||
|
|
||||||
static async appliquer(codes, tmrDialog, rencData) {
|
|
||||||
for(const effet of RdDRencontre.mapEffets(codes)){
|
|
||||||
await effet.method(tmrDialog, rencData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async calculerFinPeriodeTemporel(debut) {
|
|
||||||
return await debut.nouvelleHeure().addHeures(12);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
import { RdDItem } from "../item.js";
|
|
||||||
|
|
||||||
export class RdDItemService extends RdDItem {
|
|
||||||
|
|
||||||
static get defaultIcon() {
|
|
||||||
return "systems/foundryvtt-reve-de-dragon/icons/services/lit.webp";
|
|
||||||
}
|
|
||||||
|
|
||||||
isService() { return true; }
|
|
||||||
getProprietes() {
|
|
||||||
return [
|
|
||||||
RdDItem.propertyIfDefined('Qualité', this.system.qualite, this.system.qualite != 0),
|
|
||||||
RdDItem.propertyIfDefined('Moral', 'Situation heureuse', this.system.moral),
|
|
||||||
RdDItem.propertyIfDefined('Coût', `${this.calculerPrixCommercant()} sols`),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,120 +0,0 @@
|
|||||||
import { HtmlUtility } from "../html-utility.js";
|
|
||||||
import { RdDItemSheet } from "../item-sheet.js";
|
|
||||||
import { Misc } from "../misc.js";
|
|
||||||
import { RdDRaretes } from "./raretes.js";
|
|
||||||
|
|
||||||
const TYPE_ITEMS_NATURELS = ["faune", "herbe", "plante", "ingredient"];
|
|
||||||
|
|
||||||
export class RdDItemInventaireSheet extends RdDItemSheet {
|
|
||||||
|
|
||||||
static get defaultOptions() {
|
|
||||||
return mergeObject(RdDItemSheet.defaultOptions, {
|
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setPosition(options = {}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetHeader = this.element.find(".sheet-header");
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getData() {
|
|
||||||
const formData = await super.getData();
|
|
||||||
return mergeObject(formData, {
|
|
||||||
milieux: await game.system.rdd.environnement.autresMilieux(this.item)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
HtmlUtility.showControlWhen(this.html.find("div.description-milieu"), TYPE_ITEMS_NATURELS.includes(this.item.type));
|
|
||||||
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
this.html.find("a.preparer-nourriture").click(event => this.preparerNourriture(event));
|
|
||||||
this.html.find("a.manger-nourriture").click(event => this.mangerNourriture(event));
|
|
||||||
|
|
||||||
this.html.find("input.input-selection-milieu").keypress(event => {
|
|
||||||
if (event.keyCode == '13') {
|
|
||||||
this.onAddMilieu(event);
|
|
||||||
}
|
|
||||||
event.stopPropagation();
|
|
||||||
})
|
|
||||||
this.html.find("a.milieu-add").click(event => this.onAddMilieu(event));
|
|
||||||
this.html.find("div.environnement-milieu a.milieu-delete").click(event => this.onDeleteMilieu(event));
|
|
||||||
this.html.find("div.environnement-milieu select.environnement-rarete").change(event => this.onChange(event,
|
|
||||||
updated => this.$changeRarete(event, updated)));
|
|
||||||
this.html.find("div.environnement-milieu input[name='environnement-frequence']").change(event => this.onChange(event,
|
|
||||||
updated => this.$changeFrequence(event, updated)));
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async preparerNourriture(event) {
|
|
||||||
if (this.actor && this.item.getUtilisationCuisine() == 'brut') {
|
|
||||||
await this.actor.preparerNourriture(this.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async mangerNourriture(event) {
|
|
||||||
if (this.actor && this.item.getUtilisation() == 'cuisine') {
|
|
||||||
await this.actor.mangerNourriture(this.item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$changeFrequence(event, updated) {
|
|
||||||
updated.frequence = Number(this.html.find(event.currentTarget).val());
|
|
||||||
}
|
|
||||||
|
|
||||||
$changeRarete(event, updated) {
|
|
||||||
const code = this.html.find(event.currentTarget).val();
|
|
||||||
const rarete = RdDRaretes.byCode(code);
|
|
||||||
updated.rarete = rarete.code;
|
|
||||||
updated.frequence = rarete.frequence;
|
|
||||||
}
|
|
||||||
|
|
||||||
async onAddMilieu(event) {
|
|
||||||
const milieu = this.html.find('input.input-selection-milieu').val();
|
|
||||||
if (!milieu) {
|
|
||||||
ui.notifications.warn(`Choisissez le milieu dans lequel se trouve le/la ${this.item.name}`);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const list = this.item.getEnvironnements();
|
|
||||||
const exists = list.find(it => it.milieu == milieu);
|
|
||||||
if (exists) {
|
|
||||||
ui.notifications.warn(`${this.item.name} a déjà une rareté ${exists.rarete} en ${milieu} (fréquence: ${exists.frequence})`);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const rarete = RdDRaretes.rareteFrequente();
|
|
||||||
const added = { milieu, rarete: rarete.code, frequence: rarete.frequence };
|
|
||||||
const newList = [added, ...list].sort(Misc.ascending(it => it.milieu))
|
|
||||||
await this.item.update({ 'system.environnement': newList })
|
|
||||||
}
|
|
||||||
|
|
||||||
async onDeleteMilieu(event) {
|
|
||||||
const milieu = this.$getEventMilieu(event);
|
|
||||||
if (milieu != undefined) {
|
|
||||||
const newList = this.item.getEnvironnements().filter(it => it.milieu != milieu)
|
|
||||||
.sort(Misc.ascending(it => it.milieu));
|
|
||||||
await this.item.update({ 'system.environnement': newList });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async onChange(event, doMutation) {
|
|
||||||
const list = this.item.system.environnement;
|
|
||||||
const milieu = this.$getEventMilieu(event);
|
|
||||||
const updated = list.find(it => it.milieu == milieu);
|
|
||||||
if (updated) {
|
|
||||||
doMutation(updated);
|
|
||||||
const newList = [...list.filter(it => it.milieu != milieu), updated]
|
|
||||||
.sort(Misc.ascending(it => it.milieu));
|
|
||||||
await this.item.update({ 'system.environnement': newList });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$getEventMilieu(event) {
|
|
||||||
return this.html.find(event.currentTarget)?.parents("div.environnement-milieu").data("milieu");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import { RdDItemSheet } from "../item-sheet.js";
|
|
||||||
|
|
||||||
export class RdDBlessureItemSheet extends RdDItemSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "blessure" };
|
|
||||||
|
|
||||||
async getData() {
|
|
||||||
const formData = await super.getData();
|
|
||||||
formData.disabled = formData.options.isGM || formData.options.isOwned ? '' : 'disabled';
|
|
||||||
return formData;
|
|
||||||
}
|
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
|
|
||||||
this.html.find('[name="premierssoins-done"]').change(async event => {
|
|
||||||
await this.item.setSoinsBlessure({ premierssoins: { done: event.currentTarget.checked } });
|
|
||||||
});
|
|
||||||
this.html.find('[name="soinscomplets-done"]').change(async event => {
|
|
||||||
await this.item.setSoinsBlessure({ soinscomplets: { done: event.currentTarget.checked } })
|
|
||||||
});
|
|
||||||
this.html.find('[name="system-gravite"]').change(async event => {
|
|
||||||
const gravite = Number(event.currentTarget.value)
|
|
||||||
await this.item.setSoinsBlessure({ gravite: gravite, difficulte: - gravite })
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import { RdDBaseActorSheet } from "../actor/base-actor-sheet.js";
|
|
||||||
import { RdDSheetUtility } from "../rdd-sheet-utility.js";
|
|
||||||
import { RdDUtility } from "../rdd-utility.js";
|
|
||||||
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
|
|
||||||
|
|
||||||
export class RdDConteneurItemSheet extends RdDItemInventaireSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "conteneur" };
|
|
||||||
|
|
||||||
async getData() {
|
|
||||||
const formData = await super.getData();
|
|
||||||
if (this.actor) {
|
|
||||||
this.prepareConteneurData(formData);
|
|
||||||
}
|
|
||||||
return formData;
|
|
||||||
}
|
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
|
|
||||||
this.html.find('.conteneur-name a').click(async event => {
|
|
||||||
RdDUtility.toggleAfficheContenu(RdDSheetUtility.getItemId(event));
|
|
||||||
this.render(true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
prepareConteneurData(formData) {
|
|
||||||
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
|
||||||
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.inventaires);
|
|
||||||
formData.subItems = formData.conteneurs.find(it => it._id == this.item.id)?.subItems;
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDragStart(event) {
|
|
||||||
console.log("_onDragStart", event);
|
|
||||||
if (event.target.classList.contains("entity-link")) return;
|
|
||||||
|
|
||||||
const itemId = event.srcElement?.attributes["data-item-id"].value;
|
|
||||||
const item = this.actor.items.get(itemId);
|
|
||||||
// Create drag data
|
|
||||||
const dragData = {
|
|
||||||
actorId: this.actor.id,
|
|
||||||
type: "Item",
|
|
||||||
data: item.system,
|
|
||||||
uuid: item.uuid
|
|
||||||
};
|
|
||||||
|
|
||||||
event.dataTransfer.setData("text/plain", JSON.stringify(dragData));
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDropItem(event, dragData) {
|
|
||||||
if (this.actor) {
|
|
||||||
const destItemId = this.html.find(event.target)?.closest('.item').attr('data-item-id') ?? this.item.id
|
|
||||||
const dropParams = await RdDSheetUtility.prepareItemDropParameters(destItemId, this.actor, dragData, this.objetVersConteneur);
|
|
||||||
await this.actor.processDropItem(dropParams);
|
|
||||||
await this.render(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
|
|
||||||
|
|
||||||
export class RdDFauneItemSheet extends RdDItemInventaireSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "faune" };
|
|
||||||
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
|
|
||||||
html.find("a.linked-actor-delete").click(event => this.onDeleteLinkedActor());
|
|
||||||
}
|
|
||||||
|
|
||||||
async _onDropActor(event, dragData) {
|
|
||||||
console.log('faune:dropActor', event, dragData)
|
|
||||||
const linkedActor = fromUuidSync(dragData.uuid);
|
|
||||||
if (linkedActor?.pack) {
|
|
||||||
this.item.update({
|
|
||||||
'system.actor.pack': linkedActor.pack,
|
|
||||||
'system.actor.id': linkedActor._id,
|
|
||||||
'system.actor.name': linkedActor.name
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ui.notifications.warn(`${linkedActor.name} ne provient pas d'un compendium.
|
|
||||||
<br>Choisissez une créature du compendium pour représenter un élément de faune générique`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async onDeleteLinkedActor() {
|
|
||||||
this.item.update({
|
|
||||||
'system.actor.pack': '',
|
|
||||||
'system.actor.id': '',
|
|
||||||
'system.actor.name': ''
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
|
|
||||||
|
|
||||||
export class RdDHerbeItemSheet extends RdDItemInventaireSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "herbe" };
|
|
||||||
}
|
|
@ -1,5 +0,0 @@
|
|||||||
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
|
|
||||||
|
|
||||||
export class RdDIngredientItemSheet extends RdDItemInventaireSheet {
|
|
||||||
static get ITEM_TYPE() { return "ingredient" };
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
import { RdDItemInventaireSheet } from "./sheet-base-inventaire.js";
|
|
||||||
|
|
||||||
export class RdDPlanteItemSheet extends RdDItemInventaireSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "plante" };
|
|
||||||
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
import { RdDRencontre } from "./rencontre.js";
|
|
||||||
import { RdDItemSheet } from "../item-sheet.js";
|
|
||||||
|
|
||||||
export class RdDRencontreItemSheet extends RdDItemSheet {
|
|
||||||
|
|
||||||
static get ITEM_TYPE() { return "rencontre" };
|
|
||||||
|
|
||||||
static get defaultOptions() {
|
|
||||||
return mergeObject(super.defaultOptions, {
|
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
setPosition(options = {}) {
|
|
||||||
const position = super.setPosition(options);
|
|
||||||
const sheetHeader = this.element.find(".sheet-header");
|
|
||||||
const sheetBody = this.element.find(".sheet-body");
|
|
||||||
sheetBody.css("height", position.height - sheetHeader[0].clientHeight)
|
|
||||||
return position;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
async getData() {
|
|
||||||
const formData = await super.getData();
|
|
||||||
mergeObject(formData, {
|
|
||||||
effets: {
|
|
||||||
succes: {
|
|
||||||
liste: RdDRencontre.getEffetsSucces(),
|
|
||||||
select: RdDRencontre.mapEffets(this.item.system.succes.effets)
|
|
||||||
},
|
|
||||||
echec: {
|
|
||||||
liste: RdDRencontre.getEffetsEchec(),
|
|
||||||
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return formData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -------------------------------------------- */
|
|
||||||
/** @override */
|
|
||||||
activateListeners(html) {
|
|
||||||
super.activateListeners(html);
|
|
||||||
if (!this.options.editable) return;
|
|
||||||
this.html.find("a.effet-add").click(event => this.onAddEffet(event));
|
|
||||||
this.html.find("a.effet-delete").click(event => this.onDeleteEffet(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
async onAddEffet(event) {
|
|
||||||
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
|
|
||||||
const keyEffets = `system.${resultat}.effets`;
|
|
||||||
|
|
||||||
const code = this.html.find(event.currentTarget)?.data("effet-code");
|
|
||||||
const liste = RdDRencontre.getListeEffets(this.item, resultat);
|
|
||||||
liste.push(code);
|
|
||||||
|
|
||||||
await this._updateEffetsRencontre(keyEffets, liste);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onDeleteEffet(event) {
|
|
||||||
const resultat = this.html.find(event.currentTarget)?.data("effet-resultat");
|
|
||||||
const keyEffets = `system.${resultat}.effets`;
|
|
||||||
|
|
||||||
const pos = this.html.find(event.currentTarget)?.data("effet-pos");
|
|
||||||
const liste = RdDRencontre.getListeEffets(this.item, resultat);
|
|
||||||
liste.splice(pos, 1);
|
|
||||||
|
|
||||||
await this._updateEffetsRencontre(keyEffets, liste);
|
|
||||||
}
|
|
||||||
|
|
||||||
async _updateEffetsRencontre(key, liste) {
|
|
||||||
const updates = {};
|
|
||||||
updates[key] = liste;
|
|
||||||
this.item.update(updates);
|
|
||||||
}
|
|
||||||
}
|
|