Compare commits
184 Commits
foundryvtt
...
foundryvtt
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f8b5b104d | |||
| 9fe265165b | |||
| b92003ac1f | |||
| a1e4bfb529 | |||
| b4f0be5d64 | |||
| 5ff31d462f | |||
| be1d109def | |||
| d91bee0f42 | |||
| ed222c7b6d | |||
| 70198a5727 | |||
| bfe70c6634 | |||
| 09365eb744 | |||
| 894d4f3941 | |||
| 6e234411ca | |||
| 85acb5a255 | |||
| 6106e2a19e | |||
| f896f1da6e | |||
| 9bb45c2349 | |||
| 5cab219e0e | |||
| 2de9ea49c8 | |||
| 1760d26014 | |||
| 92185d4a5b | |||
| 210b129934 | |||
| b892068b38 | |||
| 3906cb0a7b | |||
| 5c58932a0d | |||
| 3b06bd382b | |||
| b4a725ff12 | |||
| 05df6a68cc | |||
| 025c3483a9 | |||
| 97138b25c7 | |||
| c0066f79c1 | |||
| 4db8bf95f9 | |||
| a7e1ca0b07 | |||
| e2c4d93413 | |||
| 3888efc6aa | |||
| 5004774a15 | |||
| 226afc1680 | |||
| 582df7e290 | |||
| 501f1f2e4f | |||
| 90d46c6a78 | |||
| 174ef4256a | |||
| be132a9ff1 | |||
| b2037a852c | |||
| 2137a6c403 | |||
| 99f5578c4f | |||
| a6ae7babbe | |||
| 814266e649 | |||
| 080d05d2cd | |||
| f8f889e9f9 | |||
| ad80802af6 | |||
| 0f7b9baf51 | |||
| b866c95ebd | |||
| 689e287ac7 | |||
| 40b0d7e6dc | |||
| d439d73636 | |||
| e91eea532d | |||
| f116003d6f | |||
| c3a44665c5 | |||
| 40b57517d8 | |||
| e04586ba44 | |||
| 611acd4d44 | |||
| 9b37533bdf | |||
| 50d923061b | |||
| e89a8ba232 | |||
| b8f236fa97 | |||
| 74b184aa32 | |||
| 9c17f85fa8 | |||
| 599fdc752d | |||
| fa890491e5 | |||
| 80435b6bca | |||
| 1a476bd5bc | |||
| 8d6c4565a9 | |||
| 6819f1c2f5 | |||
| 43607afc12 | |||
| 538cf5bdbf | |||
| 75507f3eca | |||
| a622814295 | |||
| 2aa8fcb980 | |||
| a65326d658 | |||
| b6a203b82a | |||
| 7e8f642d87 | |||
| 91be2761f5 | |||
| 2ac39e3428 | |||
| a162001ba4 | |||
| 52e1f9dfbf | |||
| c586a90690 | |||
| 16e40b0ed8 | |||
| 427a950954 | |||
| a7b20bdd35 | |||
| 3b18e0b919 | |||
| ff8a5d7ba3 | |||
| 3aa8c0f0af | |||
| 8d9f09c18c | |||
| 9d654246c2 | |||
| 111fac2b2d | |||
| 3e99265125 | |||
| 28878b74fc | |||
| ba8276ef37 | |||
| b9e8c24461 | |||
| 8754ea9f5f | |||
| f56ddb4a1b | |||
| e80dbc7332 | |||
| 4c82d85e6a | |||
| 538058ecc6 | |||
| 70e42ea631 | |||
| 15525ef8cc | |||
| 5a4ef6da7e | |||
| ab698b2124 | |||
| 4cc6e86d79 | |||
| 8f3d56a830 | |||
| 8561e3f8bc | |||
| f207cb7325 | |||
| b9e911a588 | |||
| 92e9be8b02 | |||
| 50a86e751d | |||
| 1725d4c17b | |||
| 3e33053ed4 | |||
| baa3729568 | |||
| 99f29cb95b | |||
| 7d19860f5f | |||
| 40987149cc | |||
| 49d7c4f71d | |||
| 23582984cf | |||
| 638459049d | |||
| 366ca981ca | |||
| c0e54c2369 | |||
| f95f5b2b81 | |||
| d30226cb33 | |||
| 5cf7dda76c | |||
| 9bc2593b8c | |||
| efd02b40a9 | |||
| feb3116c47 | |||
| 91a870ad91 | |||
| 2bbf606f30 | |||
| a385b98126 | |||
| 8775df5285 | |||
| a103239288 | |||
| 0b1c5d0a3d | |||
| e19577eab2 | |||
| c3b502ff6c | |||
| db2ca2453e | |||
| 915283a674 | |||
| 621bb4ebc3 | |||
| 26e805cf46 | |||
| 657566fb11 | |||
| 26e8853a94 | |||
| 4f69d3cf78 | |||
| dfe4b47452 | |||
| 80719d8c15 | |||
| 5c59f76c17 | |||
| 65525cfd79 | |||
| 042f5d0f69 | |||
| 19dd3b540c | |||
| 611b57c149 | |||
| fedf8f3b29 | |||
| d1ec67e485 | |||
| 7f7148e658 | |||
| bc35c8d80e | |||
| ad9e75c66d | |||
| e946299810 | |||
| fad894704d | |||
| 3365852210 | |||
| d71bf27311 | |||
| e6da18bebd | |||
| 972ae74e2c | |||
| 7969e74c8d | |||
| 84ea3a6ea9 | |||
| 7ada5577aa | |||
| b0e28ef937 | |||
| 6414f76d67 | |||
| dde3011f1d | |||
| 6dbf322efe | |||
| d34fde2ba4 | |||
| bc169d931b | |||
| 3b269b2baa | |||
| dffaa29fd1 | |||
| c49e2a850b | |||
| a5a9cc334e | |||
| 43e49a0eb8 | |||
| 5ab551da9e | |||
| 2a9e98f8c7 | |||
| 669982ec4a | |||
| 34183cd1a7 |
BIN
assets/scenes/9fmf9lcb3L9XO3bJ-thumb.png
Normal file
BIN
assets/scenes/9fmf9lcb3L9XO3bJ-thumb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
169
changelog.md
169
changelog.md
@@ -1,4 +1,173 @@
|
||||
# 12.0
|
||||
## 12.0.19 - La témérité d'Astrobazzarh
|
||||
- Fix
|
||||
- les défenses des créatures sont correctement filtrées
|
||||
- le lancer d'initiative pour tous les personnages/PNJs fonctionne correctement
|
||||
- les lieux et commerces n'ont pas d'initiative
|
||||
|
||||
## 12.0.18 - A la barbe d'Astrobazzarh
|
||||
- Améliorations sur la feuille de PNJ simplifiée
|
||||
- Ajout du portrait
|
||||
- Ajout du corps à corps
|
||||
- Affichage du niveau d'esquive
|
||||
- Un clic sur l'initiative permet de lancer l'initiative
|
||||
- les boutons +/- pour la vie, l'endurance et la fatigue changent si on est à la valeur normale
|
||||
- un clic sur l'endurance effectue un jet d'endurance
|
||||
- Fix
|
||||
- les achats des commerces sont de nouveau possibles
|
||||
- la commande /astro fonctionne de nouveau
|
||||
- le nombre d'utilisations d'items est réinitialisé à chaque round et fin de combat
|
||||
- la difficulté de parade pour les armes à distances n'est plus indiquée
|
||||
- les propositions d'armes de parade sont corrigées
|
||||
- Ajout d'un indicateur pour les armes de parade nécessitant une significative
|
||||
|
||||
## 12.0.16 - Le secret d'Astrobazzarh
|
||||
- Fix: les jets envoyés messages uniquement au MJ ne sont plus envoyés à tous les autres joueurs (et dupliqués)
|
||||
- Les noms affichés dans les automatisations de combat sont maintenant ceux des tokens plutôt que ceux des acteurs
|
||||
- Ajout d'une option pour la localisation des blessures
|
||||
|
||||
## 12.0.15 - Le messager d'Astrobazzarh
|
||||
- Correction des faces de dés personalisés dice-so-nice
|
||||
- Les messages de maladies ne sont plus publics
|
||||
- Les messages privés dans les TMR sont aussi envoyés au GM
|
||||
- Les informations de compétences pouvant augmenter s'affichent comme tooltips
|
||||
- Amélioration du rendu des tables de compendiums (commande /table)
|
||||
|
||||
## 12.0.14 - Les légions d'Astrobazzarh
|
||||
- Feuille de PNJ:
|
||||
- boutons standard (encaissement, ...)
|
||||
- boutons pour ajuster les compteurs
|
||||
- visualisation des blessures
|
||||
- click sur blessure pour ajouter/enlever
|
||||
- gestion des armes
|
||||
|
||||
## 12.0.13 - La Chance d'Astrobazzarh
|
||||
- Fix: jets de caractéristiques
|
||||
|
||||
## 12.0.12 - L'étalage d'Astrobazzarh
|
||||
- Fix: On peut de nouveau vendre des items sans propriétaire, depuis les compendiums ou depuis l'onglet des Objets
|
||||
- Début de Feuille PNJ au format des encarts Scriptarium
|
||||
- support des jets de caractéristiques
|
||||
- support des jets de compétences
|
||||
|
||||
## 12.0.11 - Le scriptorium d'Astrobazzarh
|
||||
- ajout d'un bouton pour générer les éléments de description d'un personnage
|
||||
- ajout du logo en background dans la liste des systèmes Foundry
|
||||
- ajout d'un champ pour le métier
|
||||
- export scriptarium
|
||||
- encodage de l'export en windows-1252
|
||||
- export de l'esquive avec armure et sans armure
|
||||
|
||||
## 12.0.10 - Le scriptorium d'Astrobazzarh
|
||||
- corrections de l'export scriptarium
|
||||
|
||||
## 12.0.9 - Le scriptorium d'Astrobazzarh
|
||||
- ajout d'une fonction avancée pour exporter les personnages dans un format csv
|
||||
|
||||
## 12.0.8 - La quincaillerie d'Astrobazzarh
|
||||
- le propriétaire est indiqué dans les feuilles d'équipements/compétences/...
|
||||
- Ecaille d'efficacité
|
||||
- l'écaille d'efficacité est prise en compte même si on n'utilise pas le ciblage en combat
|
||||
- l'écaille d'efficacité est prise en compte pour l'initiative
|
||||
- Corrections
|
||||
- l'état général est pris en compte pour les initiatives
|
||||
- le tooltip de l'initiative affiche correctement l'initiative
|
||||
|
||||
## 12.0.7 - La propriété d'Astrobazzarh
|
||||
- correction des opérations faites à la création d'un Item:
|
||||
- la durée des queues/rencontres/souffles
|
||||
- les effets draconiques d'un souffle/queue
|
||||
- mise à jour des points de tâche des blessures lors des soins
|
||||
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
|
||||
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
|
||||
d'une entité incarnée permet d'accorder le personnage
|
||||
- Les messages pour résister aux possessions/conjuration sont envoyées
|
||||
au défenseur
|
||||
- Les messages pour résister aux empoignades sont envoyées au défenseur
|
||||
- la commande /voyage affiche maintenant le total de fatigue pour chaque voyageur
|
||||
- la commande /voyage affiche maintenant les compétences liées au terrain
|
||||
|
||||
## 12.0.6 - Le bazar d'Astrobazzarh
|
||||
- Corrections de l'inventaire en bazar:
|
||||
- un problème pouvait survenir en déplaçant les objets
|
||||
l'inventaire, qui fait qu'un conteneur se retrouve récursivement dans son
|
||||
propre contenu, ce qui empêche d'ouvrir la feuille d'acteur.
|
||||
- un objet non-conteneur pouvait dans certains cas avoir un pseudo contenu
|
||||
- un objet pouvait être considéré comme contenu, sans être présent dans un
|
||||
conteneur (et donc non affiché)
|
||||
- vider les conteneurs supprime correctement toutes les informations liées
|
||||
aux conteneurs/contenus
|
||||
- Les messages pour les tirages dans le compendium utilisent le "roll mode"
|
||||
courant pour leur visibilité
|
||||
- Fix: restaurer la compatibilité Foundry 11
|
||||
|
||||
## 12.0.5 - Les mauvais jours d'Astrobazzarh
|
||||
- Fix: on peut de nouveau ouvrir l'édition de calendrier
|
||||
- Fix: on ne peut plus ouvrir plusieurs fenêtres de lancer de sort
|
||||
- Fix: Failed to execute 'getComputedStyle' on 'Window'
|
||||
|
||||
## 12.0.4 - La plaie d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- Fix: les boutons d'encaissement dans le tchat fonctionnent de nouveau
|
||||
- Fix warnings sur "Die" et AudioHelper
|
||||
|
||||
## 12.0.3 - L'hémorragie d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- On peut de nouveau ouvrir un acteur blessé après redémarrage du monde
|
||||
- On peut de nouveau ouvrir les Items avec une rareté par environnement
|
||||
- Le choix de ne plus afficher les demandes de suppression est bien pris en compte
|
||||
|
||||
## 12.0.2 - Les pluies d'Astrobazzarh
|
||||
- **Support V12**
|
||||
- correction des actions techniques déleguées au MJ qui bloquaient les fenêtre de lancer de dés des joueurs (et plein d'autres)
|
||||
- la fenêtre de calendrier s'ouvre correctement
|
||||
- les dés draconiques peuvent de nouveau faire plus que 0
|
||||
- adaptation de la fenêtre de recherche
|
||||
- correction des comparaisons de version pour les migrations automatiques
|
||||
- correction des roll.eveluate: l'option async est maintenant standard
|
||||
- correction des templates liés aux selections
|
||||
- correction de l'ajustement de luminosité de la scène selon l'heure
|
||||
- correction des images d'effets sur les tokens
|
||||
- correction de la vente par le tchat: seul le premier acheteur pouvait acheter
|
||||
- correction d'erreurs intempestives 'User ... lacks permission to update ...'
|
||||
|
||||
# 11.2
|
||||
## 11.2.21 - Le questionnement d'Akarlikarlikar
|
||||
- Une confirmation spécifique est demandée pour monter dans les terres médianes en cas de rencontre en attente
|
||||
- L'expérience en caractéristique sur les jets de chance et rêve actuels est mise dans la caractéristique correspondante
|
||||
- Les effets s'appliquent correctement sur les créatures
|
||||
- La date et l'heure (draconiques) sont affichées dans les messages du tchat
|
||||
|
||||
## 11.2.20 - Le soulagement d'Akarlikarlikar
|
||||
- L'option "ajout de la difficulté d'attaque à l'encaissement" est affichée comme un modificateur d'encaissement
|
||||
- Les options d'encaissement alternatives fonctionnent avec la validation de l'encaissement par le gardien
|
||||
- La fenêtre d'astrologie du gardien affiche toutes les heures lues par un personnage
|
||||
- Si aucune expérience n'est gagnée, les autres effets à appliquer (comme la récupération de seuil après avoir vaincu un rêve de Dragon) s'appliquent normalement
|
||||
- Les tooltips de Foundry sont lisibles
|
||||
- On n'accorde plus les entités de cauchemar deux fois quand le gardien valide les encaissements
|
||||
- Les messages de récupération de rêve en cas de Rêve de Dragon sont clarifiés
|
||||
|
||||
## 11.2.19 - Les hémorroïdes d'Akarlikarlikar
|
||||
- La validation des jets d'encaissement par le Gardien fonctionne de nouveau
|
||||
|
||||
## 11.2.18 - Le bourrichon d'Akarlikarlikar
|
||||
- Les différentes listes de la feuille de personnage ont maintenant le bouton pour envoyer dans le tchat
|
||||
|
||||
## 11.2.17 - Le cache-oeil d'Akarlikarlikar
|
||||
- Le titre des fenêtre d'objet affiche de nouveau le type traduit
|
||||
- Les tooltips des boutons edit/delete sont maintenant en Français
|
||||
- La case à cocher "Cacher les points de tâches" fonctionne de nouveau
|
||||
- Les personnages non-liés ne sont plus dans les liste de personnages joueurs pour le repos, le stress, la fatigue
|
||||
- L'utilisation de Thanatos est visible dans l'onglet Haut-Rêve pour indiquer que la prochaine queue est une ombre
|
||||
- La fenêtre des TMRs ne devrait plus afficher une zone noire au lieu de la carte.
|
||||
|
||||
## 11.2.16 - Le Tri d'Akarlikarlikar
|
||||
- Tri alphabétique des items dans la fenêtre de création
|
||||
- Mise à jour comptage de monde
|
||||
|
||||
## 11.2.15 - La Table d'Akarlikarlikar
|
||||
- Tirage automatique de la foce d'une rencontre (via la commande /tmrr)
|
||||
- Ajout de boutons pour ajouter des blessures "complètes" (ie avec perte d'endurance/vie)
|
||||
|
||||
## 11.2.14 - Les petits pas d'Akarlikarlikar
|
||||
- Correction sur la gestion de la surprise
|
||||
|
||||
4
icons/heures/.directory
Normal file
4
icons/heures/.directory
Normal file
@@ -0,0 +1,4 @@
|
||||
[Dolphin]
|
||||
Timestamp=2024,5,29,20,57,41.954
|
||||
Version=4
|
||||
VisibleRoles=Details_text,Details_size,Details_modificationtime,Details_creationtime,CustomizedDetails
|
||||
95
lang/fr.json
95
lang/fr.json
@@ -1,55 +1,56 @@
|
||||
{
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"Personnage": "Personnage",
|
||||
"Creature": "Créature",
|
||||
"Entite": "Entité de cauchemar",
|
||||
"Commerce": "Commerce",
|
||||
"Vehicule": "Véhicule"
|
||||
"personnage": "Personnage",
|
||||
"creature": "Créature",
|
||||
"entite": "Entité de cauchemar",
|
||||
"commerce": "Commerce",
|
||||
"vehicule": "Véhicule"
|
||||
},
|
||||
"Item": {
|
||||
"Arme": "Arme",
|
||||
"Armure": "Armure",
|
||||
"Blessure": "Blessure",
|
||||
"Casetmr": "TMR spéciale",
|
||||
"Chant": "Chant",
|
||||
"Competence": "Compétence",
|
||||
"Competencecreature": "Compétence de créature",
|
||||
"Conteneur": "Conteneur",
|
||||
"Danse": "Danse",
|
||||
"Extraitpoetique": "Extrait poetique",
|
||||
"Faune": "Faune",
|
||||
"Gemme": "Gemme",
|
||||
"Herbe": "Herbe",
|
||||
"Ingredient": "Ingrédient",
|
||||
"Jeu": "Jeu",
|
||||
"Livre": "Livre",
|
||||
"Maladie": "Maladie",
|
||||
"Meditation": "Méditation",
|
||||
"Monnaie": "Monnaie",
|
||||
"Munition": "Munition",
|
||||
"Musique": "Musique",
|
||||
"Nombreastral": "Nombre astral",
|
||||
"Nourritureboisson": "Nourriture & boisson",
|
||||
"Objet": "Objet",
|
||||
"Oeuvre": "Oeuvre",
|
||||
"Ombre": "Ombre de Thanatos",
|
||||
"Plante": "Plante",
|
||||
"Poison": "Poison",
|
||||
"Possession": "Possession",
|
||||
"Potion": "Potion",
|
||||
"Queue": "Queue de Dragon",
|
||||
"Recettealchimique": "Recette alchimique",
|
||||
"Recettecuisine": "Recette de cuisine",
|
||||
"Rencontre": "Rencontre TMR",
|
||||
"Service": "Service",
|
||||
"Signedraconique": "Signe draconique",
|
||||
"Sort": "Sort",
|
||||
"Sortreserve": "Sort en réserve",
|
||||
"Souffle": "Souffle de Dragon",
|
||||
"Tache": "Tâche",
|
||||
"Tarot": "Carte de tarot",
|
||||
"Tete": "Tête de Dragon"
|
||||
"arme": "Arme",
|
||||
"armure": "Armure",
|
||||
"blessure": "Blessure",
|
||||
"casetmr": "Case TMR spéciale",
|
||||
"chant": "Chant",
|
||||
"competence": "Compétence",
|
||||
"competencecreature": "Compétence de créature",
|
||||
"conteneur": "Conteneur",
|
||||
"danse": "Danse",
|
||||
"empoignade": "Empoignade",
|
||||
"extraitpoetique": "Extrait poetique",
|
||||
"faune": "Faune",
|
||||
"gemme": "Gemme",
|
||||
"herbe": "Herbe",
|
||||
"ingredient": "Ingrédient",
|
||||
"jeu": "Jeu",
|
||||
"livre": "Livre",
|
||||
"maladie": "Maladie",
|
||||
"meditation": "Méditation",
|
||||
"monnaie": "Monnaie",
|
||||
"munition": "Munition",
|
||||
"musique": "Musique",
|
||||
"nombreastral": "Nombre astral",
|
||||
"nourritureboisson": "Nourriture & boisson",
|
||||
"objet": "Objet",
|
||||
"oeuvre": "Oeuvre",
|
||||
"ombre": "Ombre de Thanatos",
|
||||
"plante": "Plante",
|
||||
"poison": "Poison",
|
||||
"possession": "Possession",
|
||||
"potion": "Potion",
|
||||
"queue": "Queue de Dragon",
|
||||
"recettealchimique": "Recette alchimique",
|
||||
"recettecuisine": "Recette de cuisine",
|
||||
"rencontre": "Rencontre TMR",
|
||||
"service": "Service",
|
||||
"signedraconique": "Signe draconique",
|
||||
"sort": "Sort",
|
||||
"sortreserve": "Sort en réserve",
|
||||
"souffle": "Souffle de Dragon",
|
||||
"tache": "Tâche",
|
||||
"tarot": "Carte de tarot",
|
||||
"tete": "Tête de Dragon"
|
||||
}
|
||||
},
|
||||
"EFFECT": {
|
||||
|
||||
65
module/achat-vente/chat-vente.js
Normal file
65
module/achat-vente/chat-vente.js
Normal file
@@ -0,0 +1,65 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
|
||||
const DETAIL_VENTE = 'detailVente';
|
||||
const NB_LOTS = 'nbLotss';
|
||||
|
||||
export class ChatVente {
|
||||
|
||||
static getDetailVente(chatMessageId) {
|
||||
const chatMessage = game.messages.get(chatMessageId)
|
||||
if (!chatMessage) {
|
||||
return undefined;
|
||||
}
|
||||
const nbLots = chatMessage.getFlag(SYSTEM_RDD, NB_LOTS)
|
||||
const detail = foundry.utils.duplicate(chatMessage.getFlag(SYSTEM_RDD, DETAIL_VENTE))
|
||||
if (!detail.item) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const vendeur = detail.vendeurId ? game.actors.get(detail.vendeurId) : undefined;
|
||||
return foundry.utils.mergeObject(detail,
|
||||
{
|
||||
alias: vendeur?.name ?? game.user.name,
|
||||
vendeur,
|
||||
nbLots: nbLots,
|
||||
chatMessageIdVente: chatMessageId
|
||||
})
|
||||
}
|
||||
|
||||
static getDetailAchatVente(chatMessageId) {
|
||||
const acheteur = RdDUtility.getSelectedActor()
|
||||
const detail = ChatVente.getDetailVente(chatMessageId)
|
||||
if (!acheteur && !detail.vendeur) {
|
||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||
return undefined;
|
||||
}
|
||||
return foundry.utils.mergeObject(detail, { acheteur })
|
||||
}
|
||||
|
||||
static async diminuerQuantiteAchatVente(chatMessageId, quantite) {
|
||||
const chatMessage = game.messages.get(chatMessageId)
|
||||
const vente = ChatVente.getDetailVente(chatMessageId)
|
||||
vente.nbLots = Math.max(0, vente.nbLots - quantite)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
chatMessage.update({ content: html });
|
||||
chatMessage.render(true);
|
||||
}
|
||||
|
||||
static async displayAchatVente(vente) {
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
const chatMessage = await ChatMessage.create(RdDUtility.chatDataSetup(html))
|
||||
await chatMessage.setFlag(SYSTEM_RDD, NB_LOTS, vente.nbLots)
|
||||
await chatMessage.setFlag(SYSTEM_RDD, DETAIL_VENTE, {
|
||||
item: vente.item,
|
||||
properties: vente.item.getProprietes(),
|
||||
vendeurId: vente.vendeurId,
|
||||
tailleLot: vente.tailleLot,
|
||||
quantiteIllimite: vente.quantiteIllimite,
|
||||
prixLot: vente.prixLot
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,13 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ChatVente } from "./chat-vente.js";
|
||||
|
||||
export class DialogItemAchat extends Dialog {
|
||||
|
||||
static preparerAchat(chatButton) {
|
||||
const vendeurId = chatButton.attributes['data-vendeurId']?.value;
|
||||
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
|
||||
const acheteur = RdDUtility.getSelectedActor();
|
||||
const json = chatButton.attributes['data-jsondata']?.value;
|
||||
if (!acheteur && !vendeur) {
|
||||
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
|
||||
return undefined;
|
||||
}
|
||||
if (!json) {
|
||||
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
item: JSON.parse(json),
|
||||
vendeur,
|
||||
acheteur,
|
||||
nbLots: parseInt(chatButton.attributes['data-quantiteNbLots']?.value),
|
||||
tailleLot: parseInt(chatButton.attributes['data-tailleLot']?.value ?? 1),
|
||||
prixLot: Number(chatButton.attributes['data-prixLot']?.value ?? 0),
|
||||
quantiteIllimite: chatButton.attributes['data-quantiteIllimite']?.value == 'true',
|
||||
chatMessageIdVente: RdDUtility.findChatMessageId(chatButton),
|
||||
};
|
||||
return ChatVente.getDetailAchatVente(RdDUtility.findChatMessageId(chatButton))
|
||||
}
|
||||
|
||||
|
||||
static async onAcheter({ item, vendeur, acheteur, tailleLot, prixLot, nbLots, quantiteIllimite, chatMessageIdVente }) {
|
||||
const venteData = {
|
||||
item,
|
||||
@@ -38,17 +16,21 @@ export class DialogItemAchat extends Dialog {
|
||||
acheteur,
|
||||
tailleLot,
|
||||
quantiteIllimite,
|
||||
quantiteNbLots: nbLots,
|
||||
nbLots,
|
||||
choix: { seForcer: false, supprimerSiZero: true },
|
||||
prixLot,
|
||||
isVente: prixLot > 0,
|
||||
isConsommable: item.type == 'nourritureboisson' && acheteur?.isPersonnage(),
|
||||
chatMessageIdVente
|
||||
};
|
||||
}
|
||||
if (venteData.vendeur?.id == venteData.acheteur?.id) {
|
||||
ui.notifications.info("Inutile de se vendre à soi-même")
|
||||
return
|
||||
}
|
||||
|
||||
DialogItemAchat.changeNombreLots(venteData, 1);
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
|
||||
new DialogItemAchat(html, venteData).render(true);
|
||||
DialogItemAchat.changeNombreLots(venteData, 1)
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData)
|
||||
new DialogItemAchat(html, venteData).render(true)
|
||||
}
|
||||
|
||||
static changeNombreLots(venteData, nombreLots) {
|
||||
@@ -116,18 +98,18 @@ export class DialogItemAchat extends Dialog {
|
||||
this.venteData.choix.seForcer = event.currentTarget.checked;
|
||||
}
|
||||
|
||||
setNombreLots(nombreLots) {
|
||||
setNombreLots(nbLots) {
|
||||
|
||||
if (!this.venteData.quantiteIllimite) {
|
||||
if (!this.venteData.quantiteIllimite && nombreLots > this.venteData.quantiteNbLots) {
|
||||
ui.notifications.warn(`Seulement ${this.venteData.quantiteNbLots} lots disponibles, vous ne pouvez pas en prendre ${nombreLots}`)
|
||||
if (!this.venteData.quantiteIllimite && nbLots > this.venteData.nbLots) {
|
||||
ui.notifications.warn(`Seulement ${this.venteData.nbLots} lots disponibles, vous ne pouvez pas en prendre ${nbLots}`)
|
||||
}
|
||||
nombreLots = Math.min(nombreLots, this.venteData.quantiteNbLots);
|
||||
nbLots = Math.min(nbLots, this.venteData.nbLots);
|
||||
}
|
||||
|
||||
DialogItemAchat.changeNombreLots(this.venteData, nombreLots);
|
||||
DialogItemAchat.changeNombreLots(this.venteData, nbLots);
|
||||
|
||||
this.html.find(".nombreLots").val(nombreLots);
|
||||
this.html.find(".nombreLots").val(nbLots);
|
||||
this.html.find(".prixTotal").text(this.venteData.prixTotal);
|
||||
this.html.find("span.total-sust").text(this.venteData.totalSust);
|
||||
this.html.find("span.total-desaltere").text(this.venteData.totalDesaltere);
|
||||
@@ -1,10 +1,11 @@
|
||||
import { HtmlUtility } from "./html-utility.js";
|
||||
import { HtmlUtility } from "../html-utility.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { ChatVente } from "./chat-vente.js";
|
||||
|
||||
export class DialogItemVente extends Dialog {
|
||||
|
||||
static async display({ item, callback, quantiteMax = undefined }) {
|
||||
static async display({ item, quantiteMax = undefined }) {
|
||||
const quantite = quantiteMax ?? item.getQuantite() ?? 1;
|
||||
const isOwned = item.parent;
|
||||
const venteData = {
|
||||
item: item,
|
||||
alias: item.actor?.name ?? game.user.name,
|
||||
@@ -13,17 +14,17 @@ export class DialogItemVente extends Dialog {
|
||||
prixUnitaire: item.calculerPrixCommercant(),
|
||||
prixLot: item.calculerPrixCommercant(),
|
||||
tailleLot: 1,
|
||||
quantiteNbLots: quantite,
|
||||
quantiteMaxLots: quantite,
|
||||
nbLots: quantite,
|
||||
maxLots: quantite,
|
||||
quantiteMax: quantite,
|
||||
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !isOwned,
|
||||
isOwned: isOwned,
|
||||
};
|
||||
quantiteIllimite: item.isItemCommerce() ? quantiteMax == undefined : !item.parent,
|
||||
isOwned: item.parent,
|
||||
}
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
|
||||
return new DialogItemVente(venteData, html, callback).render(true);
|
||||
return new DialogItemVente(venteData, html).render(true);
|
||||
}
|
||||
|
||||
constructor(venteData, html, callback) {
|
||||
constructor(venteData, html) {
|
||||
let options = { classes: ["dialogvente"], width: 400, height: 'fit-content', 'z-index': 99999 };
|
||||
|
||||
let conf = {
|
||||
@@ -34,7 +35,6 @@ export class DialogItemVente extends Dialog {
|
||||
};
|
||||
|
||||
super(conf, options);
|
||||
this.callback = callback;
|
||||
this.venteData = venteData;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class DialogItemVente extends Dialog {
|
||||
|
||||
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(".nbLots").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)));
|
||||
|
||||
@@ -52,16 +52,24 @@ export class DialogItemVente extends Dialog {
|
||||
|
||||
async onProposer(it) {
|
||||
this.updateVente(this.getChoixVente());
|
||||
this.callback(this.venteData);
|
||||
|
||||
this.venteData["properties"] = this.venteData.item.getProprietes();
|
||||
if (this.venteData.isOwned) {
|
||||
if (this.venteData.nbLots * this.venteData.tailleLot > this.venteData.quantiteMax) {
|
||||
ui.notifications.warn(`Vous avez ${this.venteData.quantiteMax} ${this.venteData.item.name}, ce n'est pas suffisant pour vendre ${this.venteData.nbLots} de ${this.venteData.tailleLot}`)
|
||||
return;
|
||||
}
|
||||
}
|
||||
await ChatVente.displayAchatVente(this.venteData)
|
||||
}
|
||||
|
||||
updateVente(update) {
|
||||
mergeObject(this.venteData, update);
|
||||
foundry.utils.mergeObject(this.venteData, update);
|
||||
}
|
||||
|
||||
getChoixVente() {
|
||||
return {
|
||||
quantiteNbLots: Number(this.html.find(".quantiteNbLots").val()),
|
||||
nbLots: Number(this.html.find(".nbLots").val()),
|
||||
tailleLot: Number(this.html.find(".tailleLot").val()),
|
||||
quantiteIllimite: this.html.find(".quantiteIllimite").is(':checked'),
|
||||
prixLot: Number(this.html.find(".prixLot").val())
|
||||
@@ -77,26 +85,26 @@ export class DialogItemVente extends Dialog {
|
||||
const maxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
|
||||
this.updateVente({
|
||||
tailleLot,
|
||||
quantiteNbLots: Math.min(maxLots, this.venteData.quantiteNbLots),
|
||||
quantiteMaxLots: maxLots,
|
||||
nbLots: Math.min(maxLots, this.venteData.nbLots),
|
||||
maxLots: maxLots,
|
||||
prixLot: (tailleLot * this.venteData.prixOrigine).toFixed(2)
|
||||
});
|
||||
|
||||
this.html.find(".prixLot").val(this.venteData.prixLot);
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
this.html.find(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
|
||||
this.html.find(".nbLots").val(this.venteData.nbLots);
|
||||
this.html.find(".nbLots").attr("max", this.venteData.maxLots)
|
||||
}
|
||||
|
||||
setNbLots(nbLots) {
|
||||
this.updateVente({
|
||||
quantiteNbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots)) : nbLots
|
||||
nbLots: this.venteData.isOwned ? Math.max(0, Math.min(nbLots, this.venteData.maxLots)) : nbLots
|
||||
})
|
||||
this.html.find(".quantiteNbLots").val(this.venteData.quantiteNbLots);
|
||||
this.html.find(".nbLots").val(this.venteData.nbLots);
|
||||
}
|
||||
|
||||
setQuantiteIllimite(checked) {
|
||||
this.updateVente({ quantiteIllimite: checked })
|
||||
this.html.find(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
|
||||
HtmlUtility.showControlWhen(this.html.find(".quantiteNbLots"), !this.venteData.quantiteIllimite)
|
||||
HtmlUtility.showControlWhen(this.html.find(".nbLots"), !this.venteData.quantiteIllimite)
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ import { RdDItem } from "./item.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { RdDBaseActorSangSheet } from "./actor/base-actor-sang-sheet.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/**
|
||||
@@ -28,28 +28,26 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-sheet.html",
|
||||
width: 550,
|
||||
showCompNiveauBase: false,
|
||||
vueArchetype: false,
|
||||
});
|
||||
}, { inplace: false });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
mergeObject(formData,
|
||||
{
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
effects: this.actor.effects.map(e => foundry.utils.deepClone(e)),
|
||||
limited: this.actor.limited,
|
||||
owner: this.actor.isOwner,
|
||||
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
|
||||
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
|
||||
});
|
||||
mergeObject(formData.calc, {
|
||||
foundry.utils.mergeObject(formData, {
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
limited: this.actor.limited,
|
||||
owner: this.actor.isOwner,
|
||||
biographie: await TextEditor.enrichHTML(this.actor.system.biographie, { async: true }),
|
||||
notes: await TextEditor.enrichHTML(this.actor.system.notes, { async: true }),
|
||||
});
|
||||
foundry.utils.mergeObject(formData.calc, {
|
||||
surenc: this.actor.computeMalusSurEncombrement(),
|
||||
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
|
||||
resumeBlessures: this.actor.computeResumeBlessure(this.actor.system.blessures),
|
||||
@@ -80,7 +78,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
|
||||
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
|
||||
const actor = this.actor;
|
||||
formData.combat = duplicate(formData.armes);
|
||||
formData.combat = foundry.utils.duplicate(formData.armes);
|
||||
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
|
||||
formData.combat.push(RdDItemArme.mainsNues(actor));
|
||||
formData.combat.push(RdDItemArme.empoignade(actor));
|
||||
@@ -130,7 +128,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
this.render(true);
|
||||
});
|
||||
|
||||
this.html.find('.visu-tmr').click(async event => this.actor.displayTMR("visu"))
|
||||
this.html.find('.button-tmr-visu').click(async event => this.actor.displayTMR("visu"))
|
||||
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
@@ -188,7 +186,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
this.html.find('.item-equip').click(async event => this.actor.equiperObjet(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.chance-actuelle').click(async event => this.actor.rollCarac('chance-actuelle'))
|
||||
|
||||
this.html.find('.chance-appel').click(async event => this.actor.rollAppelChance())
|
||||
this.html.find('.button-appel-chance').click(async event => this.actor.rollAppelChance())
|
||||
|
||||
this.html.find('[name="jet-astrologie"]').click(async event => this.actor.astrologieNombresAstraux())
|
||||
this.html.find('.tache-label a').click(async event => this.actor.rollTache(RdDSheetUtility.getItemId(event)))
|
||||
@@ -201,6 +199,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
this.html.find('.jeu-label a').click(async event => this.actor.rollJeu(RdDSheetUtility.getItemId(event)))
|
||||
this.html.find('.recettecuisine-label a').click(async event => this.actor.rollRecetteCuisine(RdDSheetUtility.getItemId(event)))
|
||||
|
||||
this.html.find('.description-aleatoire').click(async event => new AppPersonnageAleatoire(this.actor).render(true))
|
||||
if (game.user.isGM) {
|
||||
// experience log
|
||||
this.html.find('.experiencelog-delete').click(async event => {
|
||||
@@ -213,32 +212,32 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
const key = Number(li.data("key") ?? -1);
|
||||
await this.actor.deleteExperienceLog(0, key + 1);
|
||||
});
|
||||
// Boutons spéciaux MJs
|
||||
// Boutons spéciaux MJs
|
||||
this.html.find('.forcer-tmr-aleatoire').click(async event => this.actor.reinsertionAleatoire("Action MJ"))
|
||||
this.html.find('.afficher-tmr').click(async event => this.actor.changeTMRVisible())
|
||||
}
|
||||
|
||||
// Points de reve actuel
|
||||
this.html.find('.ptreve-actuel a').click(async event => this.actor.rollCarac('reve-actuel', true))
|
||||
this.html.find('.roll-reve-actuel').click(async event => this.actor.rollCarac('reve-actuel', true))
|
||||
this.html.find('.empoignade-label a').click(async event => RdDEmpoignade.onAttaqueEmpoignadeFromItem(RdDSheetUtility.getItem(event, this.actor)))
|
||||
this.html.find('.arme-label a').click(async event => this.actor.rollArme(duplicate(this._getEventArmeCombat(event))))
|
||||
|
||||
this.html.find('.roll-arme').click(async event => this.actor.rollArme(foundry.utils.duplicate(this._getEventArmeCombat(event)), 'competence'))
|
||||
|
||||
// Initiative pour l'arme
|
||||
this.html.find('.arme-initiative a').click(async event => {
|
||||
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id);
|
||||
this.html.find('.roll-init-arme').click(async event => {
|
||||
let combatant = game.combat.combatants.find(c => c.actor.id == this.actor.id)
|
||||
if (combatant) {
|
||||
let action = this._getEventArmeCombat(event);
|
||||
RdDCombatManager.rollInitiativeAction(combatant._id, action);
|
||||
RdDCombatManager.rollInitiativeAction(combatant._id, this._getEventArmeCombat(event));
|
||||
} else {
|
||||
ui.notifications.info("Impossible de lancer l'initiative sans être dans un combat.");
|
||||
}
|
||||
});
|
||||
})
|
||||
// Display TMR
|
||||
|
||||
this.html.find('.monte-tmr').click(async event => this.actor.displayTMR("normal"))
|
||||
this.html.find('.monte-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
|
||||
this.html.find('.button-tmr').click(async event => this.actor.displayTMR("normal"))
|
||||
this.html.find('.button-tmr-rapide').click(async event => this.actor.displayTMR("rapide"))
|
||||
|
||||
this.html.find('.repos').click(async event => await this.actor.repos())
|
||||
this.html.find('.button-repos').click(async event => await this.actor.repos())
|
||||
|
||||
this.html.find('.carac-xp-augmenter').click(async event => this.actor.updateCaracXPAuto(event.currentTarget.name.replace("augmenter.", "")))
|
||||
this.html.find('.competence-xp-augmenter').click(async event => this.actor.updateCompetenceXPAuto(RdDSheetUtility.getItemId(event)))
|
||||
@@ -280,7 +279,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
this.html.find('.moral-malheureux').click(async event => this.actor.jetDeMoral('malheureuse'))
|
||||
this.html.find('.moral-neutre').click(async event => this.actor.jetDeMoral('neutre'))
|
||||
this.html.find('.moral-heureux').click(async event => this.actor.jetDeMoral('heureuse'))
|
||||
this.html.find('.ethylisme-test').click(async event => this.actor.jetEthylisme())
|
||||
this.html.find('.button-ethylisme').click(async event => this.actor.jetEthylisme())
|
||||
|
||||
this.html.find('.ptreve-actuel-plus').click(async event => this.actor.reveActuelIncDec(1))
|
||||
this.html.find('.ptreve-actuel-moins').click(async event => this.actor.reveActuelIncDec(-1))
|
||||
@@ -388,7 +387,7 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
|
||||
async _onSplitItem(item, split) {
|
||||
if (split >= 1 && split < item.system.quantite) {
|
||||
await item.diminuerQuantite(split);
|
||||
const splitItem = duplicate(item);
|
||||
const splitItem = foundry.utils.duplicate(item);
|
||||
splitItem.system.quantite = split;
|
||||
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
||||
}
|
||||
|
||||
309
module/actor.js
309
module/actor.js
@@ -32,10 +32,12 @@ import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { AppAstrologie } from "./sommeil/app-astrologie.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { ExperienceLog, XP_TOPIC } from "./actor/experience-log.js";
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
import { RdDBaseActorSang } from "./actor/base-actor-sang.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { DialogChoixXpCarac } from "./dialog-choix-xp-carac.js";
|
||||
import { RdDItemArme } from "./item-arme.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
|
||||
|
||||
@@ -92,42 +94,61 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
canReceive(item) {
|
||||
return ![TYPES.competencecreature, TYPES.tarot, TYPES.service].includes(item.type)
|
||||
return ![ITEM_TYPES.competencecreature, ITEM_TYPES.tarot, ITEM_TYPES.service].includes(item.type)
|
||||
}
|
||||
|
||||
isPersonnageJoueur() {
|
||||
return this.hasPlayerOwner && this.prototypeToken.actorLink
|
||||
}
|
||||
|
||||
isPersonnage() { return true }
|
||||
isHautRevant() { return this.system.attributs.hautrevant.value != "" }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getAgilite() { return Number(this.system.carac.agilite?.value ?? 0) }
|
||||
getChance() { return Number(this.system.carac.chance?.value ?? 0) }
|
||||
getAgilite() { return this.system.carac.agilite?.value ?? 0 }
|
||||
getChance() { return this.system.carac.chance?.value ?? 0 }
|
||||
|
||||
getReveActuel() { return Misc.toInt(this.system.reve?.reve?.value ?? this.carac.reve.value) }
|
||||
getChanceActuel() { return Misc.toInt(this.system.compteurs.chance?.value ?? 10) }
|
||||
getMoralTotal() { return Number(this.system.compteurs.moral?.value ?? 0) }
|
||||
getReveActuel() { return this.system.reve?.reve?.value ?? this.carac.reve.value ?? 0 }
|
||||
getChanceActuel() { return this.system.compteurs.chance?.value ?? 10 }
|
||||
getMoralTotal() { return this.system.compteurs.moral?.value ?? 0 }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getEtatGeneral(options = { ethylisme: false }) {
|
||||
const etatGeneral = Misc.toInt(this.system.compteurs.etat?.value)
|
||||
if (options.ethylisme) {
|
||||
// Pour les jets d'Ethylisme, on retire le malus d'éthylisme (p.162)
|
||||
return etatGeneral - this.malusEthylisme()
|
||||
}
|
||||
return etatGeneral
|
||||
const etatGeneral = this.system.compteurs.etat?.value ?? 0
|
||||
// Pour les jets d'Ethylisme, on retire le malus d'éthylisme (p.162)
|
||||
const annuleMalusEthylisme = options.ethylisme ? this.malusEthylisme() : 0
|
||||
return etatGeneral - annuleMalusEthylisme
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getActivePoisons() {
|
||||
return duplicate(this.items.filter(item => item.type == 'poison' && item.system.active))
|
||||
return foundry.utils.duplicate(this.items.filter(item => item.type == 'poison' && item.system.active))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getMalusArmure() {
|
||||
return this.itemTypes[TYPES.armure].filter(it => it.system.equipe)
|
||||
return this.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
|
||||
.map(it => it.system.malus)
|
||||
.reduce(Misc.sum(), 0);
|
||||
}
|
||||
|
||||
listActionsCombat() {
|
||||
// Recupération des armes
|
||||
const actions = RdDCombatManager.listActionsArmes(
|
||||
this.itemTypes[ITEM_TYPES.arme]
|
||||
.filter(it => RdDItemArme.isAttaque(it))
|
||||
.concat(RdDItemArme.empoignade(this))
|
||||
.concat(RdDItemArme.mainsNues(this))
|
||||
,
|
||||
this.itemTypes[ITEM_TYPES.competence],
|
||||
this.system.carac)
|
||||
|
||||
if (this.system.attributs.hautrevant.value) {
|
||||
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getTache(id) { return this.findItemLike(id, 'tache') }
|
||||
getMeditation(id) { return this.findItemLike(id, 'meditation') }
|
||||
@@ -140,8 +161,8 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDemiReve() { return this.system.reve.tmrpos.coord }
|
||||
getDraconicList() { return this.itemTypes[TYPES.competence].filter(it => it.system.categorie == 'draconic') }
|
||||
getBestDraconic() { return duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
|
||||
getDraconicList() { return this.itemTypes[ITEM_TYPES.competence].filter(it => it.system.categorie == 'draconic') }
|
||||
getBestDraconic() { return foundry.utils.duplicate(this.getDraconicList().sort(Misc.descending(it => it.system.niveau)).find(it => true)) }
|
||||
getDraconicOuPossession() {
|
||||
return [...this.getDraconicList().filter(it => it.system.niveau >= 0),
|
||||
super.getDraconicOuPossession()]
|
||||
@@ -151,13 +172,13 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async $perteRevePotionsEnchantees() {
|
||||
let potions = this.itemTypes[TYPES.potion]
|
||||
let potions = this.itemTypes[ITEM_TYPES.potion]
|
||||
.filter(it => Grammar.includesLowerCaseNoAccent(it.system.categorie, 'enchanté') && !it.system.prpermanent)
|
||||
|
||||
const potionUpdates = await Promise.all(potions.map(async it => {
|
||||
const nouveauReve = Math.max(it.system.pr - 1, 0)
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html`, {
|
||||
pr: nouveauReve,
|
||||
alias: this.name,
|
||||
@@ -208,7 +229,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async grisReve(nbJours) {
|
||||
let message = {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `${nbJours} jours de gris rêve sont passés. `
|
||||
};
|
||||
for (let i = 0; i < nbJours; i++) {
|
||||
@@ -262,7 +283,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async dormirChateauDormant() {
|
||||
if (!ReglesOptionnelles.isUsing("chateau-dormant-gardien") || !this.system.sommeil || this.system.sommeil.nouveaujour) {
|
||||
const message = {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: ""
|
||||
};
|
||||
|
||||
@@ -343,9 +364,9 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async _recupererBlessures(message, isMaladeEmpoisonne) {
|
||||
const timestamp = game.system.rdd.calendrier.getTimestamp()
|
||||
const blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure).sort(Misc.ascending(it => it.system.gravite))
|
||||
const blessures = this.filterItems(it => it.system.gravite > 0, ITEM_TYPES.blessure).sort(Misc.ascending(it => it.system.gravite))
|
||||
|
||||
await Promise.all(blessures.map(b => b.recuperationBlessure({
|
||||
await Promise.all(blessures.map(async b => b.recuperationBlessure({
|
||||
actor: this,
|
||||
timestamp,
|
||||
message,
|
||||
@@ -359,7 +380,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async _recupererVie(message, isMaladeEmpoisonne) {
|
||||
const tData = this.system
|
||||
let blessures = this.filterItems(it => it.system.gravite > 0, TYPES.blessure);
|
||||
let blessures = this.filterItems(it => it.system.gravite > 0, ITEM_TYPES.blessure);
|
||||
if (blessures.length > 0) {
|
||||
return
|
||||
}
|
||||
@@ -398,7 +419,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async remiseANeuf() {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: 'Remise à neuf de ' + this.name
|
||||
});
|
||||
await this.supprimerBlessures(it => true);
|
||||
@@ -415,7 +436,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async dormir(heures, options = { grisReve: false, chateauDormant: false }) {
|
||||
const message = {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: this.name + ': '
|
||||
};
|
||||
const insomnie = this.system.sommeil?.insomnie || heures == 0;
|
||||
@@ -427,7 +448,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
let jetsReve = [];
|
||||
let dormi = await this.dormirDesHeures(jetsReve, message, heures, options);
|
||||
if (jetsReve.length > 0) {
|
||||
message.content += `Vous récupérez ${jetsReve.map(it => it < 0 ? '(dragon)' : it).reduce(Misc.joining("+"))} Points de rêve. `;
|
||||
message.content += `Vous récupérez ${jetsReve.map(it => it < 0 ? '0 (réveil)' : it).reduce(Misc.joining("+"))} Points de rêve. `;
|
||||
}
|
||||
if (dormi.etat == 'eveil') {
|
||||
await this.reveilReveDeDragon(message, dormi.heures);
|
||||
@@ -448,7 +469,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
async reveilReveDeDragon(message, heures) {
|
||||
message.content += 'Vous êtes réveillé par un Rêve de Dragon.';
|
||||
const restant = Math.max(this.system.sommeil?.heures - heures, 0)
|
||||
if (restant > 0) {
|
||||
await this.update({ 'system.sommeil': { heures: restant } });
|
||||
@@ -487,7 +507,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
else {
|
||||
if (!ReglesOptionnelles.isUsing("recuperation-reve")) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `Pas de récupération de rêve (${reve} points ignorés)`
|
||||
});
|
||||
jetsReve.push(0);
|
||||
@@ -635,7 +655,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async sortMisEnReserve(sort, draconic, coord, ptreve) {
|
||||
await this.createEmbeddedDocuments("Item", [{
|
||||
type: TYPES.sortreserve,
|
||||
type: ITEM_TYPES.sortreserve,
|
||||
name: sort.name,
|
||||
img: sort.img,
|
||||
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
|
||||
@@ -689,7 +709,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
let carac = this.findCaracByName(caracName);
|
||||
if (carac) {
|
||||
carac = duplicate(carac);
|
||||
carac = foundry.utils.duplicate(carac);
|
||||
const fromXp = Number(carac.xp);
|
||||
const fromValue = Number(carac.value);
|
||||
let toXp = fromXp;
|
||||
@@ -825,7 +845,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
async deleteExperienceLog(from, count) {
|
||||
if (from >= 0 && count > 0) {
|
||||
let expLog = duplicate(this.system.experiencelog);
|
||||
let expLog = foundry.utils.duplicate(this.system.experiencelog);
|
||||
expLog.splice(from, count);
|
||||
await this.update({ [`system.experiencelog`]: expLog });
|
||||
}
|
||||
@@ -901,7 +921,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async ajouterRefoulement(value = 1, refouler) {
|
||||
let refoulement = this.system.reve.refoulement.value + value;
|
||||
const roll = new Roll("1d20");
|
||||
await roll.evaluate({ async: true });
|
||||
await roll.evaluate();
|
||||
await roll.toMessage({ flavor: `${this.name} refoule ${refouler} pour ${value} points de refoulement (total: ${refoulement})` });
|
||||
if (roll.total <= refoulement) {
|
||||
refoulement = 0;
|
||||
@@ -918,7 +938,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.createEmbeddedDocuments('Item', [souffle]);
|
||||
if (options.chat) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: this.name + " subit un Souffle de Dragon : " + souffle.name
|
||||
});
|
||||
}
|
||||
@@ -938,7 +958,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.createEmbeddedDocuments('Item', [queue]);
|
||||
if (options.chat) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: this.name + " subit une Queue de Dragon : " + queue.name
|
||||
});
|
||||
}
|
||||
@@ -976,7 +996,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
let tmr = await TMRUtility.getTMRAleatoire(tmr => accessible(tmr) && !innaccessible.includes(tmr.coord));
|
||||
ChatMessage.create({
|
||||
content: `${raison} : ré-insertion aléatoire.`,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
await this.forcerPositionTMRInconnue(tmr);
|
||||
return tmr;
|
||||
@@ -990,25 +1010,31 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
buildTMRInnaccessible() {
|
||||
const tmrInnaccessibles = this.filterItems(it => Draconique.isCaseTMR(it) &&
|
||||
EffetsDraconiques.isInnaccessible(it));
|
||||
return tmrInnaccessibles.map(it => it.system.coord);
|
||||
return this.items.filter(it => it.type == ITEM_TYPES.casetmr).filter(it => EffetsDraconiques.isInnaccessible(it)).map(it => it.system.coord)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getTMRRencontres() {
|
||||
return this.itemTypes['rencontre'];
|
||||
getRencontresTMR() {
|
||||
return this.itemTypes[ITEM_TYPES.rencontre];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async deleteTMRRencontreAtPosition() {
|
||||
const demiReve = this.getDemiReve()
|
||||
let rencontreIds = this.items.filter(it => it.type == 'rencontre' && it.system.coord == demiReve).map(it => it.id);
|
||||
async deleteRencontreTMRAtPosition() {
|
||||
const rencontreIds = this.itemTypes[ITEM_TYPES.rencontre].filter(this.filterRencontreTMRDemiReve()).map(it => it.id)
|
||||
if (rencontreIds.length > 0) {
|
||||
await this.deleteEmbeddedDocuments('Item', rencontreIds);
|
||||
await this.deleteEmbeddedDocuments('Item', rencontreIds)
|
||||
}
|
||||
}
|
||||
|
||||
getRencontreTMREnAttente() {
|
||||
return this.itemTypes[ITEM_TYPES.rencontre].find(this.filterRencontreTMRDemiReve())
|
||||
}
|
||||
|
||||
filterRencontreTMRDemiReve() {
|
||||
const position = this.getDemiReve()
|
||||
return it => it.system.coord == position
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async addTMRRencontre(currentRencontre) {
|
||||
const toCreate = currentRencontre.toObject();
|
||||
@@ -1075,7 +1101,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
const jetMoral = await this._jetDeMoral(situation);
|
||||
const finMessage = (jetMoral.succes ? messageReussi : messageManque) ?? (jetMoral.ajustement == 0 ? "Vous gardez votre moral" : jetMoral.ajustement > 0 ? "Vous gagnez du moral" : "Vous perdez du moral");
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `${finMessage} - jet ${jetMoral.succes ? "réussi" : "manqué"} en situation ${situation} (${jetMoral.jet}/${jetMoral.difficulte}).`
|
||||
});
|
||||
return jetMoral.ajustement;
|
||||
@@ -1139,7 +1165,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
diffNbDoses: -Number(this.system.compteurs.ethylisme.nb_doses || 0),
|
||||
finalLevel: 0,
|
||||
diffConditions: 0,
|
||||
ajustementsForce: CONFIG.RDD.difficultesLibres,
|
||||
ajustementsForce: CONFIG.RDD.difficultesLibres
|
||||
}
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ethylisme.html', rollData);
|
||||
new RdDRollDialogEthylisme(html, rollData, this, r => this.saouler(r.forceAlcool)).render(true);
|
||||
@@ -1153,11 +1179,11 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (result) { return result }
|
||||
|
||||
switch (item.type) {
|
||||
case TYPES.potion: return await this.consommerPotion(item, onActionItem);
|
||||
case TYPES.livre: return await this.actionLire(item);
|
||||
case TYPES.conteneur: return await item.sheet.render(true);
|
||||
case TYPES.herbe: return await this.actionHerbe(item, onActionItem);
|
||||
case TYPES.queue: case TYPES.ombre: return await this.actionRefoulement(item);
|
||||
case ITEM_TYPES.potion: return await this.consommerPotion(item, onActionItem);
|
||||
case ITEM_TYPES.livre: return await this.actionLire(item);
|
||||
case ITEM_TYPES.conteneur: return await item.sheet.render(true);
|
||||
case ITEM_TYPES.herbe: return await this.actionHerbe(item, onActionItem);
|
||||
case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return await this.actionRefoulement(item);
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
@@ -1310,7 +1336,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async saouler(forceAlcool, alcool = undefined) {
|
||||
let ethylisme = duplicate(this.system.compteurs.ethylisme);
|
||||
let ethylisme = foundry.utils.duplicate(this.system.compteurs.ethylisme);
|
||||
|
||||
const etat = this.getEtatGeneral({ ethylisme: true });
|
||||
const nbDoses = Number(this.system.compteurs.ethylisme.nb_doses || 0);
|
||||
@@ -1331,7 +1357,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
await RdDResolutionTable.rollData(ethylismeData.jetVie);
|
||||
this._appliquerExperienceRollData(ethylismeData.jetVie);
|
||||
this._gererExperience(ethylismeData.jetVie);
|
||||
RollDataAjustements.calcul(ethylismeData.jetVie, this);
|
||||
if (ethylismeData.jetVie.rolled.isSuccess) {
|
||||
ethylisme.nb_doses++;
|
||||
@@ -1363,7 +1389,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
finalLevel: Number(ethylisme.value) + Number(this.system.compteurs.moral.value)
|
||||
}
|
||||
await RdDResolutionTable.rollData(ethylismeData.jetVolonte);
|
||||
this._appliquerExperienceRollData(ethylismeData.jetVolonte);
|
||||
this._gererExperience(ethylismeData.jetVolonte);
|
||||
RollDataAjustements.calcul(ethylismeData.jetVolonte, this);
|
||||
}
|
||||
}
|
||||
@@ -1412,7 +1438,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
};
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-transformer-stress.html`, stressRollData)
|
||||
});
|
||||
|
||||
@@ -1487,7 +1513,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
const niveauSuivant = Number(carac.value) + 1;
|
||||
let xpNeeded = RdDCarac.getCaracNextXp(niveauSuivant);
|
||||
if (carac.xp >= xpNeeded) {
|
||||
carac = duplicate(carac);
|
||||
carac = foundry.utils.duplicate(carac);
|
||||
carac.value = niveauSuivant;
|
||||
|
||||
let checkXp = {
|
||||
@@ -1498,7 +1524,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
if (display) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html`, checkXp)
|
||||
});
|
||||
}
|
||||
@@ -1517,7 +1543,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (compData && newXP > 0) {
|
||||
let xpNeeded = RdDItemCompetence.getCompetenceNextXp(compData.system.niveau + 1);
|
||||
if (newXP >= xpNeeded) {
|
||||
let newCompData = duplicate(compData);
|
||||
let newCompData = foundry.utils.duplicate(compData);
|
||||
newCompData.system.niveau += 1;
|
||||
newCompData.system.xp = newXP;
|
||||
let checkXp = {
|
||||
@@ -1530,7 +1556,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
if (display) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html`, checkXp)
|
||||
});
|
||||
}
|
||||
@@ -1541,19 +1567,22 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
|
||||
if (!Misc.isFirstConnectedGM()) {
|
||||
return
|
||||
}
|
||||
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
|
||||
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance);
|
||||
if (xpData.length) {
|
||||
const content = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-gain-xp.html`, {
|
||||
actor: this,
|
||||
xpData
|
||||
});
|
||||
})
|
||||
if (hideChatMessage) {
|
||||
ChatUtility.blindMessageToGM({ content: content });
|
||||
ChatUtility.blindMessageToGM({ content: content })
|
||||
}
|
||||
else {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: content
|
||||
});
|
||||
}
|
||||
@@ -1592,7 +1621,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
computeDraconicAndSortIndex(sortList) {
|
||||
let draconicList = this.getDraconicList();
|
||||
for (let sort of sortList) {
|
||||
let draconicsSort = this.getDraconicsSort(draconicList, sort).map(it => it.name);
|
||||
let draconicsSort = RdDItemSort.getDraconicsSort(draconicList, sort).map(it => it.name);
|
||||
for (let index = 0; index < draconicList.length && sort.system.listIndex == undefined; index++) {
|
||||
if (draconicsSort.includes(draconicList[index].name)) {
|
||||
sort.system.listIndex = index;
|
||||
@@ -1602,19 +1631,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
return draconicList;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getDraconicsSort(draconicList, sort) {
|
||||
//console.log(draconicList, bestDraconic, draconic, voie);
|
||||
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
|
||||
case "lecture d'aura":
|
||||
case "detection d'aura":
|
||||
return draconicList;
|
||||
case "annulation de magie":
|
||||
return draconicList.filter(it => !RdDItemCompetence.isThanatos(it));
|
||||
}
|
||||
return [RdDItemCompetence.getVoieDraconic(draconicList, sort.system.draconic)];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollUnSort(coord) {
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
@@ -1623,14 +1639,14 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
return;
|
||||
}
|
||||
// Duplication car les pts de reve sont modifiés dans le sort
|
||||
let sorts = duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
|
||||
let sorts = foundry.utils.duplicate(this.$filterSortList(this.itemTypes['sort'], coord));
|
||||
if (sorts.length == 0) {
|
||||
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
|
||||
return;
|
||||
}
|
||||
|
||||
const draconicList = this.computeDraconicAndSortIndex(sorts);
|
||||
const reve = duplicate(this.system.carac.reve);
|
||||
const reve = foundry.utils.duplicate(this.system.carac.reve);
|
||||
|
||||
const dialog = await this.openRollDialog({
|
||||
name: 'lancer-un-sort',
|
||||
@@ -1669,7 +1685,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
ChatMessage.create({
|
||||
content: "Vous êtes sous le coup d'une Mauvaise Rencontre en Persective." + addMsg,
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
return rencSpecial;
|
||||
@@ -1681,7 +1697,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (countInertieDraconique > 0) {
|
||||
ChatMessage.create({
|
||||
content: `Vous êtes sous le coup d'Inertie Draconique : vous perdrez ${countInertieDraconique + 1} cases de Fatigue par déplacement au lieu d'une.`,
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
return countInertieDraconique + 1;
|
||||
@@ -1693,7 +1709,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.reveActuelIncDec(-1);
|
||||
ChatMessage.create({
|
||||
content: "Vous êtes sous le coup d'un Péage : l'entrée sur cette case vous a coûté 1 Point de Rêve (déduit automatiquement).",
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1729,7 +1745,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
else {
|
||||
rollData.depenseReve = 0;
|
||||
rollData.show.reveInsuffisant = true;
|
||||
mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), { overwrite: true });
|
||||
foundry.utils.mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), { overwrite: true });
|
||||
}
|
||||
} else {
|
||||
if (rolled.isETotal) { // Echec total !
|
||||
@@ -1777,13 +1793,13 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
};
|
||||
RollDataAjustements.calcul(rollData, this);
|
||||
await RdDResolutionTable.rollData(rollData);
|
||||
this._appliquerExperienceRollData(rollData);
|
||||
this._gererExperience(rollData);
|
||||
await RdDResolutionTable.displayRollData(rollData, this)
|
||||
return rollData.rolled;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_appliquerExperienceRollData(rollData) {
|
||||
_gererExperience(rollData) {
|
||||
const callback = this.createCallbackExperience();
|
||||
if (callback.condition(rollData)) {
|
||||
callback.action(rollData);
|
||||
@@ -1816,7 +1832,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
blessuresASoigner() {
|
||||
return (this.itemTypes[TYPES.blessure])
|
||||
return (this.itemTypes[ITEM_TYPES.blessure])
|
||||
.filter(it => it.system.gravite > 0 && it.system.gravite <= 6)
|
||||
.filter(it => !(it.system.premierssoins.done && it.system.soinscomplets.done))
|
||||
.sort(Misc.descending(b => (b.system.premierssoins.done ? "A" : "B") + b.system.gravite))
|
||||
@@ -1871,7 +1887,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
diffConditions: 0,
|
||||
use: { libre: false, conditions: true },
|
||||
carac: {
|
||||
[tacheData.system.carac]: duplicate(this.system.carac[tacheData.system.carac])
|
||||
[tacheData.system.carac]: foundry.utils.duplicate(this.system.carac[tacheData.system.carac])
|
||||
}
|
||||
},
|
||||
callbackAction: r => this._tacheResult(r, options)
|
||||
@@ -1882,7 +1898,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async _tacheResult(rollData, options) {
|
||||
// Mise à jour de la tache
|
||||
rollData.appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
|
||||
rollData.tache = duplicate(rollData.tache);
|
||||
rollData.tache = foundry.utils.duplicate(rollData.tache);
|
||||
rollData.tache.system.points_de_tache_courant += rollData.rolled.ptTache;
|
||||
if (rollData.rolled.isETotal) {
|
||||
rollData.tache.system.difficulte--;
|
||||
@@ -1906,21 +1922,21 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async _rollArt(artData, selected, oeuvre, callbackAction = r => this._resultArt(r)) {
|
||||
oeuvre.system.niveau = oeuvre.system.niveau ?? 0;
|
||||
mergeObject(artData,
|
||||
foundry.utils.mergeObject(artData,
|
||||
{
|
||||
oeuvre: oeuvre,
|
||||
art: oeuvre.type,
|
||||
competence: duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
|
||||
competence: foundry.utils.duplicate(this.getCompetence(artData.compName ?? oeuvre.system.competence ?? artData.art)),
|
||||
diffLibre: - oeuvre.system.niveau,
|
||||
diffConditions: 0,
|
||||
use: { libre: false, conditions: true, surenc: false },
|
||||
selectedCarac: duplicate(this.system.carac[selected])
|
||||
selectedCarac: foundry.utils.duplicate(this.system.carac[selected])
|
||||
},
|
||||
{ overwrite: false });
|
||||
artData.competence.system.defaut_carac = selected;
|
||||
if (!artData.forceCarac) {
|
||||
artData.forceCarac = {};
|
||||
artData.forceCarac[selected] = duplicate(this.system.carac[selected]);
|
||||
artData.forceCarac[selected] = foundry.utils.duplicate(this.system.carac[selected]);
|
||||
}
|
||||
|
||||
await this.openRollDialog({
|
||||
@@ -1944,19 +1960,19 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async rollChant(id) {
|
||||
const artData = { art: 'chant', verbe: 'Chanter' };
|
||||
const oeuvre = duplicate(this.getChant(id));
|
||||
const oeuvre = foundry.utils.duplicate(this.getChant(id));
|
||||
await this._rollArt(artData, "ouie", oeuvre);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollDanse(id) {
|
||||
const artData = { art: 'danse', verbe: 'Danser', forceCarac: {} };
|
||||
const oeuvre = duplicate(this.findItemLike(id, artData.art));
|
||||
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art));
|
||||
if (oeuvre.system.agilite) {
|
||||
artData.forceCarac['agilite'] = duplicate(this.system.carac.agilite);
|
||||
artData.forceCarac['agilite'] = foundry.utils.duplicate(this.system.carac.agilite);
|
||||
}
|
||||
if (oeuvre.system.apparence) {
|
||||
artData.forceCarac['apparence'] = duplicate(this.system.carac.apparence);
|
||||
artData.forceCarac['apparence'] = foundry.utils.duplicate(this.system.carac.apparence);
|
||||
}
|
||||
const selectedCarac = this._getCaracDanse(oeuvre);
|
||||
await this._rollArt(artData, selectedCarac, oeuvre);
|
||||
@@ -2059,7 +2075,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
const artData = {
|
||||
art: 'jeu', verbe: 'Jeu',
|
||||
use: { libre: true, conditions: true, },
|
||||
competence: duplicate(this.getCompetence('jeu')),
|
||||
competence: foundry.utils.duplicate(this.getCompetence('jeu')),
|
||||
forceCarac: {}
|
||||
};
|
||||
listCarac.forEach(c => artData.forceCarac[c] = this.system.carac[c]);
|
||||
@@ -2070,14 +2086,14 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
async rollOeuvre(id) {
|
||||
const artData = { art: 'oeuvre', verbe: 'Interpréter' }
|
||||
const oeuvre = duplicate(this.findItemLike(id, artData.art))
|
||||
const oeuvre = foundry.utils.duplicate(this.findItemLike(id, artData.art))
|
||||
await this._rollArt(artData, oeuvre.system.default_carac, oeuvre)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollMeditation(id) {
|
||||
const meditation = duplicate(this.getMeditation(id));
|
||||
const competence = duplicate(this.getCompetence(meditation.system.competence));
|
||||
const meditation = foundry.utils.duplicate(this.getMeditation(id));
|
||||
const competence = foundry.utils.duplicate(this.getCompetence(meditation.system.competence));
|
||||
competence.system.defaut_carac = "intellect"; // Meditation = toujours avec intellect
|
||||
let meditationData = {
|
||||
competence: competence,
|
||||
@@ -2143,7 +2159,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
let draconicList = this.getDraconicList()
|
||||
.map(draconic => {
|
||||
let draconicLecture = duplicate(draconic);
|
||||
let draconicLecture = foundry.utils.duplicate(draconic);
|
||||
draconicLecture.system.defaut_carac = "intellect";
|
||||
return draconicLecture;
|
||||
});
|
||||
@@ -2267,15 +2283,15 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async _appliquerExperience(rolled, caracName, competence, jetResistance) {
|
||||
// Pas d'XP
|
||||
if (!rolled.isPart || rolled.finalLevel >= 0) {
|
||||
return undefined;
|
||||
return []
|
||||
}
|
||||
if (this.checkDesirLancinant()) {
|
||||
// Cas de désir lancinant, pas d'expérience sur particulière
|
||||
ChatMessage.create({
|
||||
content: `Vous souffrez au moins d'un Désir Lancinant, vous ne pouvez pas gagner d'expérience sur une Particulière tant que le désir n'est pas assouvi`,
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
return undefined;
|
||||
return []
|
||||
}
|
||||
|
||||
let xp = Math.abs(rolled.finalLevel);
|
||||
@@ -2312,7 +2328,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async _xpCarac(xpData) {
|
||||
if (xpData.xpCarac > 0) {
|
||||
const carac = duplicate(this.system.carac)
|
||||
const carac = foundry.utils.duplicate(this.system.carac)
|
||||
const code = RdDBaseActor._findCaracNode(carac, xpData.caracName)
|
||||
const selectedCarac = carac[code]
|
||||
if (this.isCaracMax(code)) {
|
||||
@@ -2336,7 +2352,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
async _xpCaracDerivee(xpData) {
|
||||
const caracs = RdDActor._getComposantsCaracDerivee(xpData.caracName)
|
||||
.map(c => mergeObject(this.system.carac[c], { isMax: this.isCaracMax(c) }))
|
||||
.map(c => foundry.utils.mergeObject(this.system.carac[c], { isMax: this.isCaracMax(c) }, { inplace: false }))
|
||||
switch (caracs.filter(it => !it.isMax).length) {
|
||||
case 0:
|
||||
xpData.caracRepartitionManuelle = true;
|
||||
@@ -2352,6 +2368,8 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
static _getComposantsCaracDerivee(caracName) {
|
||||
switch (Grammar.toLowerCaseNoAccent(caracName)) {
|
||||
case 'reve-actuel': case 'reve actuel': return ['reve']
|
||||
case 'chance-actuelle': case 'chance actuelle': return ['chance']
|
||||
case 'vie': return ['constitution']
|
||||
case 'tir': return ['vue', 'dexterite']
|
||||
case 'lancer': return ['force', 'dexterite', 'vue']
|
||||
@@ -2363,26 +2381,25 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async resetNombresAstraux() {
|
||||
async deleteNombresAstraux() {
|
||||
const deletions = this.itemTypes['nombreastral'].map(it => it._id);
|
||||
await this.deleteEmbeddedDocuments("Item", deletions);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ajouteNombreAstral(callData) {
|
||||
const indexDate = Number.parseInt(callData.date);
|
||||
async ajouteNombreAstral(date, nbAstral, isValid) {
|
||||
const indexDate = Number.parseInt(date);
|
||||
// Ajout du nombre astral
|
||||
const item = {
|
||||
name: "Nombre Astral", type: "nombreastral", system:
|
||||
{
|
||||
value: callData.nbAstral,
|
||||
istrue: callData.isvalid,
|
||||
value: nbAstral,
|
||||
istrue: isValid,
|
||||
jourindex: indexDate,
|
||||
jourlabel: RdDTimestamp.formatIndexDate(indexDate)
|
||||
}
|
||||
};
|
||||
await this.createEmbeddedDocuments("Item", [item]);
|
||||
game.system.rdd.calendrier.notifyChangeNombresAstraux();
|
||||
}
|
||||
|
||||
async supprimerAnciensNombresAstraux() {
|
||||
@@ -2407,7 +2424,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (countMonteeLaborieuse > 0) {
|
||||
ChatMessage.create({
|
||||
content: `Vous êtes sous le coup d'une Montée Laborieuse : vos montées en TMR coûtent ${countMonteeLaborieuse} Point de Rêve de plus.`,
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
return countMonteeLaborieuse;
|
||||
@@ -2423,22 +2440,29 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async displayTMR(mode = "normal") {
|
||||
if (this.tmrApp) {
|
||||
ui.notifications.warn("Vous êtes déja dans les TMR....");
|
||||
this.tmrApp.forceTMRDisplay();
|
||||
ui.notifications.warn("Vous êtes déja dans les TMR....")
|
||||
this.tmrApp.forceTMRDisplay()
|
||||
return
|
||||
}
|
||||
if (mode != 'visu' && this.getEffect(STATUSES.StatusDemiReve)) {
|
||||
ui.notifications.warn("Le joueur ou le MJ est déja dans les Terres Médianes avec ce personnage ! Visualisation uniquement");
|
||||
ui.notifications.warn("Les personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
|
||||
mode = "visu"; // bascule le mode en visu automatiquement
|
||||
}
|
||||
RdDConfirm.confirmer({
|
||||
bypass: mode == 'visu',
|
||||
settingConfirmer: "confirmation-tmr",
|
||||
content: `<p>Voulez vous monter dans les TMR en mode ${mode}?</p>`,
|
||||
title: 'Confirmer la montée dans les TMR',
|
||||
buttonLabel: 'Monter dans les TMR',
|
||||
onAction: async () => await this._doDisplayTMR(mode)
|
||||
});
|
||||
if (mode == 'visu') {
|
||||
await this._doDisplayTMR(mode)
|
||||
}
|
||||
else {
|
||||
const rencontre = this.getRencontreTMREnAttente();
|
||||
const settingConfirmer = rencontre ? "confirmation-tmr-rencontre" : "confirmation-tmr";
|
||||
const messageRencontre = rencontre ? `<p>Vous devrez combattre ${rencontre.system.genre == 'f' ? 'la' : 'le'} ${rencontre.name} de ${rencontre.system.force} points de Rêve</p>` : '';
|
||||
RdDConfirm.confirmer({
|
||||
settingConfirmer: settingConfirmer,
|
||||
content: `<p>Voulez vous monter dans les TMR en mode ${mode}?</p>` + messageRencontre,
|
||||
title: 'Confirmer la montée dans les TMR',
|
||||
buttonLabel: 'Monter dans les TMR',
|
||||
onAction: async () => await this._doDisplayTMR(mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async _doDisplayTMR(mode) {
|
||||
@@ -2448,7 +2472,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (this.getReveActuel() < minReveValue) {
|
||||
ChatMessage.create({
|
||||
content: `Vous n'avez les ${minReveValue} Points de Reve nécessaires pour monter dans les Terres Médianes`,
|
||||
whisper: ChatMessage.getWhisperRecipients(this.name)
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -2611,12 +2635,12 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
async resetItemUse() {
|
||||
await this.unsetFlag(SYSTEM_RDD, 'itemUse');
|
||||
await this.setFlag(SYSTEM_RDD, 'itemUse', {});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async incDecItemUse(itemId, inc = 1) {
|
||||
let itemUse = duplicate(this.getFlag(SYSTEM_RDD, 'itemUse') ?? {});
|
||||
const currentItemUse = this.getFlag(SYSTEM_RDD, 'itemUse');
|
||||
let itemUse = currentItemUse ? foundry.utils.duplicate(currentItemUse) : {};
|
||||
itemUse[itemId] = (itemUse[itemId] ?? 0) + inc;
|
||||
await this.setFlag(SYSTEM_RDD, 'itemUse', itemUse);
|
||||
console.log("ITEM USE INC", inc, itemUse);
|
||||
@@ -2684,7 +2708,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static $transformSubActeurSuivant = (suivant, link) => {
|
||||
return mergeObject(RdDBaseActor.extractActorMin(suivant), {
|
||||
return foundry.utils.mergeObject(RdDBaseActor.extractActorMin(suivant), {
|
||||
ephemere: !suivant.prototypeToken.actorLink,
|
||||
coeur: link.coeur ?? 0,
|
||||
prochainCoeur: link.prochainCoeur ?? link.coeur ?? 0
|
||||
@@ -2710,7 +2734,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
|
||||
async setPointsCoeur(subActorId, coeurs, options = { immediat: false }) {
|
||||
const newSuivants = duplicate(this.system.subacteurs.suivants)
|
||||
const newSuivants = foundry.utils.duplicate(this.system.subacteurs.suivants)
|
||||
const amoureux = newSuivants.find(it => it.id == subActorId);
|
||||
if (amoureux) {
|
||||
amoureux[options.immediat ? 'coeur' : 'prochainCoeur'] = coeurs
|
||||
@@ -2720,7 +2744,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static $transformSubActeurVehicule = (vehicle, link) => {
|
||||
return mergeObject(RdDBaseActor.extractActorMin(vehicle), {
|
||||
return foundry.utils.mergeObject(RdDBaseActor.extractActorMin(vehicle), {
|
||||
system: { categorie: vehicle.system.categorie, etat: vehicle.system.etat }
|
||||
})
|
||||
};
|
||||
@@ -2845,7 +2869,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.setBonusPotionSoin(potionData.system.herbebonus);
|
||||
}
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-soin.html`, potionData)
|
||||
});
|
||||
}
|
||||
@@ -2882,7 +2906,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
this.bonusRepos = potionData.system.herbebonus;
|
||||
}
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-repos.html`, potionData)
|
||||
});
|
||||
}
|
||||
@@ -2914,7 +2938,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
this.diminuerQuantiteObjet(herbeData._id, herbeData.nbBrins);
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html`, messageData)
|
||||
});
|
||||
}
|
||||
@@ -2939,7 +2963,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-consommer-potion-generique.html`, potionData)
|
||||
});
|
||||
}
|
||||
@@ -2967,9 +2991,6 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isEffectAllowed(effectId) { return true }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onPreUpdateItem(item, change, options, id) {
|
||||
if (item.isCompetencePersonnage() && item.system.defaut_carac && item.system.xp) {
|
||||
@@ -3009,7 +3030,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onCreateOwnedDraconique(item, options, id) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
let draconique = Draconique.all().find(it => it.match(item));
|
||||
if (draconique) {
|
||||
await draconique.onActorCreateOwned(this, item)
|
||||
@@ -3021,7 +3042,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onDeleteOwnedDraconique(item, options, id) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
let draconique = Draconique.all().find(it => it.match(item));
|
||||
if (draconique) {
|
||||
await draconique.onActorDeleteOwned(this, item)
|
||||
@@ -3031,7 +3052,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onDeleteOwnedCaseTmr(item, options, id) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
let draconique = Draconique.all().find(it => it.isCase(item));
|
||||
if (draconique) {
|
||||
await draconique.onActorDeleteCaseTmr(this, item)
|
||||
@@ -3042,7 +3063,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
notifyGestionTeteSouffleQueue(item, manualMessage = true) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `${this.name} a reçu un/une ${item.type}: ${item.name}, qui ${manualMessage ? "n'est pas" : "est"} géré(e) automatiquement. ${manualMessage ? manualMessage : ''}`
|
||||
});
|
||||
}
|
||||
@@ -3050,7 +3071,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async nouvelleIncarnation() {
|
||||
let incarnation = this.toObject();
|
||||
|
||||
incarnation.items = Array.from(this.items.filter(it => it.type == TYPES.competence),
|
||||
incarnation.items = Array.from(this.items.filter(it => it.type == ITEM_TYPES.competence),
|
||||
it => {
|
||||
it = it.toObject();
|
||||
it.id = undefined;
|
||||
@@ -3064,8 +3085,8 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
incarnation.name = 'Réincarnation de ' + incarnation.name
|
||||
incarnation.system = {
|
||||
carac: duplicate(this.system.carac),
|
||||
heure: RdDTimestamp.defHeure(await RdDDice.rollTotal("1dh", { rollMode: "selfroll", showDice: SHOW_DICE })).key,
|
||||
carac: foundry.utils.duplicate(this.system.carac),
|
||||
heure: RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key,
|
||||
age: 18,
|
||||
biographie: '',
|
||||
notes: '',
|
||||
|
||||
@@ -11,7 +11,7 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
width: 550
|
||||
});
|
||||
}
|
||||
@@ -24,14 +24,15 @@ export class RdDBaseActorReveSheet extends RdDBaseActorSheet {
|
||||
// Everything below here is only needed if the sheet is editable
|
||||
if (!this.options.editable) return;
|
||||
|
||||
this.html.find('.encaisser-direct').click(async event => this.actor.encaisser())
|
||||
this.html.find('.carac-label a').click(async event => this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes.name.value)));
|
||||
this.html.find('a.competence-label').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
|
||||
this.html.find('.button-encaissement').click(async event => this.actor.encaisser())
|
||||
this.html.find('.roll-carac').click(async event => {
|
||||
this.actor.rollCarac(Grammar.toLowerCaseNoAccent(event.currentTarget.attributes['data-carac-name'].value))});
|
||||
this.html.find('.roll-competence').click(async event => this.actor.rollCompetence(RdDSheetUtility.getItemId(event)));
|
||||
this.html.find('.endurance-plus').click(async event => this.actor.santeIncDec("endurance", 1));
|
||||
this.html.find('.endurance-moins').click(async event => this.actor.santeIncDec("endurance", -1));
|
||||
|
||||
if (game.user.isGM) {
|
||||
this.html.find('.remise-a-neuf').click(async event => this.actor.remiseANeuf())
|
||||
this.html.find('.button-remise-a-neuf').click(async event => this.actor.remiseANeuf())
|
||||
this.html.find('.delete-active-effect').click(async event => this.actor.removeEffect(this.html.find(event.currentTarget).parents(".active-effect").data('effect')));
|
||||
this.html.find('.enlever-tous-effets').click(async event => await this.actor.removeEffects());
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { RdDBaseActor } from "./base-actor.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
import { StatusEffects } from "../settings/status-effects.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { Targets } from "../targets.js";
|
||||
import { RdDPossession } from "../rdd-possession.js";
|
||||
import { RdDCombat } from "../rdd-combat.js";
|
||||
import { RdDCombat, RdDCombatManager } from "../rdd-combat.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { ENTITE_INCARNE, SHOW_DICE, SYSTEM_RDD } from "../constants.js";
|
||||
import { RdDItemArme } from "../item-arme.js";
|
||||
@@ -78,8 +78,27 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
async jetEndurance(resteEndurance = undefined) { return { jetEndurance: 0, sonne: false } }
|
||||
isDead() { return false }
|
||||
isSonne() { return false }
|
||||
blessuresASoigner() { return [] }
|
||||
getEtatGeneral(options = { ethylisme: false }) { return 0 }
|
||||
isActorCombat() { return true }
|
||||
|
||||
getCaracInit(competence) {
|
||||
if (!competence){
|
||||
return 0
|
||||
}
|
||||
if (competence.type == ITEM_TYPES.competencecreature) {
|
||||
return competence.system.carac_value
|
||||
}
|
||||
return this.system.carac[competence.system.defaut_carac].value;
|
||||
}
|
||||
listActionsCombat() {
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => RdDItemCompetenceCreature.isAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.armeCreature(it))
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
|
||||
|
||||
async computeArmure(attackerRoll) { return this.getProtectionNaturelle() }
|
||||
async remiseANeuf() { }
|
||||
@@ -108,14 +127,14 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
async $finDeRoundSupprimerObsoletes() {
|
||||
const obsoletes = []
|
||||
.concat(this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
|
||||
.concat(this.itemTypes[TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
|
||||
.concat(this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp <= 0))
|
||||
.concat(this.itemTypes[ITEM_TYPES.possession].filter(it => it.system.compteur < -2 || it.system.compteur > 2))
|
||||
.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('Item', obsoletes);
|
||||
}
|
||||
|
||||
async $finDeRoundEmpoignade() {
|
||||
const immobilisations = this.itemTypes[TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
|
||||
const immobilisations = this.itemTypes[ITEM_TYPES.empoignade].filter(it => it.system.pointsemp >= 2 && it.system.empoigneurid == this.id);
|
||||
immobilisations.forEach(emp => RdDEmpoignade.onImmobilisation(this,
|
||||
game.actors.get(emp.system.empoigneid),
|
||||
emp
|
||||
@@ -151,13 +170,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
|
||||
getPossession(possessionId) {
|
||||
return this.itemTypes[TYPES.possession].find(it => it.system.possessionid == possessionId);
|
||||
}
|
||||
getPossessions() {
|
||||
return this.itemTypes[TYPES.possession];
|
||||
return this.itemTypes[ITEM_TYPES.possession].find(it => it.system.possessionid == possessionId);
|
||||
}
|
||||
getEmpoignades() {
|
||||
return this.itemTypes[TYPES.empoignade];
|
||||
return this.itemTypes[ITEM_TYPES.empoignade];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -180,7 +196,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isEffectAllowed(effectId) { return true }
|
||||
isEffectAllowed(effectId) { return false }
|
||||
|
||||
getEffects(filter = e => true) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
|
||||
@@ -189,7 +205,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
getEffect(effectId) {
|
||||
return this.getEmbeddedCollection("ActiveEffect").find(it => it.statuses?.has(effectId));
|
||||
}
|
||||
|
||||
|
||||
async setEffect(effectId, status) {
|
||||
if (this.isEffectAllowed(effectId)) {
|
||||
const effect = this.getEffect(effectId);
|
||||
@@ -201,7 +217,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async removeEffect(id) {
|
||||
const effect = this.getEmbeddedCollection("ActiveEffect").find(it => it.id == id);
|
||||
if (effect) {
|
||||
@@ -286,18 +302,22 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
getCarac() {
|
||||
// TODO: le niveau d'une entité de cauchemar devrait être exclu...
|
||||
const carac = mergeObject(duplicate(this.system.carac),
|
||||
return foundry.utils.mergeObject(this.system.carac,
|
||||
{
|
||||
'reve-actuel': this.getCaracReveActuel(),
|
||||
'chance-actuelle': this.getCaracChanceActuelle()
|
||||
});
|
||||
return carac;
|
||||
},
|
||||
{ inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCarac(caracName, jetResistance = undefined) {
|
||||
if (Grammar.equalsInsensitive(caracName, 'taille')) {
|
||||
return
|
||||
}
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
let selectedCarac = this.getCaracByName(caracName)
|
||||
console.log("selectedCarac", selectedCarac)
|
||||
await this.openRollDialog({
|
||||
name: 'jet-' + caracName,
|
||||
label: 'Jet ' + Grammar.apostrophe('de', selectedCarac.label),
|
||||
@@ -318,19 +338,20 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollCompetence(idOrName, options = { tryTarget: true }) {
|
||||
async rollCompetence(idOrName, options = { tryTarget: true, arme: undefined }) {
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this)
|
||||
const competence = this.getCompetence(idOrName);
|
||||
let rollData = { carac: this.system.carac, competence: competence }
|
||||
if (competence.type == TYPES.competencecreature) {
|
||||
let rollData = { carac: this.system.carac, competence: competence, arme: options.arme }
|
||||
if (competence.type == ITEM_TYPES.competencecreature) {
|
||||
const token = RdDUtility.getSelectedToken(this)
|
||||
const arme = RdDItemCompetenceCreature.armeCreature(competence)
|
||||
if (arme && options.tryTarget && Targets.hasTargets()) {
|
||||
Targets.selectOneToken(target => {
|
||||
Targets.selectOneTargetToken(target => {
|
||||
if (arme.action == "possession") {
|
||||
RdDPossession.onAttaquePossession(target, this, competence)
|
||||
}
|
||||
else {
|
||||
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme)
|
||||
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme)
|
||||
}
|
||||
});
|
||||
return;
|
||||
@@ -360,9 +381,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
* @param {*} categorieArme catégorie d'attaque à utiliser: competence (== melee), lancer, tir; naturelle, possession
|
||||
* @returns
|
||||
*/
|
||||
rollArme(arme, categorieArme = "competence") {
|
||||
let compToUse = this.$getCompetenceArme(arme, categorieArme)
|
||||
if (!RdDItemArme.isArmeUtilisable(arme)) {
|
||||
rollArme(arme, categorieArme, token) {
|
||||
token = token ?? RdDUtility.getSelectedToken(this)
|
||||
const compToUse = this.$getCompetenceArme(arme, categorieArme)
|
||||
if (!RdDItemArme.isUtilisable(arme)) {
|
||||
ui.notifications.warn(`Arme inutilisable: ${arme.name} a une résistance de 0 ou moins`)
|
||||
return
|
||||
}
|
||||
@@ -375,13 +397,13 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
title: 'Ne pas utiliser les automatisation de combat',
|
||||
buttonLabel: "Pas d'automatisation",
|
||||
onAction: async () => {
|
||||
this.rollCompetence(compToUse, { tryTarget: false })
|
||||
this.rollCompetence(compToUse, { tryTarget: false, arme: arme })
|
||||
}
|
||||
});
|
||||
return
|
||||
}
|
||||
|
||||
Targets.selectOneToken(target => {
|
||||
Targets.selectOneTargetToken(target => {
|
||||
if (Targets.isTargetEntite(target)) {
|
||||
ui.notifications.warn(`Vous ne pouvez pas attaquer une entité non incarnée avec votre ${arme.name}!!!!`);
|
||||
return
|
||||
@@ -391,86 +413,74 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
if (competence.isCompetencePossession()) {
|
||||
return RdDPossession.onAttaquePossession(target, this, competence);
|
||||
}
|
||||
RdDCombat.rddCombatTarget(target, this).attaque(competence, arme);
|
||||
RdDCombat.rddCombatTarget(target, this, token).attaque(competence, arme);
|
||||
})
|
||||
}
|
||||
|
||||
$getCompetenceArme(arme, competenceName) {
|
||||
switch (arme.type) {
|
||||
case TYPES.competencecreature:
|
||||
return arme.name
|
||||
case TYPES.arme:
|
||||
switch (competenceName) {
|
||||
case 'competence': return arme.system.competence;
|
||||
case 'unemain': return RdDItemArme.competence1Mains(arme);
|
||||
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
|
||||
case 'tir': return arme.system.tir;
|
||||
case 'lancer': return arme.system.lancer;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return RdDItemArme.getCompetenceArme(arme, competenceName)
|
||||
}
|
||||
|
||||
verifierForceMin(item) {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
async resetItemUse() { }
|
||||
async incDecItemUse(itemId, inc = 1) { }
|
||||
getItemUse(itemId) { return 0; }
|
||||
verifierForceMin(item) { }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async encaisser() { await RdDEncaisser.encaisser(this) }
|
||||
|
||||
async encaisserDommages(rollData, attacker = undefined, show = undefined) {
|
||||
async encaisserDommages(rollData, attacker = undefined, show = undefined, attackerToken = undefined, defenderToken = undefined) {
|
||||
if (attacker && !await attacker.accorder(this, 'avant-encaissement')) {
|
||||
return;
|
||||
}
|
||||
const attackerId = attacker?.id;
|
||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr') && !game.user.isGM) {
|
||||
const armure = await this.computeArmure(rollData);
|
||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
||||
await this.encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken);
|
||||
}
|
||||
else {
|
||||
const jet = await RdDUtility.jetEncaissement(this, rollData, armure, { showDice: SHOW_DICE });
|
||||
await this.$onEncaissement(jet, show, attackerToken, defenderToken)
|
||||
}
|
||||
}
|
||||
|
||||
async encaisserDommagesValidationGR(rollData, armure, show, attackerToken, defenderToken) {
|
||||
if (!game.user.isGM) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
method: 'encaisserDommages',
|
||||
args: [rollData, show, attackerId]
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const armure = await this.computeArmure(rollData);
|
||||
if (ReglesOptionnelles.isUsing('validation-encaissement-gr')) {
|
||||
method: 'encaisserDommagesValidationGR',
|
||||
args: [rollData, armure, show, attackerToken, defenderToken]
|
||||
})
|
||||
} else {
|
||||
DialogValidationEncaissement.validerEncaissement(this, rollData, armure,
|
||||
jet => this.$onEncaissement(jet, show, attacker));
|
||||
}
|
||||
else {
|
||||
const jet = await RdDUtility.jetEncaissement(rollData, armure, { showDice: SHOW_DICE });
|
||||
await this.$onEncaissement(jet, show, attacker);
|
||||
jet => this.$onEncaissement(jet, show, attackerToken, defenderToken));
|
||||
}
|
||||
}
|
||||
|
||||
async $onEncaissement(jet, show, attacker) {
|
||||
await this.onAppliquerJetEncaissement(jet, attacker);
|
||||
await this.$afficherEncaissement(jet, show);
|
||||
async $onEncaissement(jet, show, attackerToken, defenderToken) {
|
||||
await this.onAppliquerJetEncaissement(jet, attackerToken);
|
||||
await this.$afficherEncaissement(jet, show, defenderToken);
|
||||
}
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attacker) { }
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) { }
|
||||
|
||||
async $afficherEncaissement(encaissement, show) {
|
||||
mergeObject(encaissement, {
|
||||
alias: this.name,
|
||||
async $afficherEncaissement(encaissement, show, defenderToken) {
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
alias: defenderToken?.name ?? this.name,
|
||||
hasPlayerOwner: this.hasPlayerOwner,
|
||||
show: show ?? {}
|
||||
});
|
||||
}, { overwrite: false });
|
||||
|
||||
await ChatUtility.createChatWithRollMode(this.name, {
|
||||
roll: encaissement.roll,
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
|
||||
});
|
||||
await ChatUtility.createChatWithRollMode(
|
||||
{
|
||||
roll: encaissement.roll,
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
|
||||
},
|
||||
this
|
||||
)
|
||||
|
||||
if (!encaissement.hasPlayerOwner && encaissement.endurance != 0) {
|
||||
encaissement = duplicate(encaissement);
|
||||
encaissement.isGM = true;
|
||||
encaissement = foundry.utils.duplicate(encaissement)
|
||||
encaissement.isGM = true
|
||||
ChatMessage.create({
|
||||
whisper: ChatMessage.getWhisperRecipients("GM"),
|
||||
whisper: ChatUtility.getGMs(),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-encaissement.html', encaissement)
|
||||
});
|
||||
}
|
||||
@@ -505,8 +515,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
|
||||
isEntiteAccordee(attacker) { return true }
|
||||
|
||||
async setEntiteReveAccordee(attacker) {
|
||||
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve");
|
||||
async setEntiteReveAccordee(actor) {
|
||||
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entité incarnée");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ export class RdDBaseActorSangSheet extends RdDBaseActorReveSheet {
|
||||
this.html.find('.creer-blessure-grave').click(async event => RdDItemBlessure.createBlessure(this.actor, 4));
|
||||
this.html.find('.creer-blessure-critique').click(async event => RdDItemBlessure.createBlessure(this.actor, 6));
|
||||
|
||||
this.html.find('.subir-blessure-contusion').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 2));
|
||||
this.html.find('.subir-blessure-legere').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 2));
|
||||
this.html.find('.subir-blessure-grave').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 4));
|
||||
this.html.find('.subir-blessure-critique').click(async event => RdDItemBlessure.applyFullBlessure(this.actor, 6));
|
||||
|
||||
this.html.find('.jet-vie').click(async event => this.actor.jetDeVie())
|
||||
this.html.find('.jet-endurance').click(async event => await this.jetEndurance())
|
||||
|
||||
@@ -34,8 +39,8 @@ export class RdDBaseActorSangSheet extends RdDBaseActorReveSheet {
|
||||
ChatMessage.create({
|
||||
content: `Jet d'Endurance : ${result.jetEndurance} / ${endurance}
|
||||
<br>${this.actor.name} a ${result.sonne ? 'échoué' : 'réussi'} son Jet d'Endurance ${result.sonne ? 'et devient Sonné' : ''}`,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.actor.name)
|
||||
});
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { MAX_ENDURANCE_FATIGUE, RdDUtility } from "../rdd-utility.js";
|
||||
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js";
|
||||
import { STATUSES } from "../settings/status-effects.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { RdDBaseActorReve } from "./base-actor-reve.js";
|
||||
import { RdDDice } from "../rdd-dice.js";
|
||||
import { RdDItemBlessure } from "../item/blessure.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
|
||||
/**
|
||||
* Classe de base pour les acteurs qui peuvent subir des blessures
|
||||
@@ -50,9 +51,9 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
|
||||
isDead() { return this.system.sante.vie.value < -this.getSConst() }
|
||||
|
||||
nbBlessuresLegeres() { return this.itemTypes[TYPES.blessure].filter(it => it.isLegere()).length }
|
||||
nbBlessuresGraves() { return this.itemTypes[TYPES.blessure].filter(it => it.isGrave()).length }
|
||||
nbBlessuresCritiques() { return this.itemTypes[TYPES.blessure].filter(it => it.isCritique()).length }
|
||||
nbBlessuresLegeres() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isLegere()).length }
|
||||
nbBlessuresGraves() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isGrave()).length }
|
||||
nbBlessuresCritiques() { return this.itemTypes[ITEM_TYPES.blessure].filter(it => it.isCritique()).length }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
computeResumeBlessure() {
|
||||
@@ -88,13 +89,13 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attacker) {
|
||||
const santeOrig = duplicate(this.system.sante);
|
||||
const blessure = await this.ajouterBlessure(encaissement, attacker); // Will update the result table
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) {
|
||||
const santeOrig = foundry.utils.duplicate(this.system.sante);
|
||||
const blessure = await this.ajouterBlessure(encaissement, attackerToken); // Will update the result table
|
||||
const perteVie = await this.santeIncDec("vie", -encaissement.vie);
|
||||
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance, blessure?.isCritique());
|
||||
|
||||
mergeObject(encaissement, {
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
resteEndurance: perteEndurance.newValue,
|
||||
sonne: perteEndurance.sonne,
|
||||
jetEndurance: perteEndurance.jetEndurance,
|
||||
@@ -108,7 +109,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
return;
|
||||
}
|
||||
const sante = duplicate(this.system.sante)
|
||||
const sante = foundry.utils.duplicate(this.system.sante)
|
||||
let compteur = sante[name];
|
||||
if (!compteur) {
|
||||
return;
|
||||
@@ -135,7 +136,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
result.perte = perte;
|
||||
if (perte > 1) {
|
||||
// Peut-être sonné si 2 points d'endurance perdus d'un coup
|
||||
mergeObject(result, await this.jetEndurance(result.newValue));
|
||||
foundry.utils.mergeObject(result, await this.jetEndurance(result.newValue));
|
||||
} else if (inc > 0) {
|
||||
await this.setSonne(false);
|
||||
}
|
||||
@@ -168,7 +169,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ajouterBlessure(encaissement, attacker = undefined) {
|
||||
async ajouterBlessure(encaissement, attackerToken = undefined) {
|
||||
if (encaissement.gravite < 0) return;
|
||||
if (encaissement.gravite > 0) {
|
||||
while (this.countBlessures(it => it.system.gravite == encaissement.gravite) >= RdDItemBlessure.maxBlessures(encaissement.gravite) && encaissement.gravite <= 6) {
|
||||
@@ -180,7 +181,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
}
|
||||
}
|
||||
const endActuelle = this.getEnduranceActuelle();
|
||||
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg.loc.label, attacker);
|
||||
const blessure = await RdDItemBlessure.createBlessure(this, encaissement.gravite, encaissement.dmg?.loc.label ?? '', attackerToken);
|
||||
if (blessure.isCritique()) {
|
||||
encaissement.endurance = endActuelle;
|
||||
}
|
||||
@@ -196,20 +197,30 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
return blessure;
|
||||
}
|
||||
|
||||
async supprimerBlessure({ gravite }) {
|
||||
const toDelete = this.itemTypes[ITEM_TYPES.blessure].find(it => it.system.gravite == gravite)?.id
|
||||
if (toDelete) {
|
||||
await this.deleteEmbeddedDocuments('Item', [toDelete]);
|
||||
}
|
||||
}
|
||||
|
||||
async supprimerBlessures(filterToDelete) {
|
||||
const toDelete = this.filterItems(filterToDelete, TYPES.blessure)
|
||||
const toDelete = this.filterItems(filterToDelete, ITEM_TYPES.blessure)
|
||||
.map(it => it.id);
|
||||
await this.deleteEmbeddedDocuments('Item', toDelete);
|
||||
}
|
||||
|
||||
countBlessures(filter = it => !it.isContusion()) {
|
||||
return this.filterItems(filter, 'blessure').length
|
||||
return this.filterItems(filter, ITEM_TYPES.blessure).length
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async jetDeVie() {
|
||||
if (this.isDead()) {
|
||||
ChatMessage.create({ content: `Jet de Vie: ${this.name} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`, whisper: ChatMessage.getWhisperRecipients(this.name) });
|
||||
ChatMessage.create({
|
||||
content: `Jet de Vie: ${this.name} est déjà mort, ce n'est pas la peine d'en rajouter !!!!!`,
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
})
|
||||
return
|
||||
}
|
||||
const jetDeVie = await RdDDice.roll("1d20");
|
||||
@@ -236,7 +247,10 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
else if (prochainJet > 0) {
|
||||
msgText += `<br>Prochain jet de vie dans ${prochainJet} ${isCritique ? 'round' : 'minute'}${prochainJet > 1 ? 's' : ''} ${isCritique ? '(état critique)' : '(état grave)'}`
|
||||
}
|
||||
ChatMessage.create({ content: msgText, whisper: ChatMessage.getWhisperRecipients(this.name) });
|
||||
ChatMessage.create({
|
||||
content: msgText,
|
||||
whisper: ChatUtility.getOwners(this)
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -262,13 +276,15 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
ui.notifications.info(`${this.name} est hors combat, il ne reste donc pas sonné`);
|
||||
return;
|
||||
}
|
||||
await this.setEffect(STATUSES.StatusStunned, sonne);
|
||||
await this.setEffect(STATUSES.StatusStunned, sonne)
|
||||
}
|
||||
|
||||
getSonne() {
|
||||
return this.getEffect(STATUSES.StatusStunned);
|
||||
isSonne() {
|
||||
return this.getEffect(STATUSES.StatusStunned)
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) { return true }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async computeEtatGeneral() { this.system.compteurs.etat.value = this.malusVie() + this.malusFatigue() + this.malusEthylisme() }
|
||||
getEtatGeneral(options = { ethylisme: false }) { return this.system.compteurs.etat.value }
|
||||
|
||||
@@ -3,7 +3,7 @@ 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 { RdDItem, ITEM_TYPES } from "../item.js";
|
||||
import { RdDItemCompetenceCreature } from "../item-competencecreature.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -15,12 +15,12 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(ActorSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(ActorSheet.defaultOptions, {
|
||||
classes: ["rdd", "sheet", "actor"],
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }],
|
||||
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: undefined }],
|
||||
vueDetaillee: false
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -37,7 +37,8 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
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)
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.actor, this.isEditable),
|
||||
effects: this.actor.effects
|
||||
}
|
||||
|
||||
RdDBaseActorSheet.filterItemsPerTypeForSheet(formData, this.actor.itemTypes);
|
||||
@@ -50,7 +51,7 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
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)
|
||||
formData.competences.filter(it => it.type == ITEM_TYPES.competencecreature)
|
||||
.forEach(it => it.isdommages = RdDItemCompetenceCreature.isDommages(it))
|
||||
return formData;
|
||||
}
|
||||
@@ -312,7 +313,7 @@ export class RdDBaseActorSheet extends ActorSheet {
|
||||
async _onSplitItem(item, split) {
|
||||
if (split >= 1 && split < item.system.quantite) {
|
||||
await item.diminuerQuantite(split);
|
||||
const splitItem = duplicate(item);
|
||||
const splitItem = foundry.utils.duplicate(item);
|
||||
splitItem.system.quantite = split;
|
||||
await this.actor.createEmbeddedDocuments('Item', [splitItem])
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { ChatVente } from "../achat-vente/chat-vente.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { SYSTEM_SOCKET_ID } from "../constants.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { Monnaie } from "../item-monnaie.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDAudio } from "../rdd-audio.js";
|
||||
import { RdDConfirm } from "../rdd-confirm.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "../sommeil/app-astrologie.js";
|
||||
|
||||
export class RdDBaseActor extends Actor {
|
||||
|
||||
@@ -16,7 +16,7 @@ export class RdDBaseActor extends Actor {
|
||||
return Object.entries(carac)
|
||||
.filter(it => Grammar.equalsInsensitive(it[1].label, name))
|
||||
.map(it => it[0])
|
||||
.find(it => it);
|
||||
.find(it => it)
|
||||
}
|
||||
static $findCaracByName(carac, name) {
|
||||
const caracList = Object.entries(carac);
|
||||
@@ -32,23 +32,16 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
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));
|
||||
Hooks.on("preUpdateItem", (item, change, options, id) => Misc.documentIfResponsible(item.parent)?.onPreUpdateItem(item, change, options, id))
|
||||
Hooks.on("createItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onCreateItem(item, options, id))
|
||||
Hooks.on("deleteItem", (item, options, id) => Misc.documentIfResponsible(item.parent)?.onDeleteItem(item, options, id))
|
||||
Hooks.on("updateActor", (actor, change, options, actorId) => Misc.documentIfResponsible(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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,11 +78,9 @@ export class RdDBaseActor extends Actor {
|
||||
return game.actors.get(actorId)
|
||||
}
|
||||
|
||||
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
|
||||
isPersonnageJoueur() { return false }
|
||||
|
||||
static getParentActor(document) {
|
||||
return document?.parent instanceof Actor ? document.parent : undefined
|
||||
}
|
||||
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
|
||||
|
||||
/**
|
||||
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
|
||||
@@ -121,7 +112,7 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
constructor(docData, context = {}) {
|
||||
if (!context.rdd?.ready) {
|
||||
mergeObject(context, { rdd: { ready: true } });
|
||||
foundry.utils.mergeObject(context, { rdd: { ready: true } });
|
||||
const ActorConstructor = game.system.rdd.actorClasses[docData.type];
|
||||
if (ActorConstructor) {
|
||||
if (!docData.img) {
|
||||
@@ -130,6 +121,7 @@ export class RdDBaseActor extends Actor {
|
||||
return new ActorConstructor(docData, context);
|
||||
}
|
||||
}
|
||||
context.rdd = undefined
|
||||
super(docData, context);
|
||||
}
|
||||
|
||||
@@ -213,11 +205,8 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
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) {
|
||||
@@ -226,7 +215,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
async creerObjetParMJ(object) {
|
||||
if (!Misc.isUniqueConnectedGM()) {
|
||||
if (!Misc.isFirstConnectedGM()) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
tokenId: this.token?.id,
|
||||
actorId: this.id,
|
||||
@@ -240,11 +229,13 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async cleanupConteneurs() {
|
||||
let updates = this.itemTypes['conteneur']
|
||||
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
|
||||
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
|
||||
if (updates.length > 0) {
|
||||
await this.updateEmbeddedDocuments("Item", updates)
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this)) {
|
||||
let updates = this.itemTypes['conteneur']
|
||||
.filter(c => c.system.contenu.filter(id => this.getItem(id) == undefined).length > 0)
|
||||
.map(c => { return { _id: c._id, 'system.contenu': c.system.contenu.filter(id => this.getItem(id) != undefined) } });
|
||||
if (updates.length > 0) {
|
||||
await this.updateEmbeddedDocuments("Item", updates)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +267,7 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
let fortune = this.getFortune();
|
||||
console.log("payer", game.user.character, depense, fortune);
|
||||
// TODO: passer en handlebars
|
||||
let msg = "";
|
||||
if (fortune >= depense) {
|
||||
await Monnaie.optimiserFortune(this, fortune - depense);
|
||||
@@ -285,11 +277,10 @@ export class RdDBaseActor extends Actor {
|
||||
msg = "Vous n'avez pas assez d'argent pour payer cette somme !";
|
||||
}
|
||||
|
||||
let message = {
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: msg
|
||||
};
|
||||
ChatMessage.create(message);
|
||||
})
|
||||
}
|
||||
|
||||
async depenserSols(sols) {
|
||||
@@ -323,7 +314,7 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
RdDAudio.PlayContextAudio("argent"); // Petit son
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: `Vous avez reçu <strong>${sols} Sols</strong> ${fromActor ? " de " + fromActor.name : ''}, qui ont été ajoutés à votre argent.`
|
||||
});
|
||||
}
|
||||
@@ -341,7 +332,7 @@ export class RdDBaseActor extends Actor {
|
||||
ui.notifications.info("Inutile de se vendre à soi-même");
|
||||
return;
|
||||
}
|
||||
if (!Misc.isUniqueConnectedGM()) {
|
||||
if (!Misc.isFirstConnectedGM()) {
|
||||
RdDBaseActor.remoteActorCall({
|
||||
actorId: achat.vendeurId ?? achat.acheteurId,
|
||||
method: 'achatVente',
|
||||
@@ -366,43 +357,42 @@ export class RdDBaseActor extends Actor {
|
||||
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);
|
||||
}
|
||||
await vendeur?.vendre(itemVendu, quantite, cout);
|
||||
await acheteur?.acheter(itemVendu, quantite, cout, achat)
|
||||
|
||||
if (cout > 0) {
|
||||
RdDAudio.PlayContextAudio("argent");
|
||||
}
|
||||
const chatAchatItem = duplicate(achat.vente);
|
||||
const chatAchatItem = foundry.utils.duplicate(achat.vente);
|
||||
chatAchatItem.quantiteTotal = quantite;
|
||||
ChatMessage.create({
|
||||
user: achat.userId,
|
||||
speaker: { alias: (acheteur ?? vendeur).name },
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(this),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-achat-item.html', chatAchatItem)
|
||||
});
|
||||
|
||||
if (!achat.vente.quantiteIllimite) {
|
||||
if (achat.vente.quantiteNbLots <= achat.choix.nombreLots) {
|
||||
if (achat.vente.nbLots <= 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);
|
||||
await ChatVente.diminuerQuantiteAchatVente(achat.chatMessageIdVente, achat.choix.nombreLots)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async decrementerVente(vendeur, itemVendu, quantite, cout) {
|
||||
if (vendeur) {
|
||||
await vendeur.ajouterSols(cout);
|
||||
await vendeur.decrementerQuantiteItem(itemVendu, quantite);
|
||||
async vendre(item, quantite, cout) {
|
||||
await this.ajouterSols(cout);
|
||||
await this.decrementerQuantiteItem(item, quantite);
|
||||
}
|
||||
|
||||
async acheter(item, quantite, cout, achat) {
|
||||
await this.depenserSols(cout)
|
||||
const createdItemId = await this.creerQuantiteItem(item, quantite)
|
||||
if (achat.choix.consommer && item.type == 'nourritureboisson' && createdItemId != undefined) {
|
||||
achat.choix.doses = achat.choix.nombreLots;
|
||||
await this.consommerNourritureboisson(createdItemId, achat.choix, achat.vente.actingUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,31 +405,28 @@ export class RdDBaseActor extends Actor {
|
||||
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 consommerNourritureboisson(itemId, choix, userId) { }
|
||||
|
||||
async decrementerQuantiteItem(item, quantite, options = { supprimerSiZero: true }) {
|
||||
if (item.isService()) {
|
||||
return;
|
||||
}
|
||||
const itemId = item.id;
|
||||
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 }]);
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: itemId, '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) {
|
||||
const realItem = this.getItem(item.id)
|
||||
realItem.update({ 'system.quantite': resteQuantite });
|
||||
await this.updateEmbeddedDocuments("Item", [{ _id: item.id, 'system.quantite': resteQuantite }]);
|
||||
}
|
||||
}
|
||||
@@ -451,7 +438,7 @@ export class RdDBaseActor extends Actor {
|
||||
type: item.type,
|
||||
img: item.img,
|
||||
name: item.name,
|
||||
system: mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined })
|
||||
system: foundry.utils.mergeObject(item.system, { quantite: isItemEmpilable ? quantite : undefined }, { inplace: false })
|
||||
};
|
||||
const newItems = isItemEmpilable ? [baseItem] : Array.from({ length: quantite }, (_, i) => baseItem);
|
||||
const items = await this.createEmbeddedDocuments("Item", newItems);
|
||||
@@ -552,7 +539,7 @@ export class RdDBaseActor extends Actor {
|
||||
// Calculer le total actuel des contenus
|
||||
const encContenu = dest.getEncContenu();
|
||||
const newEnc = moved.getEncTotal(); // Calculer le total actuel du nouvel objet
|
||||
const placeDisponible = Math.roundDecimals(dest.system.capacite - encContenu - newEnc, 4)
|
||||
const placeDisponible = Misc.keepDecimals(dest.system.capacite - encContenu - newEnc, 4)
|
||||
|
||||
// Teste si le conteneur de destination a suffisament de capacité pour recevoir le nouvel objet
|
||||
if (placeDisponible < 0) {
|
||||
@@ -567,15 +554,15 @@ export class RdDBaseActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
/** 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()) {
|
||||
if (conteneur?.isConteneur()) {
|
||||
item.estContenu = true;
|
||||
const nouveauContenu = [...conteneur.system.contenu, item.id];
|
||||
await conteneur.update({ 'system.contenu': nouveauContenu });
|
||||
onAjouterDansConteneur(item.id, conteneur.id);
|
||||
onAjouterDansConteneur(item.id, conteneur.id)
|
||||
}
|
||||
else {
|
||||
item.estContenu = false;
|
||||
await conteneur?.update({ 'system.-=contenu': undefined })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -593,8 +580,13 @@ export class RdDBaseActor extends Actor {
|
||||
if (item.estContenu) {
|
||||
item.estContenu = undefined;
|
||||
}
|
||||
if (item.type == 'conteneur' && item.system.contenu.length > 0) {
|
||||
corrections.push({ _id: item.id, 'system.contenu': [] });
|
||||
if (item.system.contenu != undefined) {
|
||||
if (item.type == 'conteneur') {
|
||||
corrections.push({ _id: item.id, 'system.contenu': [] });
|
||||
}
|
||||
else {
|
||||
corrections.push({ _id: item.id, 'system.-=contenu': undefined });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (corrections.length > 0) {
|
||||
@@ -629,15 +621,21 @@ export class RdDBaseActor extends Actor {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/** Supprime un item d'un conteneur, sur la base
|
||||
* de leurs ID */
|
||||
/**
|
||||
* Supprime un item d'un conteneur, sur la base de leurs ID
|
||||
*/
|
||||
async enleverDeConteneur(item, conteneur, onEnleverDeConteneur) {
|
||||
if (conteneur?.isConteneur()) {
|
||||
item.estContenu = false;
|
||||
const contenu = conteneur.system.contenu.filter(id => id != item.id);
|
||||
await conteneur.update({ 'system.contenu': contenu });
|
||||
onEnleverDeConteneur();
|
||||
if (conteneur) {
|
||||
if (conteneur.isConteneur()) {
|
||||
const contenu = conteneur.system.contenu.filter(id => id != item.id);
|
||||
await conteneur.update({ 'system.contenu': contenu });
|
||||
onEnleverDeConteneur();
|
||||
}
|
||||
else {
|
||||
await conteneur.update({ 'system.-=contenu': undefined })
|
||||
}
|
||||
}
|
||||
item.estContenu = false;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -647,7 +645,7 @@ export class RdDBaseActor extends Actor {
|
||||
sourceActor.buildSubConteneurObjetList(itemId, itemsList); // Get itemId list
|
||||
|
||||
const itemsDataToCreate = itemsList.map(it => sourceActor.getItem(it.id))
|
||||
.map(it => duplicate(it))
|
||||
.map(it => foundry.utils.duplicate(it))
|
||||
.map(it => { it.system.contenu = []; return it; });
|
||||
let newItems = await this.createEmbeddedDocuments('Item', itemsDataToCreate);
|
||||
|
||||
@@ -703,9 +701,28 @@ export class RdDBaseActor extends Actor {
|
||||
|
||||
async actionPrincipale(item, onActionItem = async () => { }) {
|
||||
switch (item.type) {
|
||||
case TYPES.conteneur: return await item.sheet.render(true);
|
||||
case ITEM_TYPES.conteneur: return await item.sheet.render(true);
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
async resetItemUse() { }
|
||||
async incDecItemUse(itemId, inc = 1) { }
|
||||
getItemUse(itemId) { return 0; }
|
||||
async finDeRound(options = { terminer: false }) { }
|
||||
isActorCombat() { return false }
|
||||
getCaracInit(competence) { return 0 }
|
||||
listActionsCombat() { return [] }
|
||||
listActionsPossessions() {
|
||||
return this.itemTypes[ITEM_TYPES.possession]
|
||||
.map(p => {
|
||||
return {
|
||||
name: p.name,
|
||||
action: 'possession',
|
||||
system: {
|
||||
competence: p.name,
|
||||
possessionid: p.system.possessionid,
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DialogItemAchat } from "../dialog-item-achat.js";
|
||||
import { DialogItemAchat } from "../achat-vente/dialog-item-achat.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { RdDBaseActorSheet } from "./base-actor-sheet.js";
|
||||
@@ -11,11 +11,11 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/commerce-actor-sheet.html",
|
||||
width: 600, height: 720,
|
||||
tabs: []
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
get title() {
|
||||
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
|
||||
@@ -27,7 +27,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
if (this.actor.token && this.actor.token != this.actor.prototypeToken) {
|
||||
mergeObject(formData,
|
||||
foundry.utils.mergeObject(formData,
|
||||
{
|
||||
title: this.actor.token.name,
|
||||
token: {
|
||||
|
||||
@@ -25,8 +25,7 @@ export class RdDCommerce extends RdDBaseActor {
|
||||
}
|
||||
await super.depenserSols(cout)
|
||||
}
|
||||
|
||||
async consommerNourritureAchetee(achat, vente, createdItemId) {
|
||||
async consommerNourritureboisson(itemId, choix, userId) {
|
||||
// ne pas consommer pour un commerce
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ export class RdDCreatureSheet extends RdDBaseActorSangSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDBaseActorSangSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDBaseActorSangSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html",
|
||||
width: 640, height: 720
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ENTITE_INCARNE } from "../constants.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { STATUSES } from "../settings/status-effects.js";
|
||||
import { RdDBaseActorSang } from "./base-actor-sang.js";
|
||||
|
||||
@@ -12,7 +12,7 @@ export class RdDCreature extends RdDBaseActorSang {
|
||||
isCreature() { return true }
|
||||
|
||||
canReceive(item) {
|
||||
return item.type == TYPES.competencecreature || item.isInventaire();
|
||||
return item.type == ITEM_TYPES.competencecreature || item.isInventaire();
|
||||
}
|
||||
|
||||
async remiseANeuf() {
|
||||
@@ -33,31 +33,4 @@ export class RdDCreature extends RdDBaseActorSang {
|
||||
}
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) {
|
||||
return [STATUSES.StatusComma].includes(effectId);
|
||||
}
|
||||
|
||||
isEntiteAccordee(attacker) {
|
||||
if (this.isEntite([ENTITE_INCARNE])) {
|
||||
let resonnance = this.system.sante.resonnance
|
||||
return (resonnance.actors.find(it => it == attacker.id))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setEntiteReveAccordee(attacker) {
|
||||
if (this.isEntite([ENTITE_INCARNE])) {
|
||||
let resonnance = duplicate(this.system.sante.resonnance);
|
||||
if (resonnance.actors.find(it => it == attacker.id)) {
|
||||
// déjà accordé
|
||||
return;
|
||||
}
|
||||
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
|
||||
}
|
||||
else {
|
||||
super.setEntiteReveAccordee(attacker)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDBaseActorReveSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html",
|
||||
width: 640, height: 720,
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
async getData() {
|
||||
@@ -54,6 +54,12 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
|
||||
});
|
||||
}
|
||||
|
||||
async _onDropActor(event, dragData) {
|
||||
const dropActor = fromUuidSync(dragData.uuid)
|
||||
await this.actor.setEntiteReveAccordee(dropActor)
|
||||
super._onDropActor(event, dragData)
|
||||
}
|
||||
|
||||
async deleteSubActeur(actorId) {
|
||||
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
|
||||
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ENTITE_INCARNE, ENTITE_NONINCARNE } from "../constants.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDEncaisser } from "../rdd-roll-encaisser.js";
|
||||
import { STATUSES } from "../settings/status-effects.js";
|
||||
@@ -12,7 +12,7 @@ export class RdDEntite extends RdDBaseActorReve {
|
||||
}
|
||||
|
||||
canReceive(item) {
|
||||
return item.type == TYPES.competencecreature
|
||||
return item.type == ITEM_TYPES.competencecreature
|
||||
}
|
||||
|
||||
isEntite(typeentite = []) {
|
||||
@@ -29,7 +29,7 @@ export class RdDEntite extends RdDBaseActorReve {
|
||||
getChance() { return this.getReve() }
|
||||
|
||||
getDraconicOuPossession() {
|
||||
return this.itemTypes[TYPES.competencecreature]
|
||||
return this.itemTypes[ITEM_TYPES.competencecreature]
|
||||
.filter(it => it.system.categorie == 'possession')
|
||||
.sort(Misc.descending(it => it.system.niveau))
|
||||
.find(it => true);
|
||||
@@ -67,16 +67,16 @@ export class RdDEntite extends RdDBaseActorReve {
|
||||
if (this.isNonIncarnee()) {
|
||||
return
|
||||
}
|
||||
await RdDEncaisser.encaisser(this)
|
||||
await RdDEncaisser.encaisser(this)
|
||||
}
|
||||
|
||||
isEffectAllowed(effectId) {
|
||||
return [STATUSES.StatusComma].includes(effectId);
|
||||
}
|
||||
|
||||
async onAppliquerJetEncaissement(encaissement, attacker) {
|
||||
async onAppliquerJetEncaissement(encaissement, attackerToken) {
|
||||
const perteEndurance = await this.santeIncDec("endurance", -encaissement.endurance);
|
||||
mergeObject(encaissement, {
|
||||
foundry.utils.mergeObject(encaissement, {
|
||||
resteEndurance: perteEndurance.newValue,
|
||||
endurance: perteEndurance.perte
|
||||
});
|
||||
@@ -91,20 +91,16 @@ export class RdDEntite extends RdDBaseActorReve {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setEntiteReveAccordee(attacker) {
|
||||
async setEntiteReveAccordee(actor) {
|
||||
if (this.isEntite([ENTITE_INCARNE])) {
|
||||
let resonnance = duplicate(this.system.sante.resonnance);
|
||||
if (resonnance.actors.find(it => it == attacker.id)) {
|
||||
if (this.system.sante.resonnance.actors.find(it => it == actor.id)) {
|
||||
// déjà accordé
|
||||
return;
|
||||
return
|
||||
}
|
||||
resonnance.actors.push(attacker.id);
|
||||
await this.update({ "system.sante.resonnance": resonnance });
|
||||
await this.update({ "system.sante.resonnance.actors": [...this.system.sante.resonnance.actors, actor.id] })
|
||||
}
|
||||
else {
|
||||
super.setEntiteReveAccordee(attacker)
|
||||
super.setEntiteReveAccordee(actor)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export const XP_TOPIC = {
|
||||
export class ExperienceLog {
|
||||
|
||||
static async add(actor, topic, from, to, raison, manuel = false) {
|
||||
if (!actor.hasPlayerOwner || !actor.isPersonnage()) {
|
||||
if (!actor.isPersonnageJoueur()) {
|
||||
return
|
||||
}
|
||||
if (from == to) {
|
||||
|
||||
115
module/actor/export-scriptarium/actor-encart-sheet.js
Normal file
115
module/actor/export-scriptarium/actor-encart-sheet.js
Normal file
@@ -0,0 +1,115 @@
|
||||
import { RdDActorSheet } from "../../actor-sheet.js"
|
||||
import { SYSTEM_RDD } from "../../constants.js";
|
||||
import { Misc } from "../../misc.js";
|
||||
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js";
|
||||
import { ExportScriptarium } from "./export-scriptarium.js";
|
||||
import { CATEGORIES_COMPETENCES, CATEGORIES_DRACONIC, Mapping } from "./mapping.js";
|
||||
|
||||
export class RdDActorExportSheet extends RdDActorSheet {
|
||||
static async init() {
|
||||
await loadTemplates([
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/arme.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessure.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/blessures.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-compteur.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/carac-derivee-compteur.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/competences.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/esquive.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/fatigue.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/protection.hbs",
|
||||
"systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/sort.hbs",
|
||||
])
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorExportSheet, { types: ["personnage"], makeDefault: false, label: "Feuille simplifiée" })
|
||||
}
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(RdDActorSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/export-scriptarium/actor-encart-sheet.hbs",
|
||||
width: 550,
|
||||
showCompNiveauBase: false,
|
||||
vueArchetype: false,
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor(actor, options) {
|
||||
super(actor, options)
|
||||
}
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData()
|
||||
// Add any structured, precomputed list of data
|
||||
formData.context = Mapping.prepareContext(this.actor)
|
||||
formData.export = this.getMappingValues(formData.context, this.actor)
|
||||
formData.competences = this.getCompetences(CATEGORIES_COMPETENCES)
|
||||
formData.draconic = this.getCompetences(CATEGORIES_DRACONIC)
|
||||
const legeres = this.actor.nbBlessuresLegeres()
|
||||
const graves = this.actor.nbBlessuresGraves()
|
||||
const critiques = this.actor.nbBlessuresCritiques()
|
||||
formData.etat = {
|
||||
surenc: this.actor.computeMalusSurEncombrement(),
|
||||
fatigue: {
|
||||
value: this.actor.getFatigueActuelle(),
|
||||
max: this.actor.getFatigueMax(),
|
||||
malus: this.actor.malusFatigue()
|
||||
},
|
||||
blessures: legeres + graves + critiques,
|
||||
blessure: [legeres > 0, legeres > 1, legeres > 2, legeres > 3, legeres > 4, graves > 0, graves > 1, critiques > 0],
|
||||
}
|
||||
formData.options.exportScriptarium = OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM)
|
||||
return formData
|
||||
}
|
||||
|
||||
getMappingValues(context, actor) {
|
||||
return Object.fromEntries(Mapping.getMapping().map(it => [it.column, {
|
||||
colName: it.colName ?? it.column,
|
||||
column: it.column,
|
||||
rollClass: it.rollClass,
|
||||
value: String(it.getter(actor, context))
|
||||
}]))
|
||||
}
|
||||
|
||||
getCompetences(categories) {
|
||||
const competences = Mapping.getCompetencesCategorie(this.actor, categories)
|
||||
if (competences.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
|
||||
const listByCategories = Object.values(byCategories)
|
||||
.map(it => it.competencesParNiveau)
|
||||
.map(byNiveau => {
|
||||
const niveaux = Object.keys(byNiveau).map(it => Number(it)).sort(Misc.ascending())
|
||||
if (niveaux.length == 0) {
|
||||
return undefined
|
||||
}
|
||||
const listCategorieByNiveau = niveaux.map(niveau => {
|
||||
const list = byNiveau[niveau].sort(Misc.ascending(it => it.name))
|
||||
return { niveau, list }
|
||||
})
|
||||
return Misc.concat(listCategorieByNiveau)
|
||||
}).filter(it => it != undefined)
|
||||
|
||||
return Misc.concat(listByCategories)
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
this.html.find('.click-blessure-remove').click(async event =>
|
||||
await this.actor.supprimerBlessure({
|
||||
gravite: this.html.find(event.currentTarget).data('gravite')
|
||||
})
|
||||
)
|
||||
this.html.find('.click-blessure-add').click(async event =>
|
||||
await this.actor.ajouterBlessure({
|
||||
gravite: this.html.find(event.currentTarget).data('gravite')
|
||||
// event.currentTarget.attributes['data-gravite'].value
|
||||
})
|
||||
)
|
||||
this.html.find('.button-export').click(async event => {
|
||||
ExportScriptarium.INSTANCE.exportActors([this.actor],
|
||||
`${this.actor.uuid}-${this.actor.name}`
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
78
module/actor/export-scriptarium/export-scriptarium.js
Normal file
78
module/actor/export-scriptarium/export-scriptarium.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import { ACTOR_TYPES } from "../../item.js"
|
||||
import { Misc } from "../../misc.js"
|
||||
import { EXPORT_CSV_SCRIPTARIUM, OptionsAvancees } from "../../settings/options-avancees.js"
|
||||
import { Mapping } from "./mapping.js"
|
||||
|
||||
const IMG_SCRIPTARIUM = '<img class="context-menu-img" src="systems/foundryvtt-reve-de-dragon/styles/img/ui/scriptarium.svg">'
|
||||
|
||||
export class ExportScriptarium {
|
||||
|
||||
static init() {
|
||||
ExportScriptarium.INSTANCE = new ExportScriptarium()
|
||||
}
|
||||
|
||||
constructor() {
|
||||
Hooks.on("getActorDirectoryFolderContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
|
||||
Hooks.on("getActorDirectoryEntryContext", (actorDirectory, menus) => { ExportScriptarium.INSTANCE.onActorDirectoryMenu(actorDirectory, menus) })
|
||||
}
|
||||
|
||||
onActorDirectoryMenu(actorDirectory, menus) {
|
||||
menus.push({
|
||||
name: 'Export Personnages <i class="fa-regular fa-file-csv"></i>',
|
||||
icon: IMG_SCRIPTARIUM,
|
||||
condition: (target) => game.user.isGM &&
|
||||
OptionsAvancees.isUsing(EXPORT_CSV_SCRIPTARIUM) &&
|
||||
this.$getActors(actorDirectory, target).length > 0,
|
||||
callback: target => this.exportActors(this.$getActors(actorDirectory, target), this.$getTargetName(actorDirectory, target))
|
||||
})
|
||||
}
|
||||
|
||||
$getTargetName(actorDirectory, target) {
|
||||
const li = target.closest(".directory-item")
|
||||
const folderId = li.data("folderId")
|
||||
const actorId = li.data("documentId")
|
||||
return actorId
|
||||
? game.actors.get(actorId).name
|
||||
: actorDirectory.folders.find(it => it.id == folderId).name
|
||||
}
|
||||
|
||||
$getActors(actorDirectory, target) {
|
||||
const li = target.closest(".directory-item")
|
||||
const folderId = li.data("folderId")
|
||||
const actorId = li.data("documentId")
|
||||
const actors = actorId
|
||||
? [game.actors.get(actorId)]
|
||||
: folderId
|
||||
? actorDirectory.folders.find(it => it.id == folderId).contents
|
||||
: []
|
||||
return actors.filter(it => it.type == ACTOR_TYPES.personnage)
|
||||
}
|
||||
|
||||
exportActors(actors, targetName) {
|
||||
const eol = '\n\r'
|
||||
const header = Misc.join(this.getHeaderLine(), ';')
|
||||
const actorLines = actors.map(actor => Misc.join(this.getActorLine(actor), ';'))
|
||||
const data = Misc.join([header, ...actorLines], eol)
|
||||
const filename = `scriptarium-${targetName?.slugify()}.csv`;
|
||||
saveDataToFile(data, "text/csv;charset=windows-1252", `${filename}`);
|
||||
}
|
||||
|
||||
getHeaderLine() {
|
||||
return Mapping.getColumns()
|
||||
}
|
||||
|
||||
getActorLine(actor) {
|
||||
const values = Mapping.getValues(actor)
|
||||
return values
|
||||
.map(it => this.$escapeQuotes(it))
|
||||
.map(it => it.replaceAll("\n", " ").replaceAll("\r", ""))
|
||||
}
|
||||
|
||||
$escapeQuotes(it) {
|
||||
it = '' + it
|
||||
if (it.includes('"') || it.includes(';')) {
|
||||
return `"${it.replaceAll('"', '\\"')}"`
|
||||
}
|
||||
return it
|
||||
}
|
||||
}
|
||||
384
module/actor/export-scriptarium/mapping.js
Normal file
384
module/actor/export-scriptarium/mapping.js
Normal file
@@ -0,0 +1,384 @@
|
||||
import { Grammar } from "../../grammar.js"
|
||||
import { RdDItemArme } from "../../item-arme.js"
|
||||
import { RdDItemCompetence } from "../../item-competence.js"
|
||||
import { RdDItemSort } from "../../item-sort.js"
|
||||
import { ITEM_TYPES } from "../../item.js"
|
||||
import { Misc } from "../../misc.js"
|
||||
import { RdDTimestamp } from "../../time/rdd-timestamp.js"
|
||||
import { RdDBonus } from "../../rdd-bonus.js"
|
||||
import { TMRType } from "../../tmr-utility.js"
|
||||
|
||||
|
||||
export const CATEGORIES_COMPETENCES = [
|
||||
"generale",
|
||||
"particuliere",
|
||||
"specialisee",
|
||||
"connaissance",
|
||||
]
|
||||
export const CATEGORIES_DRACONIC = [
|
||||
"draconic",
|
||||
]
|
||||
|
||||
const CATEGORIES_COMBAT = [
|
||||
"melee",
|
||||
"tir",
|
||||
"lancer"
|
||||
]
|
||||
|
||||
const NIVEAU_BASE = {
|
||||
"generale": -4,
|
||||
"particuliere": -8,
|
||||
"specialisee": -11,
|
||||
"connaissance": -11,
|
||||
"draconic": -11,
|
||||
"melee": -6,
|
||||
"tir": -8,
|
||||
"lancer": -8,
|
||||
}
|
||||
|
||||
class ColumnMappingFactory {
|
||||
static createMappingArme(part, i) {
|
||||
return { column: `arme_${part}_${i}`, getter: (actor, context) => Mapping.getArme(actor, context, part, i) }
|
||||
}
|
||||
|
||||
static createMappingSort(part, i) {
|
||||
return { column: `sort_${part}_${i}`, getter: (actor, context) => Mapping.getSort(actor, context, part, i) }
|
||||
}
|
||||
}
|
||||
|
||||
const NB_ARMES = 10
|
||||
const NB_SORTS = 20
|
||||
const TABLEAU_ARMES = [...Array(NB_ARMES).keys()]
|
||||
const TABLEAU_SORTS = [...Array(NB_SORTS).keys()]
|
||||
|
||||
const MAPPING_BASE = [
|
||||
{ column: "ID", colName: 'ID', getter: (actor, context) => actor.id },
|
||||
{ column: "name", getter: (actor, context) => actor.name },
|
||||
{ column: "metier", colName: 'Métier', getter: (actor, context) => actor.system.metier },
|
||||
{ column: "biographie", colName: 'Biographie', getter: (actor, context) => actor.system.biographie },
|
||||
{ column: "taille", getter: (actor, context) => actor.system.carac.taille.value },
|
||||
{ column: "apparence", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.apparence.value },
|
||||
{ column: "constitution", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.constitution.value },
|
||||
{ column: "force", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.force.value },
|
||||
{ column: "agilite", rollClass: 'roll-carac', colName: 'Agilité', getter: (actor, context) => actor.system.carac.agilite.value },
|
||||
{ column: "dexterite", rollClass: 'roll-carac', colName: 'Dextérité', getter: (actor, context) => actor.system.carac.dexterite.value },
|
||||
{ column: "vue", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.vue.value },
|
||||
{ column: "ouie", rollClass: 'roll-carac', colName: 'Ouïe', getter: (actor, context) => actor.system.carac.ouie.value },
|
||||
{ column: "odoratgout", rollClass: 'roll-carac', colName: 'Odo-goût', getter: (actor, context) => actor.system.carac.odoratgout.value },
|
||||
{ column: "volonte", rollClass: 'roll-carac', colName: 'Volonté', getter: (actor, context) => actor.system.carac.volonte.value },
|
||||
{ column: "intellect", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.intellect.value },
|
||||
{ column: "empathie", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.empathie.value },
|
||||
{ column: "reve", rollClass: 'roll-carac', colName: 'Rêve', getter: (actor, context) => actor.system.carac.reve.value },
|
||||
{ column: "chance", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.chance.value },
|
||||
{ column: "melee", rollClass: 'roll-carac', colName: 'Mêlée', getter: (actor, context) => actor.system.carac.melee.value },
|
||||
{ column: "tir", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.tir.value },
|
||||
{ column: "lancer", rollClass: 'roll-carac', getter: (actor, context) => actor.system.carac.lancer.value },
|
||||
{ column: "derobee", rollClass: 'roll-carac', colName: 'Dérobée', getter: (actor, context) => actor.system.carac.derobee.value },
|
||||
{ column: "vie", getter: (actor, context) => actor.system.sante.vie.max },
|
||||
{ column: "endurance", getter: (actor, context) => actor.system.sante.endurance.max },
|
||||
{ column: "plusdom", colName: '+dom', getter: (actor, context) => actor.system.attributs.plusdom.value },
|
||||
{ column: "protectionnaturelle", colName: 'Protection naturelle', getter: (actor, context) => actor.system.attributs.protection.value > 0 ? actor.system.attributs.protection.value : '' },
|
||||
{ column: "description", getter: (actor, context) => Mapping.getDescription(actor) },
|
||||
{ column: "armure", getter: (actor, context) => Mapping.getArmure(actor, context) },
|
||||
{ column: "protectionarmure", colName: 'Protection', getter: (actor, context) => Mapping.getProtectionArmure(actor, context) },
|
||||
{ column: "malus_armure", getter: (actor, context) => Mapping.getMalusArmure(actor, context) },
|
||||
{ column: "reve_actuel", rollClass: 'roll-reve-actuel', colName: 'Rêve actuel', getter: (actor, context) => actor.system.reve.reve.value },
|
||||
{ column: "vie_actuel", rollClass: 'jet-vie', getter: (actor, context) => actor.system.sante.vie.value },
|
||||
{ column: "endurance_actuel", rollClass: 'jet-endurance', getter: (actor, context) => actor.system.sante.endurance.value },
|
||||
{ column: "esquive", getter: (actor, context) => Mapping.getEsquive(context) },
|
||||
{ column: "esquive_armure", getter: (actor, context) => Mapping.getEsquiveArmure(context) },
|
||||
{ column: "competences", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_COMPETENCES) },
|
||||
{ column: "draconic", getter: (actor, context) => Mapping.getCompetences(actor, CATEGORIES_DRACONIC) },
|
||||
]
|
||||
|
||||
const MAPPING_ARMES = TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('name', i))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('niveau', i)))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('init', i)))
|
||||
.concat(TABLEAU_ARMES.map(i => ColumnMappingFactory.createMappingArme('dommages', i)))
|
||||
const MAPPING_SORTS = TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('voie', i))
|
||||
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('description', i)))
|
||||
.concat(TABLEAU_SORTS.map(i => ColumnMappingFactory.createMappingSort('bonus', i)))
|
||||
const MAPPING = MAPPING_BASE
|
||||
.concat(MAPPING_ARMES)
|
||||
.concat(MAPPING_SORTS)
|
||||
|
||||
export class Mapping {
|
||||
|
||||
static getMapping() {
|
||||
return MAPPING
|
||||
}
|
||||
|
||||
static getColumns() {
|
||||
return MAPPING.map(it => it.column)
|
||||
}
|
||||
|
||||
static getValues(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return MAPPING.map(it => it.getter(actor, context))
|
||||
}
|
||||
static getAsObject(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return Object.fromEntries(MAPPING.map(it => [it.column, {
|
||||
colName: it.colName ?? it.column,
|
||||
value: it.getter(actor, context)
|
||||
}]))
|
||||
}
|
||||
|
||||
static getValues(actor) {
|
||||
const context = Mapping.prepareContext(actor)
|
||||
return MAPPING.map(it => it.getter(actor, context))
|
||||
}
|
||||
|
||||
static prepareContext(actor) {
|
||||
return {
|
||||
armes: Mapping.prepareArmes(actor),
|
||||
armure: Mapping.prepareArmure(actor),
|
||||
esquive: Mapping.prepareEsquive(actor),
|
||||
sorts: Mapping.prepareSorts(actor)
|
||||
}
|
||||
}
|
||||
|
||||
static prepareArmes(actor) {
|
||||
const armes = actor.items.filter(it => it.type == ITEM_TYPES.arme)
|
||||
RdDItemArme.ajoutCorpsACorps(armes, actor)
|
||||
return armes.map(arme => [
|
||||
arme.system.unemain ? Mapping.prepareArme(actor, arme, 'unemain') : undefined,
|
||||
arme.system.deuxmains ? Mapping.prepareArme(actor, arme, 'deuxmains') : undefined,
|
||||
!(arme.system.unemain || arme.system.deuxmains) ? Mapping.prepareArme(actor, arme, 'competence') : undefined,
|
||||
arme.system.lancer != "" ? Mapping.prepareArme(actor, arme, 'lancer') : undefined,
|
||||
arme.system.tir != "" ? Mapping.prepareArme(actor, arme, 'tir') : undefined]
|
||||
.filter(it => it != undefined))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
}
|
||||
|
||||
static prepareArme(actor, arme, maniement) {
|
||||
const nameCompetenceArme = RdDItemArme.getCompetenceArme(arme, maniement)
|
||||
const competence = actor.getCompetence(nameCompetenceArme)
|
||||
if (RdDItemCompetence.isNiveauBase(competence)) {
|
||||
return undefined
|
||||
}
|
||||
const categorie = Mapping.complementCategorie(arme, maniement)
|
||||
const dommages = Mapping.dommagesArme(actor, arme, maniement)
|
||||
return {
|
||||
name: arme.name + categorie,
|
||||
niveau: Misc.toSignedString(competence.system.niveau),
|
||||
init: Mapping.calculBaseInit(actor, competence.system.categorie) + competence.system.niveau,
|
||||
dommages: dommages,
|
||||
competence: competence,
|
||||
arme: arme
|
||||
}
|
||||
}
|
||||
static dommagesArme(actor, arme, maniement){
|
||||
const dmgArme = RdDItemArme.dommagesReels(arme, maniement)
|
||||
const dommages = Misc.toSignedString(dmgArme + RdDBonus.bonusDmg(actor, maniement, dmgArme))
|
||||
switch(arme.system.mortalite) {
|
||||
case 'non-mortel': return `(${dommages})`
|
||||
case 'empoignade': return '-'
|
||||
}
|
||||
return dommages
|
||||
}
|
||||
|
||||
static complementCategorie(arme, maniement) {
|
||||
switch (maniement) {
|
||||
case 'unemain': return (arme.system.deuxmains) ? ' 1 main' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
||||
case 'deuxmains': return (arme.system.unemain) ? ' 2 mains' : (arme.system.lancer || arme.system.tir) ? ' mêlée' : ''
|
||||
case 'lancer': return (arme.system.unemain || arme.system.deuxmains || arme.system.tir) ? ' jet' : ''
|
||||
case 'tir': return (arme.system.unemain || arme.system.deuxmains || arme.system.lancer) ? ' tir' : ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static calculBaseInit(actor, categorie) {
|
||||
const mapping = MAPPING_BASE.find(it => it.column == categorie)
|
||||
if (mapping) {
|
||||
switch (categorie) {
|
||||
case 'melee':
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
const caracteristique = Number(actor.system.carac[categorie].value)
|
||||
return Math.floor(caracteristique / 2)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
static prepareArmure(actor) {
|
||||
const armures = actor.itemTypes[ITEM_TYPES.armure].filter(it => it.system.equipe)
|
||||
if (armures.length > 1) {
|
||||
console.warn(`${actor.name} a équipé ${armures.length} armures, seule la première sera considérée`)
|
||||
}
|
||||
if (armures.length > 0) {
|
||||
const armure = armures[0]
|
||||
return {
|
||||
name: armure.name,
|
||||
protection: armure.system.protection,
|
||||
malus: armure.system.malus ?? 0
|
||||
}
|
||||
}
|
||||
return {
|
||||
name: '',
|
||||
protection: actor.system.attributs.protection.value,
|
||||
malus: 0
|
||||
}
|
||||
}
|
||||
|
||||
static prepareEsquive(actor) {
|
||||
const esquives = actor.getCompetences("Esquive")
|
||||
if (esquives.length > 0) {
|
||||
const esquive = esquives[0]
|
||||
return {
|
||||
name: esquive.name,
|
||||
niveau: esquive.system.niveau,
|
||||
competence: esquive
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static prepareSorts(actor) {
|
||||
const codeVoies = Mapping.getCompetencesCategorie(actor, CATEGORIES_DRACONIC)
|
||||
.map(it => RdDItemSort.getVoieCode(it))
|
||||
|
||||
return actor.itemTypes[ITEM_TYPES.sort].map(it => Mapping.prepareSort(it, codeVoies))
|
||||
.sort(Misc.ascending(it => `${it.voie} : ${it.description}`))
|
||||
}
|
||||
|
||||
static prepareSort(sort, voies) {
|
||||
return {
|
||||
voie: RdDItemSort.getCodeDraconic(sort, voies),
|
||||
description: Mapping.descriptionSort(sort),
|
||||
bonus: Mapping.bonusCase(sort)
|
||||
}
|
||||
}
|
||||
|
||||
static descriptionSort(sort) {
|
||||
const ptSeuil = Array(sort.system.coutseuil).map(it => '*')
|
||||
const caseTMR = sort.system.caseTMRspeciale.length > 0 ? Mapping.toVar(sort.system.caseTMRspeciale) : Misc.upperFirst(TMRType[sort.system.caseTMR].name)
|
||||
const ptreve = Mapping.addSpaceToNonNumeric(sort.system.ptreve)
|
||||
const diff = Mapping.addSpaceToNonNumeric(sort.system.difficulte)
|
||||
return `${sort.name}${ptSeuil} (${caseTMR}) R${diff} r${ptreve}`
|
||||
}
|
||||
|
||||
static addSpaceToNonNumeric(value) {
|
||||
return Number.isNumeric(value) ? value : ' ' + Mapping.toVar(value)
|
||||
}
|
||||
|
||||
static toVar(value) {
|
||||
return value.replace('variable', 'var')
|
||||
}
|
||||
|
||||
static bonusCase(sort) {
|
||||
const list = RdDItemSort.bonuscaseStringToList(sort.system.bonuscase).sort(Misc.descending(it => it.bonus))
|
||||
if (list.length > 0) {
|
||||
const bonus = list[0]
|
||||
return `+${bonus.bonus}% en ${bonus.case}`
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getDescription(actor) {
|
||||
const sexe = actor.system.sexe
|
||||
const sexeFeminin = sexe.length > 0 && sexe.charAt(0).toLowerCase() == 'f' ? 'Née' : 'Né'
|
||||
const race = ['', 'humain'].includes(Grammar.toLowerCaseNoAccent(actor.system.race)) ? '' : (actor.system.race + ' ')
|
||||
const heure = actor.system.heure
|
||||
const hn = `${sexeFeminin} à l'heure ${RdDTimestamp.definition(heure).avecArticle}`
|
||||
const age = actor.system.age ? `${actor.system.age} ans` : undefined
|
||||
const taille = actor.system.taille
|
||||
const poids = actor.system.poids
|
||||
const cheveux = actor.system.cheveux ? `cheveux ${actor.system.cheveux}` : undefined
|
||||
const yeux = actor.system.yeux ? `yeux ${actor.system.yeux}` : undefined
|
||||
const beaute = actor.system.beaute ? `beauté ${actor.system.beaute}` : undefined
|
||||
const list = [race, hn, age, taille, poids, cheveux, yeux, beaute]
|
||||
return Misc.join(list.filter(it => it), ', ')
|
||||
}
|
||||
|
||||
static getArmure(actor, context) {
|
||||
return context.armure?.name ?? ''
|
||||
}
|
||||
|
||||
static getProtectionArmure(actor, context) {
|
||||
const naturelle = Number(actor.system.attributs.protection.value)
|
||||
if (context?.armure?.protection == undefined) {
|
||||
return naturelle
|
||||
}
|
||||
if (Number.isNumeric(context?.armure?.protection)) {
|
||||
return Number(context?.armure?.protection ?? 0) + naturelle
|
||||
}
|
||||
return context?.armure.protection + (naturelle > 0 ? `+${naturelle}` : '')
|
||||
}
|
||||
|
||||
static getMalusArmure(actor, context) {
|
||||
return context?.armure?.malus ?? 0
|
||||
}
|
||||
|
||||
static getEsquive(context) {
|
||||
if (context.esquive) {
|
||||
return Misc.toSignedString(context.esquive.niveau)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
static getEsquiveArmure(context) {
|
||||
if (context.esquive) {
|
||||
const niveau = context.esquive.niveau + context.armure.malus
|
||||
return Misc.toSignedString(niveau)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getCompetences(actor, categories) {
|
||||
const competences = Mapping.getCompetencesCategorie(actor, categories)
|
||||
if (competences.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const byCategories = Mapping.competencesByCategoriesByNiveau(competences, categories)
|
||||
const txtByCategories = Object.values(byCategories)
|
||||
.map(it => it.competencesParNiveau)
|
||||
.map(byNiveau => {
|
||||
const niveaux = Object.keys(byNiveau)
|
||||
.map(it => Number(it)).sort(Misc.ascending())
|
||||
if (niveaux.length == 0) {
|
||||
return ''
|
||||
}
|
||||
const txtCategorieByNiveau = niveaux.map(niveau => {
|
||||
const names = Misc.join(byNiveau[niveau].map(it => it.name).sort(Misc.ascending()), ', ')
|
||||
return names + ' ' + Misc.toSignedString(niveau)
|
||||
})
|
||||
const txtCategorie = Misc.join(txtCategorieByNiveau, ' / ')
|
||||
return txtCategorie
|
||||
}).filter(it => it != '')
|
||||
|
||||
return Misc.join(txtByCategories, ' / ')
|
||||
}
|
||||
|
||||
static competencesByCategoriesByNiveau(competences, categories) {
|
||||
return categories.map(c => {
|
||||
return {
|
||||
categorie: c,
|
||||
competencesParNiveau: Misc.classify(
|
||||
competences.filter(comp => comp.system.categorie == c),
|
||||
comp => comp.system.niveau)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
static getArme(actor, context, part, numero) {
|
||||
if (numero < context.armes.length) {
|
||||
return context.armes[numero][part] ?? ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
static getCompetencesCategorie(actor, categories) {
|
||||
return actor.itemTypes[ITEM_TYPES.competence]
|
||||
.filter(it => categories.includes(it.system.categorie))
|
||||
.filter(it => !RdDItemCompetence.isNiveauBase(it))
|
||||
}
|
||||
|
||||
static getSort(actor, context, part, numero) {
|
||||
if (numero < context.sorts.length) {
|
||||
return context.sorts[numero][part]
|
||||
}
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
188
module/actor/random/app-personnage-aleatoire.js
Normal file
188
module/actor/random/app-personnage-aleatoire.js
Normal file
@@ -0,0 +1,188 @@
|
||||
import { SHOW_DICE } from "../../constants.js";
|
||||
import { Misc } from "../../misc.js";
|
||||
import { RdDCarac } from "../../rdd-carac.js";
|
||||
import { RdDDice } from "../../rdd-dice.js";
|
||||
import { RdDNameGen } from "../../rdd-namegen.js";
|
||||
import { RdDTimestamp } from "../../time/rdd-timestamp.js";
|
||||
|
||||
const PATHS = [
|
||||
'name',
|
||||
'system.sexe',
|
||||
'system.age',
|
||||
'system.taille',
|
||||
'system.poids',
|
||||
'system.main',
|
||||
'system.heure',
|
||||
'system.cheveux',
|
||||
'system.yeux'
|
||||
]
|
||||
|
||||
const RANDOM_VALUES = {
|
||||
'system.sexe': { 'masculin': 1, 'féminin': 1 },
|
||||
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidectre': 6 },
|
||||
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 },
|
||||
'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
|
||||
}
|
||||
|
||||
export class AppPersonnageAleatoire extends FormApplication {
|
||||
static preloadHandlebars() {
|
||||
loadTemplates([
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
|
||||
])
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor/random/app-personnage-aleatoire.hbs",
|
||||
title: "Génération aléatoire",
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
classes: ['app-personnage-aleatoire'],
|
||||
popOut: true,
|
||||
resizable: true
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor(actor) {
|
||||
super({})
|
||||
this.actor = actor
|
||||
this.current = foundry.utils.duplicate(actor)
|
||||
this.checked = {
|
||||
'name': false,
|
||||
'system.sexe': true,
|
||||
'system.age': true,
|
||||
'system.taille': true,
|
||||
'system.poids': true,
|
||||
'system.main': true,
|
||||
'system.heure': true,
|
||||
'system.cheveux': true,
|
||||
'system.yeux': true
|
||||
}
|
||||
}
|
||||
|
||||
async getData(options) {
|
||||
return foundry.utils.mergeObject(await super.getData(options), {
|
||||
actor: this.actor,
|
||||
current: this.current,
|
||||
checked: this.checked,
|
||||
options: { isGM: game.user.isGM }
|
||||
})
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html)
|
||||
this.html = html
|
||||
this.html.find("button.button-cancel").click(async event => await this.close())
|
||||
this.html.find("button.button-apply").click(async event => await this.onApply())
|
||||
this.html.find("input.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find("a.random").click(async event => await this.onRandom(event))
|
||||
this.html.find("a.reset").click(async event => await this.onReset(event))
|
||||
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
|
||||
this.html.find("input.check-for-random").click(async event => await this.onCheckForRandom(event))
|
||||
}
|
||||
async _updateObject(event, formData) { }
|
||||
|
||||
async onApply() {
|
||||
const updates = Object.fromEntries(
|
||||
PATHS.filter(path => game.user.isGM || path != 'name')
|
||||
.map(path => [path, this.current[path]])
|
||||
)
|
||||
await this.actor.update(updates)
|
||||
await this.close()
|
||||
}
|
||||
|
||||
getPath(selector) {
|
||||
const fields = this.html.find(selector).parents("div.random-field:first")
|
||||
return fields[0].attributes['data-path'].value
|
||||
}
|
||||
|
||||
async onChange(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.current[path] = event.currentTarget.value
|
||||
}
|
||||
|
||||
async onRandom(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
await this.setRandom(path);
|
||||
this.render()
|
||||
}
|
||||
|
||||
async onReset(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.current[path] = this.actor[path]
|
||||
await this.render()
|
||||
}
|
||||
|
||||
async onCheckForRandom(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
this.checked[path] = event.currentTarget.checked
|
||||
this.render()
|
||||
}
|
||||
|
||||
async onRandomizeSelected() {
|
||||
const paths = this.html.find("input.check-for-random:checked")
|
||||
.parents("div.random-field")
|
||||
.toArray()
|
||||
.map(it => it.attributes['data-path'].value)
|
||||
await Promise.all(paths.map(path => this.setRandom(path)))
|
||||
this.render()
|
||||
}
|
||||
|
||||
async setRandom(path) {
|
||||
this.current[path] = await this.random(path);
|
||||
}
|
||||
|
||||
async random(path) {
|
||||
switch (path) {
|
||||
case 'name':
|
||||
return await RdDNameGen.generate()
|
||||
case 'system.sexe':
|
||||
case 'system.main':
|
||||
case 'system.cheveux':
|
||||
case 'system.yeux':
|
||||
return await this.randomFromMap(RANDOM_VALUES[path])
|
||||
case 'system.poids':
|
||||
return await this.randomPoids()
|
||||
case 'system.taille':
|
||||
return await this.randomTaille()
|
||||
case 'system.age':
|
||||
return await RdDDice.rollTotal('(2d4kl)*10 + 1d7xo + 2d20kl')
|
||||
case 'system.heure':
|
||||
return RdDTimestamp.defHeure(await RdDDice.rollHeure({ rollMode: "selfroll", showDice: SHOW_DICE })).key
|
||||
}
|
||||
return 'unknown'
|
||||
}
|
||||
|
||||
async randomFromMap(valuesMap) {
|
||||
const max = Object.values(valuesMap).reduce(Misc.sum(), 0)
|
||||
const total = await RdDDice.rollTotal(`1d${max}`)
|
||||
let sum = 0
|
||||
for (let entry of Object.entries(valuesMap)) {
|
||||
sum = sum + entry[1]
|
||||
if (sum >= total) {
|
||||
return entry[0]
|
||||
}
|
||||
}
|
||||
return Object.keys(valuesMap)[0]
|
||||
}
|
||||
|
||||
async randomPoids() {
|
||||
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
|
||||
const range = caracTaille.poidsMax - caracTaille.poidsMin + 1
|
||||
const total = await RdDDice.rollTotal(`1d${range} + ${caracTaille.poidsMin}`)
|
||||
return total + ' kg'
|
||||
}
|
||||
|
||||
async randomTaille() {
|
||||
const caracTaille = RdDCarac.getCaracDerivee(this.current.system.carac.taille.value)
|
||||
const base = this.current.system.carac.taille.value * 2 + 60 + caracTaille.poidsMin
|
||||
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
|
||||
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
|
||||
const cm = total % 100
|
||||
const m = (total - cm) / 100
|
||||
return `${m}m${cm}`
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,16 +6,16 @@ export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
|
||||
width: 640, height: 720,
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
let formData = await super.getData();
|
||||
mergeObject(formData,
|
||||
foundry.utils.mergeObject(formData,
|
||||
{
|
||||
editable: this.isEditable,
|
||||
cssClass: this.isEditable ? "editable" : "locked",
|
||||
|
||||
433
module/apps/rdd-import-stats.js
Normal file
433
module/apps/rdd-import-stats.js
Normal file
@@ -0,0 +1,433 @@
|
||||
/************************************************************************************/
|
||||
import "./xregexp-all.js";
|
||||
import { SystemCompendiums } from "../settings/system-compendiums.js";
|
||||
import { RdDBaseActorReve } from "../actor/base-actor-reve.js";
|
||||
|
||||
/************************************************************************************/
|
||||
// Some internal test strings
|
||||
let statBlock01 = `+$16(/, baron de Sylvedire, né à l’heure du
|
||||
Roseau, 40 ans, 1m78, 65 kg, Beauté 13.
|
||||
TAILLE
|
||||
10
|
||||
Mêlée
|
||||
14
|
||||
APPARENCE
|
||||
13
|
||||
Tir
|
||||
11
|
||||
CONSTITUTION
|
||||
12
|
||||
Lancer
|
||||
11
|
||||
FORCE
|
||||
12
|
||||
Dérobée
|
||||
13
|
||||
AGILITÉ
|
||||
16
|
||||
Vie
|
||||
11
|
||||
DEXTÉRITÉ
|
||||
13
|
||||
Endurance
|
||||
25
|
||||
VUE
|
||||
10
|
||||
+dom
|
||||
0
|
||||
OUÏE
|
||||
11
|
||||
Protection
|
||||
2 ou 4
|
||||
ODO-GOÛT
|
||||
9
|
||||
cuir souple
|
||||
VOLONTÉ
|
||||
14
|
||||
ou cuir / métal
|
||||
INTELLECT
|
||||
9
|
||||
EMPATHIE
|
||||
11
|
||||
RÊVE
|
||||
13
|
||||
CHANCE
|
||||
10
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
Épée dragonne
|
||||
+5
|
||||
12
|
||||
+3
|
||||
Hache de bataille
|
||||
+6
|
||||
13
|
||||
+3
|
||||
Bouclier moyen
|
||||
+5
|
||||
Dague mêlée
|
||||
+4
|
||||
11
|
||||
+1
|
||||
Corps à corps
|
||||
+4
|
||||
11
|
||||
(0)
|
||||
Esquive
|
||||
+8
|
||||
Escalade +4 / Saut +5 / Commerce +3 / Équitation
|
||||
+6 / Chirurgie 0 / Survie en extérieur +4 / Survie fo-
|
||||
rêt +6 / Acrobatie -2 / Métallurgie +2 / Natation +3 /
|
||||
Légendes -1 / Écriture -4
|
||||
`;
|
||||
|
||||
let statBlock02 = `/HVJDUGHV
|
||||
TAILLE
|
||||
11
|
||||
Mêlée
|
||||
12
|
||||
CONSTITUTION
|
||||
11
|
||||
Tir
|
||||
11
|
||||
FORCE
|
||||
12
|
||||
Lancer
|
||||
11
|
||||
AGILITÉ
|
||||
12
|
||||
Dérobée
|
||||
11
|
||||
DEXTERITÉ
|
||||
11
|
||||
Vie
|
||||
11
|
||||
VUE
|
||||
11
|
||||
Endurance
|
||||
22
|
||||
OUÏE
|
||||
11
|
||||
Vitesse
|
||||
12
|
||||
VOLONTÉ
|
||||
10
|
||||
+dom
|
||||
0
|
||||
Protection
|
||||
4
|
||||
cuir / métal
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
Hache de bataille
|
||||
+4
|
||||
10
|
||||
+3
|
||||
Bouclier moyen
|
||||
+4
|
||||
Dague mêlée
|
||||
+3
|
||||
9
|
||||
+1
|
||||
Arc
|
||||
+5
|
||||
10
|
||||
+2
|
||||
Corps à corps
|
||||
+3
|
||||
9
|
||||
(0)
|
||||
Esquive avec armure
|
||||
+2
|
||||
Course +1/ Vigilance +4
|
||||
`;
|
||||
|
||||
let statBlock03 = `rencontres sont laissées à /HVFKLHQVORXSVGXEDURQ
|
||||
chaque gardien des rêves.
|
||||
TAILLE
|
||||
8
|
||||
Vie
|
||||
10
|
||||
CONSTITUTION FORCE
|
||||
12
|
||||
11
|
||||
Endurance
|
||||
Vitesse
|
||||
12/38
|
||||
21
|
||||
/HVFKLHQV]RPELV
|
||||
PERCEPTION 13
|
||||
+dom
|
||||
0
|
||||
VOLONTÉ
|
||||
10
|
||||
Protection
|
||||
0
|
||||
Les « monstres » apparaîtront un soir, durant
|
||||
RÊVE
|
||||
10
|
||||
l’heure du Serpent, et attaqueront les voya-
|
||||
niv
|
||||
init
|
||||
+dom
|
||||
geurs à leur campement. Si ces derniers ne
|
||||
Morsure
|
||||
13
|
||||
+4
|
||||
10
|
||||
+1
|
||||
campent pas, ils apparaîtront tout de même à
|
||||
Esquive
|
||||
11
|
||||
+3
|
||||
l’heure du Serpent. Le feu ne les effraie pas. Ils
|
||||
Course, Saut
|
||||
12
|
||||
+3
|
||||
ne sont pas très rapides, mais en revanche, très
|
||||
Discrétion
|
||||
12
|
||||
+3
|
||||
silencieux : ils n’aboient pas. Les voyageurs
|
||||
Vigilance
|
||||
13
|
||||
+3
|
||||
`
|
||||
// Skill parser depending on the type of actor
|
||||
const compParser = { personnage: "\\s+(?<value>[\\+\\-]?\\d+)", creature: "\\s+(?<carac>\\d+)\\s+(?<value>[\\+\\-]?\\d+)\\s?(?<init>\\d+)?\\s+?(?<dommages>\\+\\d+)?" };
|
||||
|
||||
// Main class for parsing a stat block
|
||||
export class RdDStatBlockParser {
|
||||
|
||||
static openInputDialog() {
|
||||
let dialog = new Dialog({
|
||||
title: "Import de stats de PNJ/Créatures",
|
||||
content: `
|
||||
<div>
|
||||
<p>Coller le texte de la stat ici</p>
|
||||
<textarea id="statBlock" style="width: 100%; height: 200px;"></textarea>
|
||||
</div>
|
||||
`,
|
||||
buttons: {
|
||||
ok: {
|
||||
label: "OK",
|
||||
callback: async (html) => {
|
||||
let statBlock = html.find("#statBlock")[0].value;
|
||||
await RdDStatBlockParser.parseStatBlock(statBlock);
|
||||
dialog.close();
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
label: "Cancel"
|
||||
}
|
||||
}
|
||||
});
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
static fixWeirdPDF(statString) {
|
||||
// Split the statString into lines
|
||||
let lines = statString.split("\n");
|
||||
let newLines = [];
|
||||
let index = 0;
|
||||
let nextType = "string";
|
||||
// Loop through each line
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
// remove trailing spaces
|
||||
lines[i] = lines[i].trim();
|
||||
// Is it text ?
|
||||
if (lines[i].match(/^[a-zA-Zéêè\s]+/)) {
|
||||
if ( nextType == "string" ) {
|
||||
newLines[index] = lines[i];
|
||||
nextType = "number";
|
||||
} else {
|
||||
console.log("Wrong sequence string detected...", lines[i], nextType);
|
||||
}
|
||||
}
|
||||
// Is it a number ?
|
||||
if (lines[i].match(/^[\d\s]+/)) {
|
||||
if ( nextType == "number" ) {
|
||||
newLines[index] = newLines[index] + lines[i];
|
||||
nextType = "string";
|
||||
index++;
|
||||
} else {
|
||||
console.log("Wrong sequence number detected...", lines[i], nextType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static async parseStatBlock(statString, type = "npc") {
|
||||
|
||||
//statString = statBlock03;
|
||||
if (!statString) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Special function to fix strange/weird copy/paste from PDF readers
|
||||
// Unused up to now : this.fixWeirdPDF(statString);
|
||||
|
||||
// Replace all endline by space in the statString
|
||||
statString = statString.replace(/\n/g, " ");
|
||||
// Remove all multiple spaces
|
||||
statString = statString.replace(/\s{2,}/g, " ");
|
||||
// Remove all leading and trailing spaces
|
||||
statString = statString.trim();
|
||||
|
||||
let actorType = "personnage";
|
||||
let perception = XRegExp.exec(statString.toLowerCase(), XRegExp("perception\\s+(?<value>\\d+)", 'gi'));
|
||||
if (perception?.value ) {
|
||||
actorType = "creature";
|
||||
}
|
||||
|
||||
// Now start carac
|
||||
let actorData = foundry.utils.deepClone(game.model.Actor[actorType]);
|
||||
for (let key in game.model.Actor.personnage.carac) {
|
||||
let caracDef = game.model.Actor.personnage.carac[key];
|
||||
// Parse the stat string for each caracteristic
|
||||
let carac = XRegExp.exec(statString.toLowerCase(), XRegExp(caracDef.label.toLowerCase()+"\\s+(?<value>\\d+)", 'gi'));
|
||||
if (carac?.value) {
|
||||
actorData.carac[key].value = Number(carac.value);
|
||||
}
|
||||
}
|
||||
|
||||
// If creature we need to setup additionnal fields
|
||||
if (actorType == "creature") {
|
||||
let plusDom = XRegExp.exec(statString.toLowerCase(), XRegExp("\\+dom\\s+(?<value>\\+\\d+)", 'gi'));
|
||||
if (plusDom?.values) {
|
||||
actorData.attributs.plusdom.value = Number(plusDom.value);
|
||||
}
|
||||
let protection = XRegExp.exec(statString.toLowerCase(), XRegExp("protection\\s+(?<value>\\d+)", 'gi'));
|
||||
if (protection?.value) {
|
||||
actorData.attributs.protection.value = Number(protection.value);
|
||||
}
|
||||
let endurance = XRegExp.exec(statString.toLowerCase(), XRegExp("endurance\\s+(?<value>\\d+)", 'gi'));
|
||||
if (endurance?.value) {
|
||||
actorData.sante.endurance.value = Number(endurance.value);
|
||||
actorData.sante.endurance.max = Number(endurance.value);
|
||||
}
|
||||
let vie = XRegExp.exec(statString.toLowerCase(), XRegExp("vie\\s+(?<value>\\d+)", 'gi'));
|
||||
if (vie.value) {
|
||||
actorData.sante.vie.value = Number(vie.value);
|
||||
actorData.sante.vie.max = Number(vie.value);
|
||||
}
|
||||
let vitesse = XRegExp.exec(statString.toLowerCase(), XRegExp("vitesse\\s+(?<value>[\\d\\/]+)", 'gi'));
|
||||
if (vitesse?.value) {
|
||||
actorData.attributs.vitesse.value = vitesse.value;
|
||||
}
|
||||
}
|
||||
|
||||
let items = [];
|
||||
// Get skills from compendium
|
||||
const competences = await SystemCompendiums.getCompetences(actorType);
|
||||
//console.log("Competences : ", competences);
|
||||
let allComp = competences.map(i => i.toObject())
|
||||
for (let comp of allComp) {
|
||||
let skill = XRegExp.exec(statString.toLowerCase(), XRegExp(comp.name.toLowerCase()+compParser[actorType], 'gi'));
|
||||
if (skill) {
|
||||
comp.system.niveau = Number(skill.value);
|
||||
if (actorType == "creature") {
|
||||
comp.system.carac_value = Number(skill.carac);
|
||||
if (skill.init) {
|
||||
comp.system.dommages = Number(skill.dommages);
|
||||
comp.system.iscombat = true;
|
||||
}
|
||||
items.push(comp); // Only selective push
|
||||
}
|
||||
}
|
||||
if (actorType == "personnage") {
|
||||
items.push(comp); // Always push
|
||||
}
|
||||
}
|
||||
|
||||
// Now process weapons
|
||||
const weapons = await SystemCompendiums.getWorldOrCompendiumItems("arme", "equipement")
|
||||
//console.log("Equipement : ", equipment);
|
||||
for (let w of weapons) {
|
||||
|
||||
let weapon = XRegExp.exec(statString.toLowerCase(), XRegExp(w.name.toLowerCase()+"\\s+(?<value>\\+\\d+)", 'gi'));
|
||||
if (weapon) {
|
||||
w.system.equipe = true
|
||||
items.push(w.toObject());
|
||||
// now process the skill
|
||||
if ( w.system?.competence != "") {
|
||||
let wComp = items.find(i => i.name.toLowerCase() == w.system.competence.toLowerCase());
|
||||
if (wComp) {
|
||||
wComp.system.niveau = Number(weapon.value);
|
||||
}
|
||||
}
|
||||
if ( w.system?.tir != "") {
|
||||
let wComp = items.find(i => i.name.toLowerCase() == w.system.tir.toLowerCase());
|
||||
if (wComp) {
|
||||
wComp.system.niveau = Number(weapon.value);
|
||||
}
|
||||
}
|
||||
if ( w.system?.lancer != "") {
|
||||
let wComp = items.find(i => i.name.toLowerCase() == w.system.lancer.toLowerCase());
|
||||
if (wComp) {
|
||||
wComp.system.niveau = Number(weapon.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now process armors
|
||||
const armors = await SystemCompendiums.getWorldOrCompendiumItems("armure", "equipement")
|
||||
for (let a of armors) {
|
||||
let armor = XRegExp.exec(statString.toLowerCase(), XRegExp(a.name.toLowerCase(), 'gi'));
|
||||
if (armor) {
|
||||
a.system.equipe = true
|
||||
items.push(a.toObject());
|
||||
}
|
||||
}
|
||||
|
||||
// Get hour name : heure du XXXXX
|
||||
let heure = XRegExp.exec(statString.toLowerCase(), XRegExp("heure du\\s+(?<value>\\w+)", 'gi'));
|
||||
if (heure?.value) {
|
||||
actorData.heure = heure.value;
|
||||
}
|
||||
// Get age
|
||||
let age = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) ans", 'gi'));
|
||||
if (age?.value) {
|
||||
actorData.age = Number(age.value);
|
||||
}
|
||||
// Get height
|
||||
let taille = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+)m\\d+", 'gi'));
|
||||
if (taille?.value) {
|
||||
actorData.taille = taille.value;
|
||||
}
|
||||
// Get weight
|
||||
let poids = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>\\d+) kg", 'gi'));
|
||||
if (poids?.value) {
|
||||
actorData.poids = poids.value;
|
||||
}
|
||||
// Get beauty
|
||||
let beaute = XRegExp.exec(statString.toLowerCase(), XRegExp("beauté\\s+(?<value>\\d+)", 'gi'));
|
||||
if (beaute?.value) {
|
||||
actorData.beaute = Number(beaute.value);
|
||||
}
|
||||
|
||||
// Name is all string before ', né'
|
||||
let name
|
||||
if (actorType == "personnage") {
|
||||
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>[\\w\\s\\d]+),", 'gi'));
|
||||
if (!name?.value) {
|
||||
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
|
||||
}
|
||||
name = name?.value || "Importé";
|
||||
}
|
||||
if (actorType == "creature") {
|
||||
name = XRegExp.exec(statString.toLowerCase(), XRegExp("(?<value>.+)\\s+taille", 'gi'));
|
||||
name = name?.value || "Importé";
|
||||
}
|
||||
|
||||
let newActor = RdDBaseActorReve.create({name: name || "Importé", type:actorType, system: actorData, items: items});
|
||||
|
||||
// DUmp....
|
||||
console.log(actorData);
|
||||
}
|
||||
}
|
||||
|
||||
8225
module/apps/xregexp-all.js
Normal file
8225
module/apps/xregexp-all.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
import { Misc } from "./misc.js";
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
|
||||
|
||||
/**
|
||||
@@ -7,15 +8,20 @@ import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
*/
|
||||
export class ChatUtility {
|
||||
|
||||
static async init() {
|
||||
Hooks.on("renderChatMessage", async (app, html, msg) => await ChatUtility.onRenderChatMessage(app, html, msg))
|
||||
Hooks.on("createChatMessage", async (chatMessage, options, id) => await ChatUtility.onCreateChatMessage(chatMessage, options, id))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data);
|
||||
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data);
|
||||
case "msg_gm_chat_message": return ChatUtility.handleGMChatMessage(sockmsg.data)
|
||||
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data)
|
||||
case "msg_user_ui_notifications": return ChatUtility.onNotifyUser(sockmsg.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static notifyUser(userId, level = 'info', message) {
|
||||
const socketData = {
|
||||
@@ -43,7 +49,7 @@ export class ChatUtility {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onRemoveMessages(socketData) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
if (socketData.part) {
|
||||
const toDelete = game.messages.filter(it => it.content.includes(socketData.part));
|
||||
toDelete.forEach(it => it.delete());
|
||||
@@ -57,7 +63,7 @@ export class ChatUtility {
|
||||
/* -------------------------------------------- */
|
||||
|
||||
static removeMessages(socketData) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
ChatUtility.onRemoveMessages(socketData);
|
||||
}
|
||||
else {
|
||||
@@ -77,85 +83,101 @@ export class ChatUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async createChatWithRollMode(name, chatOptions) {
|
||||
let rollMode = game.settings.get("core", "rollMode")
|
||||
switch (rollMode) {
|
||||
static async createChatWithRollMode(messageData, actor = undefined) {
|
||||
switch (game.settings.get("core", "rollMode")) {
|
||||
case "blindroll": // GM only
|
||||
if (!game.user.isGM) {
|
||||
ChatUtility.blindMessageToGM(chatOptions);
|
||||
|
||||
chatOptions.whisper = [game.user.id];
|
||||
chatOptions.content = "Message envoyé en aveugle au Gardien";
|
||||
ChatUtility.blindMessageToGM(messageData)
|
||||
messageData.whisper = [game.user];
|
||||
messageData.content = "Message envoyé en aveugle au Gardien"
|
||||
}
|
||||
else {
|
||||
chatOptions.whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
messageData.whisper = ChatUtility.getGMs()
|
||||
}
|
||||
break;
|
||||
default:
|
||||
chatOptions.whisper = ChatUtility.getWhisperRecipients(rollMode, name);
|
||||
break;
|
||||
break
|
||||
case "gmroll":
|
||||
messageData.whisper = ChatUtility.getOwners(actor)
|
||||
break
|
||||
case "selfroll":
|
||||
messageData.whisper = [game.user]
|
||||
break
|
||||
}
|
||||
chatOptions.alias = chatOptions.alias || name;
|
||||
return await ChatMessage.create(chatOptions);
|
||||
messageData.alias = messageData.alias ?? actor?.name ?? game.user.name
|
||||
return await ChatMessage.create(messageData)
|
||||
}
|
||||
|
||||
static getOwners(document) {
|
||||
return game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
}
|
||||
|
||||
static getUserAndGMs() {
|
||||
return [game.user, ...ChatUtility.getGMs()]
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareChatMessage(rollMode, name) {
|
||||
return {
|
||||
user: game.user.id,
|
||||
whisper: ChatUtility.getWhisperRecipients(rollMode, name)
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipients(rollMode, name) {
|
||||
switch (rollMode) {
|
||||
case "blindroll": return ChatUtility.getUsers(user => user.isGM);
|
||||
case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name);
|
||||
case "selfroll": return [game.user.id];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getWhisperRecipientsAndGMs(...names) {
|
||||
let recipients = [...ChatMessage.getWhisperRecipients('GM')]
|
||||
names.forEach(name => recipients.push(...ChatMessage.getWhisperRecipients(name)))
|
||||
return recipients
|
||||
static getMultipleActorsOwners(...actors) {
|
||||
return Misc.concat(actors.map(it => it == undefined ? [] : ChatUtility.getOwners(it)))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getUsers(filter) {
|
||||
return game.users.filter(filter).map(user => user.id);
|
||||
return game.users.filter(filter)
|
||||
}
|
||||
|
||||
static getGMs() {
|
||||
return game.users.filter(user => user.isGM)
|
||||
}
|
||||
|
||||
static applyRollMode(chatMessageData = {}, rollMode = game.settings.get("core", "rollMode")) {
|
||||
switch (rollMode) {
|
||||
case "blindroll":
|
||||
chatMessageData.blind = true
|
||||
chatMessageData.whisper = ChatUtility.getGMs()
|
||||
break
|
||||
case "gmroll":
|
||||
chatMessageData.whisper = ChatUtility.getGMs()
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
case "roll":
|
||||
chatMessageData.whisper = ChatUtility.getUsers(user => user.active)
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
case "selfroll":
|
||||
chatMessageData.whisper = [game.user]
|
||||
chatMessageData.blind = false
|
||||
break
|
||||
}
|
||||
return chatMessageData
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static blindMessageToGM(chatOptions) {
|
||||
let chatGM = duplicate(chatOptions);
|
||||
chatGM.whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content;
|
||||
console.log("blindMessageToGM", chatGM);
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM });
|
||||
const chatGM = foundry.utils.duplicate(chatOptions)
|
||||
chatGM.content = "Message aveugle de " + game.user.name + "<br>" + chatOptions.content
|
||||
console.log("blindMessageToGM", chatGM)
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_gm_chat_message", data: chatGM })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static handleGMChatMessage(socketData) {
|
||||
console.log("blindMessageToGM", socketData);
|
||||
if (game.user.isGM) { // message privé pour GM only
|
||||
socketData.user = game.user.id;
|
||||
ChatMessage.create(socketData);
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
whisper: ChatUtility.getGMs(),
|
||||
content: socketData.content
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
static async setMessageData(chatMessage, key, flag) {
|
||||
if (flag) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, JSON.stringify(flag));
|
||||
if (flag && chatMessage.isAuthor) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, key, flag)
|
||||
}
|
||||
}
|
||||
|
||||
static getMessageData(chatMessage, key) {
|
||||
const json = chatMessage.getFlag(SYSTEM_RDD, key);
|
||||
return json ? JSON.parse(json) : undefined;
|
||||
return chatMessage.getFlag(SYSTEM_RDD, key);
|
||||
}
|
||||
|
||||
static getChatMessage(event) {
|
||||
@@ -163,4 +185,19 @@ export class ChatUtility {
|
||||
return game.messages.get(chatMessageId);
|
||||
}
|
||||
|
||||
static async onRenderChatMessage(chatMessage, html, data) {
|
||||
const rddTimestamp = chatMessage.getFlag(SYSTEM_RDD, 'rdd-timestamp')
|
||||
if (rddTimestamp) {
|
||||
const timestamp = new RdDTimestamp(rddTimestamp);
|
||||
const timestampData = timestamp.toCalendrier();
|
||||
const dateHeure = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs', timestampData);
|
||||
html.find('header.message-header .message-sender').after(dateHeure)
|
||||
}
|
||||
}
|
||||
|
||||
static async onCreateChatMessage(chatMessage, options, id) {
|
||||
if (chatMessage.isAuthor) {
|
||||
await chatMessage.setFlag(SYSTEM_RDD, 'rdd-timestamp', game.system.rdd.calendrier.getTimestamp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ export class RdDCoeur {
|
||||
}
|
||||
|
||||
static extractInfoCoeur(event) {
|
||||
return ChatUtility.getMessageData(ChatUtility.getChatMessage(event), INFO_COEUR)
|
||||
const chatMesage = ChatUtility.getChatMessage(event);
|
||||
return ChatUtility.getMessageData(chatMesage, INFO_COEUR)
|
||||
}
|
||||
|
||||
static getInfoCoeur(sourceActorId, targetActorId) {
|
||||
@@ -69,7 +70,7 @@ export class RdDCoeur {
|
||||
}
|
||||
|
||||
static async applyCoeurChateauDormant(actor, message) {
|
||||
const newSuivants = duplicate(actor.system.subacteurs.suivants)
|
||||
const newSuivants = foundry.utils.duplicate(actor.system.subacteurs.suivants)
|
||||
let count = 0
|
||||
newSuivants.forEach(async link => {
|
||||
const suivant = game.actors.get(link.id)
|
||||
@@ -98,12 +99,11 @@ export class RdDCoeur {
|
||||
|
||||
static async startSubActeurTendreMoment(actorId, subActeurId) {
|
||||
const infoCoeur = RdDCoeur.getInfoCoeur(actorId, subActeurId)
|
||||
if (infoCoeur.target?.actor.id) {
|
||||
if (infoCoeur.target?.actor?.id) {
|
||||
// TODO: passer par une fenêtre pour saisir sa proposition (lieu, heure, ...)
|
||||
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
|
||||
const chatMessage = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.target?.actor.name),
|
||||
content: chatHtml
|
||||
whisper: ChatUtility.getOwners(infoCoeur.target.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-proposer-tendre-moment.hbs`, infoCoeur)
|
||||
})
|
||||
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
|
||||
}
|
||||
@@ -117,8 +117,8 @@ export class RdDCoeur {
|
||||
}
|
||||
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
|
||||
|
||||
infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total
|
||||
infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate({ async: true }))).total
|
||||
infoCoeur.target.jetTendre = (await (new Roll('1d6').evaluate())).total
|
||||
infoCoeur.source.jetTendre = (await (new Roll('1d6').evaluate())).total
|
||||
const diff = Math.abs(infoCoeur.source.jetTendre - infoCoeur.target.jetTendre)
|
||||
for (let amoureux of [infoCoeur.source, infoCoeur.target]) {
|
||||
const actorAmoureux = game.actors.get(amoureux.actor.id);
|
||||
@@ -127,7 +127,7 @@ export class RdDCoeur {
|
||||
}
|
||||
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-accepter-tendre-moment.hbs`, infoCoeur)
|
||||
const chatMessage = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name),
|
||||
whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
|
||||
content: chatHtml
|
||||
})
|
||||
RdDCoeur.addTagsInfoCoeur(infoCoeur, chatMessage)
|
||||
@@ -142,7 +142,7 @@ export class RdDCoeur {
|
||||
ChatUtility.removeChatMessageId(infoCoeur.chatMessageId)
|
||||
const chatHtml = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/coeur/chat-refuser-tendre-moment.hbs`, infoCoeur)
|
||||
await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(infoCoeur.source?.actor.name, infoCoeur.target?.actor.name),
|
||||
whisper: ChatUtility.getMultipleActorsOwners(infoCoeur.source?.actor, infoCoeur.target?.actor),
|
||||
content: chatHtml
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,3 +8,46 @@ export const SHOW_DICE = 'show';
|
||||
export const ENTITE_INCARNE = 'incarne';
|
||||
export const ENTITE_NONINCARNE = 'nonincarne';
|
||||
export const ENTITE_BLURETTE = 'blurette';
|
||||
|
||||
export const RDD_CONFIG = {
|
||||
niveauEthylisme : [
|
||||
{value: "1", label: "Aucun"},
|
||||
{value: "0", label: "Eméché (0)"},
|
||||
{value: "-1", label: "Gris (-1)"},
|
||||
{value: "-2", label: "Pinté (-2)"},
|
||||
{value: "-3", label: "Pas Frais (-3)"},
|
||||
{value: "-4", label: "Ivre (-4)"},
|
||||
{value: "-5", label: "Bu (-5)"},
|
||||
{value: "-6", label: "Complètement fait (-6)"},
|
||||
{value: "-7", label: "Ivre mort (-7)"}
|
||||
],
|
||||
categorieEntite: {
|
||||
"cauchemar": "Cauchemar",
|
||||
"reve": "Rêve"
|
||||
},
|
||||
typeEntite: {
|
||||
"incarne": "Incarnée",
|
||||
"nonincarne": "Non Incarnée",
|
||||
"blurette": "Blurette"
|
||||
},
|
||||
heuresRdD : [
|
||||
{value : "vaisseau", label: "Vaisseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd01.webp"},
|
||||
{value : "sirene", label: "Sirène", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd02.webp"},
|
||||
{value : "faucon", label: "Faucon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd03.webp"},
|
||||
{value : "couronne", label: "Couronne", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd04.webp"},
|
||||
{value : "dragon", label: "Dragon", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd05.webp"},
|
||||
{value : "epees", label: "Epées", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd06.webp"},
|
||||
{value : "lyre", label: "Lyre", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd07.webp"},
|
||||
{value : "serpent", label: "Serpent", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd08.webp"},
|
||||
{value : "poissonacrobate", label: "Poisson Acrobate", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd09.webp"},
|
||||
{value : "araignee", label: "Araignée", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd10.webp"},
|
||||
{value : "roseau", label: "Roseau", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd11.webp"},
|
||||
{value : "chateaudormant", label: "Chateau Dormant", img: "modules/foundryvtt-reve-de-dragon/icons/heures/hd12.webp"}
|
||||
],
|
||||
raretes: [
|
||||
{value: "Commune", label: "Commune"},
|
||||
{value: "Frequente", label: "Fréquente"},
|
||||
{value: "Rare", label: "Rare"},
|
||||
{value: "Rarissime", label: "Rarissime"}
|
||||
]
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
export class DialogChoixXpCarac extends Dialog {
|
||||
|
||||
static async choix(actor, xpData, caracs) {
|
||||
caracs = caracs.map(it => mergeObject({ ajout: 0 }, it))
|
||||
xpData = mergeObject({ reste: xpData.xpCarac }, xpData)
|
||||
caracs = caracs.map(it => foundry.utils.mergeObject({ ajout: 0 }, it))
|
||||
xpData = foundry.utils.mergeObject({ reste: xpData.xpCarac }, xpData)
|
||||
const dialogData = {
|
||||
title: `Choisissez la répartition d'expérience`,
|
||||
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-choix-xp-carac.hbs", {
|
||||
@@ -24,7 +24,7 @@ export class DialogChoixXpCarac extends Dialog {
|
||||
}
|
||||
|
||||
constructor(dialogData, dialogOptions, actor, xpData, caracs) {
|
||||
dialogData = mergeObject(dialogData, {
|
||||
dialogData = foundry.utils.mergeObject(dialogData, {
|
||||
default: 'appliquer',
|
||||
buttons: {
|
||||
'appliquer': { icon:'<i class="fa-solid fa-check"></i>', label: "Ajouter la répartition", callback: it => this.appliquerSelection() }
|
||||
|
||||
@@ -8,7 +8,7 @@ const LATEST_USED_JOURNAL_ID = "chronologie-dernier-journal";
|
||||
|
||||
export class DialogChronologie extends Dialog {
|
||||
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, LATEST_USED_JOURNAL_ID, {
|
||||
name: "Dernier article de journal utilisé pour enregistrer la chronologie",
|
||||
scope: "client",
|
||||
|
||||
@@ -24,7 +24,7 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
}
|
||||
|
||||
constructor(dialogData, html) {
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||
let options = { classes: ["DialogCreateSigneDraconiqueActors"], width: 500, height: 650, 'z-index': 99999 };
|
||||
let conf = {
|
||||
title: "Créer un signe",
|
||||
content: html,
|
||||
@@ -48,7 +48,7 @@ export class DialogCreateSigneDraconique extends Dialog {
|
||||
async _createSigneForActor(actor, signe) {
|
||||
actor.createEmbeddedDocuments("Item", [signe]);
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name),
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
|
||||
signe: signe,
|
||||
alias: actor.name
|
||||
|
||||
@@ -21,7 +21,7 @@ export class DialogFabriquerPotion extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
let potionData = duplicate(item)
|
||||
let potionData = foundry.utils.duplicate(item)
|
||||
potionData.nbBrinsSelect = RdDUtility.buildListOptions(
|
||||
DialogFabriquerPotion.nombreBrinsMinimum(item),
|
||||
DialogFabriquerPotion.nombreBrinsOptimal(item));
|
||||
|
||||
@@ -47,7 +47,7 @@ export class DialogConsommer extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
static prepareData(actor, item) {
|
||||
let consommerData = {
|
||||
item: duplicate(item),
|
||||
item: foundry.utils.duplicate(item),
|
||||
cuisine: actor.getCompetence('cuisine'),
|
||||
choix: {
|
||||
doses: 1,
|
||||
|
||||
@@ -8,14 +8,13 @@ import { RdDUtility } from "./rdd-utility.js";
|
||||
export class DialogValidationEncaissement extends Dialog {
|
||||
|
||||
static async validerEncaissement(actor, rollData, armure, onEncaisser) {
|
||||
let encaissement = await RdDUtility.jetEncaissement(rollData, armure, { showDice: HIDE_DICE });
|
||||
const encaissement = await RdDUtility.jetEncaissement(actor, rollData, armure, { showDice: HIDE_DICE });
|
||||
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-validation-encaissement.html', {
|
||||
actor: actor,
|
||||
rollData: rollData,
|
||||
encaissement: encaissement
|
||||
});
|
||||
const dialog = new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser);
|
||||
dialog.render(true);
|
||||
new DialogValidationEncaissement(html, actor, rollData, armure, encaissement, onEncaisser).render(true);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -56,14 +55,14 @@ export class DialogValidationEncaissement extends Dialog {
|
||||
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.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: HIDE_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.html.find('label.encaissement-total').text(this.encaissement.total);
|
||||
this.html.find('label.encaissement-blessure').text(this.encaissement.blessures)
|
||||
});
|
||||
}
|
||||
|
||||
async onValider() {
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.encaissement = await RdDUtility.jetEncaissement(this.actor, this.rollData, this.armure, { showDice: SHOW_DICE, forceDiceResult: this.forceDiceResult});
|
||||
this.onEncaisser(this.encaissement)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { CompendiumTableHelpers, CompendiumTable, SystemCompendiums } from "./se
|
||||
const COMPENDIUMS_RECHERCHE = 'compendiums-recherche';
|
||||
|
||||
export class Environnement {
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, COMPENDIUMS_RECHERCHE, {
|
||||
name: COMPENDIUMS_RECHERCHE,
|
||||
default: [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js"
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
const nomCategorieParade = {
|
||||
@@ -20,19 +20,35 @@ const nomCategorieParade = {
|
||||
export class RdDItemArme extends Item {
|
||||
|
||||
static isArme(item) {
|
||||
return item.type == TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
|
||||
return item.type == ITEM_TYPES.arme || RdDItemCompetenceCreature.getCategorieAttaque(item);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getArme(arme) {
|
||||
switch (arme ? arme.type : '') {
|
||||
case TYPES.arme: return arme;
|
||||
case TYPES.competencecreature:
|
||||
case ITEM_TYPES.arme: return arme;
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return RdDItemCompetenceCreature.armeCreature(arme);
|
||||
}
|
||||
return RdDItemArme.mainsNues();
|
||||
}
|
||||
|
||||
static getCompetenceArme(arme, maniement) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.name
|
||||
case ITEM_TYPES.arme:
|
||||
switch (maniement) {
|
||||
case 'competence': return arme.system.competence;
|
||||
case 'unemain': return RdDItemArme.competence1Mains(arme);
|
||||
case 'deuxmains': return RdDItemArme.competence2Mains(arme);
|
||||
case 'tir': return arme.system.tir;
|
||||
case 'lancer': return arme.system.lancer;
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static computeNiveauArmes(armes, competences) {
|
||||
for (const arme of armes) {
|
||||
arme.system.niveau = RdDItemArme.niveauCompetenceArme(arme, competences);
|
||||
@@ -65,37 +81,59 @@ export class RdDItemArme extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static getCategorieParade(armeData) {
|
||||
if (armeData.system.categorie_parade) {
|
||||
return armeData.system.categorie_parade;
|
||||
return armeData.system.categorie_parade
|
||||
}
|
||||
// pour compatibilité avec des personnages existants
|
||||
if (armeData.type == TYPES.competencecreature || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '');
|
||||
if (armeData.type == ITEM_TYPES.competencecreature || armeData.system.categorie == 'creature') {
|
||||
return armeData.system.categorie_parade || (armeData.system.isparade ? 'armes-naturelles' : '')
|
||||
}
|
||||
if (!armeData.type.match(/arme|competencecreature/)) {
|
||||
return '';
|
||||
return ''
|
||||
}
|
||||
if (armeData.system.competence == undefined) {
|
||||
return TYPES.competencecreature;
|
||||
return ITEM_TYPES.competencecreature;
|
||||
}
|
||||
let compname = armeData.system.competence.toLowerCase();
|
||||
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) return '';
|
||||
if (compname.match(/^(dague de jet|javelot|fouet|arc|arbalête|fronde|hache de jet|fléau)$/)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (compname.match('hache')) return 'haches';
|
||||
if (compname.match('hast')) return 'hast';
|
||||
if (compname.match('lance')) return 'lances';
|
||||
if (compname.match('bouclier')) return 'boucliers';
|
||||
if (compname.match('masse')) return 'masses';
|
||||
if (compname.match('hache')) return 'haches'
|
||||
if (compname.match('hast')) return 'hast'
|
||||
if (compname.match('lance')) return 'lances'
|
||||
if (compname.match('bouclier')) return 'boucliers'
|
||||
if (compname.match('masse')) return 'masses'
|
||||
if (compname.match('epée') || compname.match('épée')) {
|
||||
if (armeData.name.toLowerCase().match(/(gnome)/))
|
||||
return 'epees-courtes';
|
||||
return 'epees-courtes'
|
||||
if (armeData.name.toLowerCase().match(/((e|é)pée dragone|esparlongue|demi-dragonne)/))
|
||||
return 'epees-longues';
|
||||
return 'epees-lourdes';
|
||||
return 'epees-longues'
|
||||
return 'epees-lourdes'
|
||||
}
|
||||
if (compname.match('dague')) {
|
||||
return 'dagues';
|
||||
return 'dagues'
|
||||
}
|
||||
return 'sans-armes'
|
||||
}
|
||||
|
||||
static defenseArmeParade(armeAttaque, armeParade) {
|
||||
const defCategory = RdDItemArme.getCategorieParade(armeParade)
|
||||
if (defCategory == 'bouclier') {
|
||||
return 'norm'
|
||||
}
|
||||
if (armeAttaque.system.competence.toLowerCase().match(/(fléau)/)) {
|
||||
return ''
|
||||
}
|
||||
if (armeParade.system.tir) {
|
||||
return ''
|
||||
}
|
||||
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
|
||||
switch (attCategory) {
|
||||
case 'armes-naturelles': case 'sans-armes':
|
||||
return defCategory == 'sans-armes' ? 'norm' : ''
|
||||
default:
|
||||
return RdDItemArme.needParadeSignificative(armeAttaque, armeParade) ? 'sign' : 'norm'
|
||||
}
|
||||
return 'sans-armes';
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -104,8 +142,8 @@ export class RdDItemArme extends Item {
|
||||
return false;
|
||||
}
|
||||
// categories d'armes à la parade (cf. page 115 )
|
||||
let attCategory = RdDItemArme.getCategorieParade(armeAttaque);
|
||||
let defCategory = RdDItemArme.getCategorieParade(armeParade);
|
||||
const attCategory = RdDItemArme.getCategorieParade(armeAttaque)
|
||||
const defCategory = RdDItemArme.getCategorieParade(armeParade)
|
||||
// bouclier et mêmes catégorie: peuvent se parer sans difficulté
|
||||
if (defCategory == 'boucliers') {
|
||||
return false;
|
||||
@@ -132,43 +170,66 @@ export class RdDItemArme extends Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeUneOuDeuxMains(armeData, aUneMain) {
|
||||
if (armeData && !armeData.system.cac) {
|
||||
armeData.system.unemain = armeData.system.unemain || !armeData.system.deuxmains;
|
||||
const uneOuDeuxMains = armeData.system.unemain && armeData.system.deuxmains;
|
||||
const containsSlash = !Number.isInteger(armeData.system.dommages) && armeData.system.dommages.includes("/");
|
||||
if (containsSlash) { // Sanity check
|
||||
armeData = duplicate(armeData);
|
||||
|
||||
const tableauDegats = armeData.system.dommages.split("/");
|
||||
if (aUneMain)
|
||||
armeData.system.dommagesReels = Number(tableauDegats[0]);
|
||||
else // 2 mains
|
||||
armeData.system.dommagesReels = Number(tableauDegats[1]);
|
||||
}
|
||||
else {
|
||||
armeData.system.dommagesReels = Number(armeData.system.dommages);
|
||||
}
|
||||
|
||||
if (uneOuDeuxMains != containsSlash) {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + armeData.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
}
|
||||
static dommagesReels(arme, maniement) {
|
||||
switch (maniement) {
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
case 'competence':
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
return armeData;
|
||||
if (arme.system.unemain && arme.system.deuxmains) {
|
||||
const containsSlash = !Number.isInteger(arme.system.dommages) && arme.system.dommages.includes("/")
|
||||
if (!containsSlash) {
|
||||
ui.notifications.info("Les dommages de l'arme à 1/2 mains " + arme.name + " ne sont pas corrects (ie sous la forme X/Y)");
|
||||
return Number(arme.system.dommages)
|
||||
}
|
||||
const tableauDegats = arme.system.dommages.split("/");
|
||||
return Number(tableauDegats[maniement == 'unemain' ? 0 : 1])
|
||||
}
|
||||
return Number(arme.system.dommages);
|
||||
}
|
||||
static competence2Mains(arme) {
|
||||
return arme.system.competence.replace(" 1 main", " 2 mains");
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static armeUneOuDeuxMains(arme, aUneMain) {
|
||||
if (arme && !arme.system.cac) {
|
||||
arme = foundry.utils.duplicate(arme);
|
||||
arme.system.dommagesReels = RdDItemArme.dommagesReels(arme, aUneMain ? 'unemain' : 'deuxmains')
|
||||
}
|
||||
return arme;
|
||||
}
|
||||
|
||||
static competence1Mains(arme) {
|
||||
return arme.system.competence.replace(" 2 mains", " 1 main");
|
||||
}
|
||||
|
||||
static isArmeUtilisable(arme) {
|
||||
static competence2Mains(arme) {
|
||||
return arme.system.competence.replace(" 1 main", " 2 mains");
|
||||
}
|
||||
|
||||
static isUtilisable(arme) {
|
||||
switch (arme.type) {
|
||||
case TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case TYPES.competencecreature: return true
|
||||
case ITEM_TYPES.arme: return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature: return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isAttaque(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme:
|
||||
return arme.system.equipe && (arme.system.resistance > 0 || arme.system.portee_courte > 0)
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.system.iscombat && RdDItemCompetenceCreature.isAttaque(item)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(arme) {
|
||||
switch (arme.type) {
|
||||
case ITEM_TYPES.arme:
|
||||
return arme.system.equipe && arme.system.resistance > 0 && true/* TODO: regarder la categorie d'arme?*/
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return arme.system.iscombat && RdDItemCompetenceCreature.isParade(arme)
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -180,11 +241,11 @@ export class RdDItemArme extends Item {
|
||||
|
||||
static corpsACorps(actor) {
|
||||
let competence = actor?.getCompetenceCorpsACorps() ?? { system: { niveau: -6 } };
|
||||
let melee = actor? actor.system.carac['melee'].value : 0
|
||||
let melee = actor ? actor.system.carac['melee'].value : 0
|
||||
return {
|
||||
_id: competence?.id,
|
||||
name: 'Corps à corps',
|
||||
type: TYPES.arme,
|
||||
type: ITEM_TYPES.arme,
|
||||
img: 'systems/foundryvtt-reve-de-dragon/icons/competence_corps_a_corps.webp',
|
||||
system: {
|
||||
initiative: RdDCombatManager.calculInitiative(competence.system.niveau, melee),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
|
||||
@@ -23,12 +24,12 @@ const limitesArchetypes = [
|
||||
];
|
||||
|
||||
/* -------------------------------------------- */
|
||||
const categoriesCompetences = {
|
||||
export const CATEGORIES_COMPETENCES = {
|
||||
"generale": { base: -4, label: "Générales" },
|
||||
"particuliere": { base: -8, label: "Particulières" },
|
||||
"specialisee": { base: -11, label: "Spécialisées" },
|
||||
"connaissance": { base: -11, label: "Connaissances" },
|
||||
"draconic": { base: -11, label: "Draconics" },
|
||||
"draconic": { base: -11, label: "Draconic" },
|
||||
"melee": { base: -6, label: "Mêlée" },
|
||||
"tir": { base: -8, label: "Tir" },
|
||||
"lancer": { base: -8, label: "Lancer" }
|
||||
@@ -48,16 +49,14 @@ function _buildCumulXP() {
|
||||
const competence_xp_cumul = _buildCumulXP();
|
||||
|
||||
export class RdDItemCompetence extends Item {
|
||||
/* -------------------------------------------- */
|
||||
static getCategories() {
|
||||
return categoriesCompetences;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getLabelCategorie(category) {
|
||||
return categoriesCompetences[category].label;
|
||||
return CATEGORIES_COMPETENCES[category].label;
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category, categories = categoriesCompetences) {
|
||||
/* -------------------------------------------- */
|
||||
static getNiveauBase(category, itemType) {
|
||||
let categories = RdDItem.getCategories(itemType)
|
||||
return categories[category]?.base ?? 0;
|
||||
}
|
||||
|
||||
@@ -191,7 +190,7 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isNiveauBase(item) {
|
||||
return Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.getCategories());
|
||||
return item.system.niveau == undefined || Number(item.system.niveau) == RdDItemCompetence.getNiveauBase(item.system.categorie, item.type);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -199,7 +198,7 @@ export class RdDItemCompetence extends Item {
|
||||
if (idOrName == undefined || idOrName == "") {
|
||||
return RdDItemCompetence.sansCompetence();
|
||||
}
|
||||
options = mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false });
|
||||
options = foundry.utils.mergeObject(options, { preFilter: it => it.isCompetence(), description: 'compétence' }, { overwrite: false, inplace: false });
|
||||
return RdDItemCompetence.findFirstItem(list, idOrName, options);
|
||||
}
|
||||
|
||||
@@ -257,7 +256,7 @@ export class RdDItemCompetence extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static computeResumeArchetype(competences) {
|
||||
const computed = duplicate(limitesArchetypes);
|
||||
const computed = foundry.utils.duplicate(limitesArchetypes);
|
||||
computed.forEach(it => { it.nombre = 0; it.reste = it.nombreMax; });
|
||||
|
||||
competences.map(it => Math.max(0, it.system.niveau_archetype))
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
import { RdDCombatManager } from "./rdd-combat.js";
|
||||
|
||||
const categories = {
|
||||
export const CATEGORIES_COMPETENCES_CREATURES = {
|
||||
"generale": { base: 0, label: "Générale" },
|
||||
"naturelle": { base: 0, label: "Arme naturelle" },
|
||||
"melee": { base: 0, label: "Mêlée" },
|
||||
@@ -15,10 +15,6 @@ const categories = {
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemCompetenceCreature extends Item {
|
||||
|
||||
static getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static setRollDataCreature(rollData) {
|
||||
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.system.carac_value } }
|
||||
@@ -31,32 +27,29 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
static armeCreature(item) {
|
||||
const categorieAttaque = RdDItemCompetenceCreature.getCategorieAttaque(item)
|
||||
if (categorieAttaque != undefined) {
|
||||
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
|
||||
let arme = item.clone();
|
||||
mergeObject(arme,
|
||||
{
|
||||
// cloner pour ne pas modifier la compétence
|
||||
return foundry.utils.mergeObject(item, {
|
||||
action: item.isCompetencePossession() ? 'possession' : 'attaque',
|
||||
system: {
|
||||
competence: arme.name,
|
||||
competence: item.name,
|
||||
cac: categorieAttaque == "naturelle" ? "naturelle" : "",
|
||||
niveau: item.system.niveau,
|
||||
initiative: RdDCombatManager.calculInitiative(item.system.niveau, item.system.carac_value),
|
||||
equipe: true,
|
||||
resistance: 100,
|
||||
dommagesReels: arme.system.dommages,
|
||||
dommagesReels: item.system.dommages,
|
||||
penetration: 0,
|
||||
force: 0,
|
||||
rapide: true,
|
||||
}
|
||||
});
|
||||
return arme;
|
||||
}, { inplace: false, });
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceAttaque(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
static isAttaque(item) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
@@ -66,11 +59,11 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return false
|
||||
}
|
||||
|
||||
static getCategorieAttaque(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
@@ -83,8 +76,9 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static isDommages(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "tir":
|
||||
@@ -95,8 +89,9 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static isParade(item) {
|
||||
if (item.type == TYPES.competencecreature) {
|
||||
if (item.type == ITEM_TYPES.competencecreature) {
|
||||
switch (item.system.categorie) {
|
||||
case "melee":
|
||||
case "naturelle":
|
||||
@@ -107,8 +102,4 @@ export class RdDItemCompetenceCreature extends Item {
|
||||
return false
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isCompetenceParade(item) {
|
||||
return item.type == 'competencecreature' && item.system.categorie_parade !== "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ export class Monnaie {
|
||||
}
|
||||
|
||||
static creerDeniers(fortune) {
|
||||
const deniers = duplicate(MONNAIE_ETAIN);
|
||||
const deniers = foundry.utils.duplicate(MONNAIE_ETAIN);
|
||||
deniers.system.quantite = fortune;
|
||||
return deniers;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ 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";
|
||||
import { ITEM_TYPES, RdDItem } from "./item.js";
|
||||
|
||||
/**
|
||||
* Extend the basic ItemSheet for RdD specific items
|
||||
@@ -39,12 +39,12 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: [SYSTEM_RDD, "sheet", "item"],
|
||||
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
|
||||
width: 550,
|
||||
height: 550
|
||||
});
|
||||
}, { inplace: false });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -53,7 +53,8 @@ export class RdDItemSheet extends ItemSheet {
|
||||
}
|
||||
|
||||
get title() {
|
||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name}`;
|
||||
const owner = (this.item.parent instanceof Actor) ? `(${this.item.parent.name})` : '';
|
||||
return `${Misc.typeName('Item', this.item.type)}: ${this.item.name} ${owner}`;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -98,18 +99,18 @@ export class RdDItemSheet extends ItemSheet {
|
||||
description: await TextEditor.enrichHTML(this.item.system.description, { async: true }),
|
||||
descriptionmj: await TextEditor.enrichHTML(this.item.system.descriptionmj, { async: true }),
|
||||
isComestible: this.item.getUtilisationCuisine(),
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable)
|
||||
options: RdDSheetUtility.mergeDocumentRights(this.options, this.item, this.isEditable),
|
||||
}
|
||||
if (this.item.type == TYPES.competencecreature) {
|
||||
if (this.item.type == ITEM_TYPES.competencecreature) {
|
||||
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
|
||||
formData.isdommages = RdDItemCompetenceCreature.isDommages(this.item)
|
||||
}
|
||||
|
||||
const competences = await SystemCompendiums.getCompetences('personnage');
|
||||
formData.categories = this.item.getCategories()
|
||||
formData.categories = RdDItem.getCategories(this.item.type)
|
||||
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
|
||||
formData.caracList = duplicate(game.system.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = duplicate(game.system.model.Actor.personnage.reve.reve)
|
||||
formData.caracList = foundry.utils.duplicate(game.model.Actor.personnage.carac)
|
||||
formData.caracList["reve-actuel"] = foundry.utils.duplicate(game.model.Actor.personnage.reve.reve)
|
||||
formData.competences = competences;
|
||||
}
|
||||
if (this.item.type == 'arme') {
|
||||
@@ -228,7 +229,7 @@ export class RdDItemSheet extends ItemSheet {
|
||||
});
|
||||
}
|
||||
|
||||
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: duplicate(timestamp) })
|
||||
const updateItemTimestamp = (path, timestamp) => this.item.update({ [path]: foundry.utils.duplicate(timestamp) })
|
||||
|
||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.debut', updateItemTimestamp);
|
||||
RdDTimestamp.handleTimestampEditor(this.html, 'system.temporel.fin', updateItemTimestamp);
|
||||
@@ -257,7 +258,7 @@ export class RdDItemSheet extends ItemSheet {
|
||||
|
||||
if (this.item.isCompetence()) {
|
||||
const categorie = event.currentTarget.value;
|
||||
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.getCategories());
|
||||
const level = RdDItemCompetence.getNiveauBase(categorie, this.item.type);
|
||||
this.item.system.base = level;
|
||||
this.html.find('[name="system.base"]').val(level);
|
||||
}
|
||||
@@ -266,10 +267,17 @@ export class RdDItemSheet extends ItemSheet {
|
||||
/* -------------------------------------------- */
|
||||
/** @override */
|
||||
_updateObject(event, formData) {
|
||||
if (this.item.type == 'sort') {
|
||||
// Données de bonus de cases ?
|
||||
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue);
|
||||
switch (this.item.type) {
|
||||
case ITEM_TYPES.sort:
|
||||
// Données de bonus de cases ?
|
||||
formData['system.bonuscase'] = RdDItemSort.buildBonuscaseFromArrays(formData.bonusValue, formData.caseValue)
|
||||
break
|
||||
case ITEM_TYPES.competence:
|
||||
if (formData['system.niveau'] == undefined) {
|
||||
formData['system.niveau'] = formData['system.base']
|
||||
}
|
||||
}
|
||||
|
||||
return this.item.update(formData);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,59 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
|
||||
const VOIES_DRACONIC = [
|
||||
{ code: 'O', label: "Voie d'Oniros", short: 'Oniros', ordre: 'a' },
|
||||
{ code: 'H', label: "Voie d'Hypnos", short: 'Hypnos', ordre: 'b' },
|
||||
{ code: 'N', label: "Voie de Narcos", short: 'Narcos', ordre: 'c' },
|
||||
{ code: 'T', label: "Voie de Thanatos", short: 'Thanatos', ordre: 'd' },
|
||||
{ code: 'O/H/N/T', label: "Oniros/Hypnos/Narcos/Thanatos", short: 'Oniros/Hypnos/Narcos/Thanatos', ordre: 'e' },
|
||||
{ code: 'O/H/N', label: "Oniros/Hypnos/Narcos", short: "Oniros/Hypnos/Narcos", ordre: 'f' }
|
||||
]
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDItemSort extends Item {
|
||||
|
||||
static getDraconicsSort(draconicList, sort) {
|
||||
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
|
||||
case "lecture d'aura":
|
||||
case "detection d'aura":
|
||||
return draconicList;
|
||||
case "annulation de magie":
|
||||
return draconicList.filter(it => !RdDItemCompetence.isThanatos(it));
|
||||
}
|
||||
return [RdDItemCompetence.getVoieDraconic(draconicList, sort.system.draconic)];
|
||||
}
|
||||
|
||||
static getOrdreCode(code) {
|
||||
return (VOIES_DRACONIC.find(it => it.code == code)?.ordre ?? '?')
|
||||
}
|
||||
|
||||
static getVoieCode(voie) {
|
||||
return VOIES_DRACONIC.find(it => voie.name.includes(it.short))?.code ?? '?'
|
||||
}
|
||||
|
||||
static getCodeDraconic(sort, voies = ['O', 'H', 'N', 'T']) {
|
||||
switch (Grammar.toLowerCaseNoAccent(sort.name)) {
|
||||
case "lecture d'aura":
|
||||
case "detection d'aura":
|
||||
return RdDItemSort.$voiesConnues('O/H/N/T', voies)
|
||||
case "annulation de magie":
|
||||
return RdDItemSort.$voiesConnues('O/H/N', voies)
|
||||
}
|
||||
const voie = VOIES_DRACONIC.find(it => it.label.includes(sort.system.draconic))
|
||||
return voie?.code ?? sort.system.draconic
|
||||
}
|
||||
|
||||
|
||||
static $voiesConnues(voiesSort, voies) {
|
||||
const codes = voies.filter(it => voiesSort.includes(it))
|
||||
.sort(Misc.ascending(it => RdDItemSort.getOrdreCode(it)))
|
||||
return Misc.join(codes ?? [''], '/');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isDifficulteVariable(sort) {
|
||||
return sort && (sort.system.difficulte.toLowerCase() == "variable");
|
||||
@@ -31,9 +81,9 @@ export class RdDItemSort extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static buildBonusCaseList(bonuscase, newCase) {
|
||||
const list = RdDItemSort._bonuscaseStringToList(bonuscase)
|
||||
const list = RdDItemSort.bonuscaseStringToList(bonuscase)
|
||||
if (newCase) {
|
||||
return list.concat({ case: "Nouvelle", bonus: 0 });
|
||||
list.push({ case: "Nouvelle", bonus: 0 })
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -44,7 +94,7 @@ export class RdDItemSort extends Item {
|
||||
*/
|
||||
static getBonusCaseList(item, newCase = false) {
|
||||
// Gestion spéciale case bonus
|
||||
if (item.type == 'sort') {
|
||||
if (item.type == ITEM_TYPES.sort) {
|
||||
return RdDItemSort.buildBonusCaseList(item.system.bonuscase, newCase);
|
||||
}
|
||||
return undefined;
|
||||
@@ -104,8 +154,11 @@ export class RdDItemSort extends Item {
|
||||
.sort(Misc.ascending())
|
||||
.join(',');
|
||||
}
|
||||
static _bonuscaseStringToList(bonuscase) {
|
||||
return (bonuscase ?? '').split(',').map(it => {
|
||||
static bonuscaseStringToList(bonuscase) {
|
||||
if (bonuscase == undefined || bonuscase == '') {
|
||||
return []
|
||||
}
|
||||
return bonuscase.split(',').map(it => {
|
||||
const b = it.split(':');
|
||||
return { case: b[0], bonus: b[1] };
|
||||
});
|
||||
|
||||
168
module/item.js
168
module/item.js
@@ -1,4 +1,4 @@
|
||||
import { DialogItemVente } from "./dialog-item-vente.js";
|
||||
import { DialogItemVente } from "./achat-vente/dialog-item-vente.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
@@ -6,10 +6,18 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { RdDItemCompetence } from "./item-competence.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { CATEGORIES_COMPETENCES } from "./item-competence.js";
|
||||
import { CATEGORIES_COMPETENCES_CREATURES } from "./item-competencecreature.js";
|
||||
|
||||
export const TYPES = {
|
||||
export const ACTOR_TYPES = {
|
||||
personnage: 'personnage',
|
||||
creature: 'creature',
|
||||
entite: 'entite',
|
||||
commerce: 'commerce',
|
||||
vehicule: 'vehicule'
|
||||
}
|
||||
|
||||
export const ITEM_TYPES = {
|
||||
competence: 'competence',
|
||||
competencecreature: 'competencecreature',
|
||||
empoignade: 'empoignade',
|
||||
@@ -56,33 +64,33 @@ export const TYPES = {
|
||||
}
|
||||
|
||||
const typesInventaireMateriel = [
|
||||
TYPES.arme,
|
||||
TYPES.armure,
|
||||
TYPES.conteneur,
|
||||
TYPES.faune,
|
||||
TYPES.gemme,
|
||||
TYPES.herbe,
|
||||
TYPES.plante,
|
||||
TYPES.ingredient,
|
||||
TYPES.livre,
|
||||
TYPES.monnaie,
|
||||
TYPES.munition,
|
||||
TYPES.nourritureboisson,
|
||||
TYPES.objet,
|
||||
TYPES.potion,
|
||||
ITEM_TYPES.arme,
|
||||
ITEM_TYPES.armure,
|
||||
ITEM_TYPES.conteneur,
|
||||
ITEM_TYPES.faune,
|
||||
ITEM_TYPES.gemme,
|
||||
ITEM_TYPES.herbe,
|
||||
ITEM_TYPES.plante,
|
||||
ITEM_TYPES.ingredient,
|
||||
ITEM_TYPES.livre,
|
||||
ITEM_TYPES.monnaie,
|
||||
ITEM_TYPES.munition,
|
||||
ITEM_TYPES.nourritureboisson,
|
||||
ITEM_TYPES.objet,
|
||||
ITEM_TYPES.potion,
|
||||
]
|
||||
const typesInventaire = {
|
||||
materiel: typesInventaireMateriel,
|
||||
all: ['service'].concat(typesInventaireMateriel),
|
||||
}
|
||||
|
||||
const typesObjetsOeuvres = [TYPES.oeuvre, TYPES.recettecuisine, TYPES.musique, TYPES.chant, TYPES.danse, TYPES.jeu]
|
||||
const typesObjetsDraconiques = [TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.tete, TYPES.signedraconique, TYPES.sortreserve, TYPES.rencontre]
|
||||
const typesObjetsConnaissance = [TYPES.meditation, TYPES.recettealchimique, TYPES.sort]
|
||||
const typesObjetsEffet = [TYPES.possession, TYPES.poison, TYPES.maladie, TYPES.blessure]
|
||||
const typesObjetsCompetence = [TYPES.competence, TYPES.competencecreature]
|
||||
const typesObjetsTemporels = [TYPES.blessure, TYPES.poison, TYPES.maladie, TYPES.queue, TYPES.ombre, TYPES.souffle, TYPES.signedraconique, TYPES.rencontre]
|
||||
const typesObjetsEquipable = [TYPES.arme, TYPES.armure, TYPES.objet];
|
||||
const typesObjetsOeuvres = [ITEM_TYPES.oeuvre, ITEM_TYPES.recettecuisine, ITEM_TYPES.musique, ITEM_TYPES.chant, ITEM_TYPES.danse, ITEM_TYPES.jeu]
|
||||
const typesObjetsDraconiques = [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.tete, ITEM_TYPES.signedraconique, ITEM_TYPES.sortreserve, ITEM_TYPES.rencontre]
|
||||
const typesObjetsConnaissance = [ITEM_TYPES.meditation, ITEM_TYPES.recettealchimique, ITEM_TYPES.sort]
|
||||
const typesObjetsEffet = [ITEM_TYPES.possession, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.blessure]
|
||||
const typesObjetsCompetence = [ITEM_TYPES.competence, ITEM_TYPES.competencecreature]
|
||||
const typesObjetsTemporels = [ITEM_TYPES.blessure, ITEM_TYPES.poison, ITEM_TYPES.maladie, ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle, ITEM_TYPES.signedraconique, ITEM_TYPES.rencontre]
|
||||
const typesObjetsEquipable = [ITEM_TYPES.arme, ITEM_TYPES.armure, ITEM_TYPES.objet];
|
||||
const typesEnvironnement = typesInventaireMateriel;
|
||||
const encBrin = 0.00005; // un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
|
||||
const encPepin = 0.0007; /* un pépin de gemme = 1/10 cm3 = 1/1000 l = 3.5/1000 kg = 7/2000 kg = 7/1000 enc
|
||||
@@ -141,12 +149,12 @@ export class RdDItem extends Item {
|
||||
static isFieldInventaireModifiable(type, field) {
|
||||
switch (field) {
|
||||
case 'quantite':
|
||||
if ([TYPES.conteneur].includes(type)) {
|
||||
if ([ITEM_TYPES.conteneur].includes(type)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 'cout':
|
||||
if ([TYPES.monnaie].includes(type)) {
|
||||
if ([ITEM_TYPES.monnaie].includes(type)) {
|
||||
return game.user.isGM;
|
||||
}
|
||||
break;
|
||||
@@ -164,9 +172,11 @@ export class RdDItem extends Item {
|
||||
static getItemTypesInventaire(mode = 'materiel') {
|
||||
return typesInventaire[mode ?? 'materiel']
|
||||
}
|
||||
|
||||
static getItemTypesDraconiques() {
|
||||
return typesObjetsDraconiques;
|
||||
}
|
||||
|
||||
static getItemTypesEnvironnement() {
|
||||
return typesEnvironnement;
|
||||
}
|
||||
@@ -175,9 +185,19 @@ export class RdDItem extends Item {
|
||||
return typesObjetsOeuvres
|
||||
}
|
||||
|
||||
static getCategories(itemType) {
|
||||
switch (itemType) {
|
||||
case ITEM_TYPES.competence:
|
||||
return CATEGORIES_COMPETENCES
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return CATEGORIES_COMPETENCES_CREATURES
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
constructor(docData, context = {}) {
|
||||
if (!context.rdd?.ready) {
|
||||
mergeObject(context, { rdd: { ready: true } });
|
||||
foundry.utils.mergeObject(context, { rdd: { ready: true } });
|
||||
const ItemConstructor = game.system.rdd.itemClasses[docData.type];
|
||||
if (ItemConstructor) {
|
||||
if (!docData.img) {
|
||||
@@ -189,20 +209,21 @@ export class RdDItem extends Item {
|
||||
if (!docData.img) {
|
||||
docData.img = RdDItem.getDefaultImg(docData.type);
|
||||
}
|
||||
context.rdd = undefined
|
||||
super(docData, context);
|
||||
}
|
||||
|
||||
getUniteQuantite() {
|
||||
switch (this.type) {
|
||||
case TYPES.monnaie: return "(Pièces)"
|
||||
case TYPES.herbe:
|
||||
case ITEM_TYPES.monnaie: return "(Pièces)"
|
||||
case ITEM_TYPES.herbe:
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'Repos': case 'Soin':
|
||||
return "(Brins)"
|
||||
case 'Cuisine': return '';
|
||||
}
|
||||
return '';
|
||||
case TYPES.ingredient: return "(Pépins ou Brins)"
|
||||
case ITEM_TYPES.ingredient: return "(Pépins ou Brins)"
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@@ -211,13 +232,13 @@ export class RdDItem extends Item {
|
||||
return typesObjetsEquipable.includes(this.type)
|
||||
}
|
||||
|
||||
isCompetencePersonnage() { return this.type == TYPES.competence }
|
||||
isCompetenceCreature() { return this.type == TYPES.competencecreature }
|
||||
isConteneur() { return this.type == TYPES.conteneur; }
|
||||
isMonnaie() { return this.type == TYPES.monnaie; }
|
||||
isPotion() { return this.type == TYPES.potion; }
|
||||
isNourritureBoisson() { return this.type == TYPES.nourritureboisson; }
|
||||
isService() { return this.type == TYPES.service; }
|
||||
isCompetencePersonnage() { return this.type == ITEM_TYPES.competence }
|
||||
isCompetenceCreature() { return this.type == ITEM_TYPES.competencecreature }
|
||||
isConteneur() { return this.type == ITEM_TYPES.conteneur; }
|
||||
isMonnaie() { return this.type == ITEM_TYPES.monnaie; }
|
||||
isPotion() { return this.type == ITEM_TYPES.potion; }
|
||||
isNourritureBoisson() { return this.type == ITEM_TYPES.nourritureboisson; }
|
||||
isService() { return this.type == ITEM_TYPES.service; }
|
||||
|
||||
isCompetence() { return typesObjetsCompetence.includes(this.type) }
|
||||
isEsquive() {
|
||||
@@ -233,33 +254,26 @@ export class RdDItem extends Item {
|
||||
}
|
||||
|
||||
isCompetenceArme() {
|
||||
return this.isCompetence() && [ 'melee','tir', 'lancer'].includes(this.system.categorie)
|
||||
return this.isCompetence() && ['melee', 'tir', 'lancer'].includes(this.system.categorie)
|
||||
}
|
||||
|
||||
isCompetencePossession() { return TYPES.competencecreature == this.type && this.system.categorie == "possession" }
|
||||
isCompetencePossession() { return ITEM_TYPES.competencecreature == this.type && this.system.categorie == "possession" }
|
||||
isTemporel() { return typesObjetsTemporels.includes(this.type) }
|
||||
isOeuvre() { return typesObjetsOeuvres.includes(this.type) }
|
||||
isDraconique() { return RdDItem.getItemTypesDraconiques().includes(this.type) }
|
||||
isQueueDragon() { return [TYPES.queue, TYPES.ombre].includes(this.type) }
|
||||
isQueueDragon() { return [ITEM_TYPES.queue, ITEM_TYPES.ombre].includes(this.type) }
|
||||
isEffet() { return typesObjetsEffet.includes(this.type) }
|
||||
isConnaissance() { return typesObjetsConnaissance.includes(this.type) }
|
||||
|
||||
isInventaire(mode = 'materiel') { return RdDItem.getItemTypesInventaire(mode).includes(this.type); }
|
||||
isBoisson() { return this.isNourritureBoisson() && this.system.boisson; }
|
||||
isAlcool() { return this.isNourritureBoisson() && this.system.boisson && this.system.alcoolise; }
|
||||
isHerbeAPotion() { return this.type == TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == TYPES.blessure }
|
||||
isHerbeAPotion() { return this.type == ITEM_TYPES.herbe && (this.system.categorie == 'Soin' || this.system.categorie == 'Repos'); }
|
||||
isBlessure() { return this.type == ITEM_TYPES.blessure }
|
||||
|
||||
isPresentDansMilieux(milieux) {
|
||||
return this.getEnvironnements(milieux).length > 0
|
||||
}
|
||||
getCategories() {
|
||||
switch (this.type) {
|
||||
case TYPES.competence: return RdDItemCompetence.getCategories()
|
||||
case TYPES.competencecreature: return RdDItemCompetenceCreature.getCategories()
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
getEnvironnements(milieux = undefined) {
|
||||
const environnements = this.isInventaire() ? this.system.environnement : undefined;
|
||||
@@ -317,8 +331,8 @@ export class RdDItem extends Item {
|
||||
const timestampFin = await this.calculerFinPeriodeTemporel(timestampDebut);
|
||||
await actor.updateEmbeddedDocuments('Item', [{
|
||||
_id: this.id,
|
||||
'system.temporel.debut': duplicate(timestampDebut),
|
||||
'system.temporel.fin': duplicate(timestampFin),
|
||||
'system.temporel.debut': foundry.utils.duplicate(timestampDebut),
|
||||
'system.temporel.fin': foundry.utils.duplicate(timestampFin),
|
||||
}])
|
||||
}
|
||||
}
|
||||
@@ -340,15 +354,15 @@ export class RdDItem extends Item {
|
||||
|
||||
getUtilisation() {
|
||||
switch (this.type) {
|
||||
case TYPES.potion:
|
||||
case ITEM_TYPES.potion:
|
||||
switch (this.system.categorie) {
|
||||
case 'Alchimie': case 'AlchimieEnchante': case 'AlchimieAutre': return 'alchimie'
|
||||
case 'Cuisine': return 'cuisine'
|
||||
case 'Remede': case 'Repos': case 'ReposEnchante': case 'Soin': case 'SoinEnchante': return 'soins'
|
||||
}
|
||||
return '';
|
||||
case TYPES.nourritureboisson: return 'cuisine';
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
case ITEM_TYPES.nourritureboisson: return 'cuisine';
|
||||
case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
|
||||
switch (this.system.categorie) {
|
||||
case 'Cuisine': return 'cuisine';
|
||||
case 'Toxique': case 'Poison': return 'poison';
|
||||
@@ -363,9 +377,9 @@ export class RdDItem extends Item {
|
||||
getUtilisationCuisine() {
|
||||
if (this.getUtilisation() == 'cuisine') {
|
||||
switch (this.type) {
|
||||
case TYPES.nourritureboisson:
|
||||
case ITEM_TYPES.nourritureboisson:
|
||||
return 'pret';
|
||||
case TYPES.herbe: case TYPES.faune: case TYPES.ingredient: case TYPES.plante:
|
||||
case ITEM_TYPES.herbe: case ITEM_TYPES.faune: case ITEM_TYPES.ingredient: case ITEM_TYPES.plante:
|
||||
return 'brut';
|
||||
}
|
||||
}
|
||||
@@ -373,7 +387,7 @@ export class RdDItem extends Item {
|
||||
}
|
||||
|
||||
isCristalAlchimique() {
|
||||
return this.type == TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
|
||||
return this.type == ITEM_TYPES.objet && Grammar.includesLowerCaseNoAccent(this.name, 'cristal alchimique') && this.system.quantite > 0;
|
||||
}
|
||||
|
||||
isMagique() {
|
||||
@@ -401,11 +415,11 @@ export class RdDItem extends Item {
|
||||
|
||||
getEnc() {
|
||||
switch (this.type) {
|
||||
case TYPES.service:
|
||||
case ITEM_TYPES.service:
|
||||
return 0;
|
||||
case TYPES.herbe:
|
||||
case ITEM_TYPES.herbe:
|
||||
return this.getEncHerbe();
|
||||
case TYPES.gemme:
|
||||
case ITEM_TYPES.gemme:
|
||||
return encPepin * this.system.taille;
|
||||
}
|
||||
return Math.max(this.system.encombrement ?? 0, 0);
|
||||
@@ -483,7 +497,7 @@ export class RdDItem extends Item {
|
||||
|
||||
getActionPrincipale(options = { warnIfNot: true }) {
|
||||
switch (this.type) {
|
||||
case TYPES.conteneur: return 'Ouvrir';
|
||||
case ITEM_TYPES.conteneur: return 'Ouvrir';
|
||||
}
|
||||
if (this.actor?.isPersonnage()) {
|
||||
const warn = options.warnIfNot;
|
||||
@@ -491,11 +505,11 @@ export class RdDItem extends Item {
|
||||
return 'Cuisiner';
|
||||
}
|
||||
switch (this.type) {
|
||||
case TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
|
||||
case TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn);
|
||||
case TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
|
||||
case TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
|
||||
case TYPES.queue: case TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
|
||||
case ITEM_TYPES.nourritureboisson: return this._actionOrWarnQuantiteZero(this.system.boisson ? 'Boire' : 'Manger', warn);
|
||||
case ITEM_TYPES.potion: return this._actionOrWarnQuantiteZero('Consommer', warn);
|
||||
case ITEM_TYPES.livre: return this._actionOrWarnQuantiteZero('Lire', warn);
|
||||
case ITEM_TYPES.herbe: return this.isHerbeAPotion() ? this._actionOrWarnQuantiteZero('Décoction', warn) : undefined;
|
||||
case ITEM_TYPES.queue: case ITEM_TYPES.ombre: return this.system.refoulement > 0 ? 'Refouler' : undefined;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -538,7 +552,7 @@ export class RdDItem extends Item {
|
||||
_id: this.id,
|
||||
'system.quantite': this.system.quantite * sust,
|
||||
'system.encombrement': Misc.keepDecimals(this.system.encombrement / sust, 2),
|
||||
'system.cout': Misc.keepDecimals(this.system.cout / sust, 2),
|
||||
'system.cout': Math.max(0, Misc.keepDecimals(this.system.cout / sust, 2)),
|
||||
'system.sust': 1
|
||||
}])
|
||||
}
|
||||
@@ -621,23 +635,7 @@ export class RdDItem extends Item {
|
||||
ui.notifications.warn(`Votre ${this.name} n'est pas vide, pas possible de le proposer`);
|
||||
return;
|
||||
}
|
||||
await DialogItemVente.display({
|
||||
item: this,
|
||||
quantiteMax,
|
||||
callback: async (vente) => {
|
||||
vente["properties"] = this.getProprietes();
|
||||
if (vente.isOwned) {
|
||||
if (vente.quantiteNbLots * vente.tailleLot > vente.quantiteMax) {
|
||||
ui.notifications.warn(`Vous avez ${vente.quantiteMax} ${vente.item.name}, ce n'est pas suffisant pour vendre ${vente.quantiteNbLots} de ${vente.tailleLot}`)
|
||||
return;
|
||||
}
|
||||
}
|
||||
vente.jsondata = JSON.stringify(vente.item);
|
||||
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', vente);
|
||||
ChatMessage.create(RdDUtility.chatDataSetup(html));
|
||||
}
|
||||
});
|
||||
await DialogItemVente.display({ item: this, quantiteMax })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
|
||||
const BASE_TACHE_SOIN_BLESSURE = {
|
||||
type: "tache",
|
||||
@@ -14,10 +15,10 @@ const TACHES_SOIN_BLESSURE = {
|
||||
}
|
||||
|
||||
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: "contusion", gravite: 0, endurance: "1d4", vie: 0, label: 'Contusion/éraflure', max: 100, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/eraflure.webp" },
|
||||
{ type: "legere", gravite: 2, endurance: "1d6", vie: 0, label: 'Légère', max: 5, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "grave", gravite: 4, endurance: "2d6", vie: -2, label: 'Grave', max: 2, icon: "systems/foundryvtt-reve-de-dragon/icons/sante/blessure.webp" },
|
||||
{ type: "critique", gravite: 6, endurance: "-100", vie: -4, 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" }
|
||||
]
|
||||
|
||||
@@ -38,9 +39,35 @@ export class RdDItemBlessure extends RdDItem {
|
||||
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
|
||||
return undefined;
|
||||
}
|
||||
return mergeObject(duplicate(BASE_TACHE_SOIN_BLESSURE), tache)
|
||||
return foundry.utils.mergeObject(BASE_TACHE_SOIN_BLESSURE, tache, { inplace: false })
|
||||
}
|
||||
static async createBlessure(actor, gravite, localisation = '', attacker) {
|
||||
|
||||
static async applyFullBlessure(actor, gravite) {
|
||||
const definition = RdDItemBlessure.getDefinition(gravite)
|
||||
|
||||
let lostEndurance = 0
|
||||
let lostVie = 0
|
||||
if (definition.endurance) {
|
||||
lostEndurance = await new Roll(definition.endurance).roll().total;
|
||||
actor.santeIncDec("endurance", -Number(lostEndurance));
|
||||
}
|
||||
if (definition.vie) {
|
||||
lostVie = definition.vie
|
||||
actor.santeIncDec("vie", definition.vie)
|
||||
}
|
||||
|
||||
await this.createBlessure(actor, gravite)
|
||||
|
||||
ChatMessage.create({
|
||||
content: `Blessure ${definition.label} appliquée à ${actor.name}`+
|
||||
`<br>Perte d'endurance : ${lostEndurance}`+
|
||||
`<br>Perte de Vie : ${lostVie}`,
|
||||
whisper: ChatUtility.getOwners(actor)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static async createBlessure(actor, gravite, localisation = '', attackerToken) {
|
||||
const definition = RdDItemBlessure.getDefinition(gravite)
|
||||
const blessure = {
|
||||
name: definition.label,
|
||||
@@ -50,7 +77,7 @@ export class RdDItemBlessure extends RdDItem {
|
||||
gravite: gravite,
|
||||
difficulte: - gravite,
|
||||
localisation: localisation,
|
||||
origine: attacker?.name ?? ""
|
||||
origine: attackerToken?.name ?? ""
|
||||
}
|
||||
}
|
||||
const blessures = await actor.createEmbeddedDocuments('Item', [blessure])
|
||||
@@ -79,12 +106,12 @@ export class RdDItemBlessure extends RdDItem {
|
||||
}
|
||||
|
||||
async setSoinsBlessure(systemUpdate = {}) {
|
||||
systemUpdate = mergeObject(systemUpdate, this.system, { overwrite: false }),
|
||||
systemUpdate.soinscomplets.done = systemUpdate.premierssoins.done && systemUpdate.soinscomplets.done
|
||||
systemUpdate = foundry.utils.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 }) {
|
||||
@@ -107,14 +134,14 @@ export class RdDItemBlessure extends RdDItem {
|
||||
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, {
|
||||
foundry.utils.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, {
|
||||
foundry.utils.mergeObject(update, {
|
||||
system: {
|
||||
gravite: graviteMoindre,
|
||||
temporel: { fin: { indexDate: timestamp.addJours(graviteMoindre).indexDate } }
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { RdDTimestamp } from "../time/rdd-timestamp.js";
|
||||
@@ -21,9 +22,12 @@ export class RdDItemMaladie extends RdDItem {
|
||||
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);
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getOwners(mal.actor),
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +42,7 @@ export class RdDItemMaladie extends RdDItem {
|
||||
|
||||
await mal.actor.updateEmbeddedDocuments('Item', [{
|
||||
_id: mal.id,
|
||||
'system.temporel.fin': duplicate(timestampFin),
|
||||
'system.temporel.fin': foundry.utils.duplicate(timestampFin),
|
||||
}])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ const TYPE_ITEMS_NATURELS = ["faune", "herbe", "plante", "ingredient"];
|
||||
export class RdDItemInventaireSheet extends RdDItemSheet {
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(RdDItemSheet.defaultOptions, {
|
||||
return foundry.utils.mergeObject(RdDItemSheet.defaultOptions, {
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "informations" }]
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
setPosition(options = {}) {
|
||||
@@ -23,9 +23,10 @@ export class RdDItemInventaireSheet extends RdDItemSheet {
|
||||
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
return mergeObject(formData, {
|
||||
foundry.utils.mergeObject(formData, {
|
||||
milieux: await game.system.rdd.environnement.autresMilieux(this.item)
|
||||
});
|
||||
})
|
||||
return formData
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
|
||||
@@ -6,9 +6,9 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
|
||||
static get ITEM_TYPE() { return "rencontre" };
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -24,7 +24,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
|
||||
/* -------------------------------------------- */
|
||||
async getData() {
|
||||
const formData = await super.getData();
|
||||
mergeObject(formData, {
|
||||
foundry.utils.mergeObject(formData, {
|
||||
effets: {
|
||||
succes: {
|
||||
liste: RdDRencontre.getEffetsSucces(),
|
||||
@@ -35,7 +35,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
|
||||
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
return formData;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,10 @@ import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { LOG_HEAD, SYSTEM_RDD } from "./constants.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { Monnaie } from "./item-monnaie.js";
|
||||
import { RdDItem, TYPES } from "./item.js";
|
||||
import { RdDItem, ITEM_TYPES } from "./item.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { RdDRaretes } from "./item/raretes.js";
|
||||
import { RdDCalendrier } from "./time/rdd-calendrier.js";
|
||||
|
||||
class Migration {
|
||||
get code() { return "sample"; }
|
||||
@@ -70,17 +71,17 @@ class _10_0_16_MigrationSortsReserve extends Migration {
|
||||
get version() { return "10.0.16"; }
|
||||
|
||||
async migrate() {
|
||||
await game.actors
|
||||
.filter((actor) => actor.type == "personnage")
|
||||
.filter((actor) => actor.system.reve?.reserve?.list?.length ?? 0 > 0)
|
||||
.forEach(async (actor) => {
|
||||
const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve);
|
||||
console.log(`${LOG_HEAD} Migration des sorts en réserve de ${actor.name}`, sortsReserve);
|
||||
await actor.createEmbeddedDocuments("Item", sortsReserve, {
|
||||
renderSheet: false,
|
||||
});
|
||||
await actor.update({ 'system.reve.reserve': undefined })
|
||||
});
|
||||
const actors = game.actors.filter((actor) => actor.type == "personnage" && (actor.system.reve?.reserve?.list?.length ?? 0 > 0))
|
||||
Promise.all(actors.map(async it => await this.convertirSortsReserveActeur(it)))
|
||||
}
|
||||
|
||||
async convertirSortsReserveActeur(actor) {
|
||||
const sortsReserve = actor.system.reve.reserve.list.map(this.conversionSortReserve);
|
||||
console.log(`${LOG_HEAD} Migration des sorts en réserve de ${actor.name}`, sortsReserve);
|
||||
await actor.createEmbeddedDocuments("Item", sortsReserve, {
|
||||
renderSheet: false,
|
||||
});
|
||||
await actor.update({ 'system.reve.reserve': undefined });
|
||||
}
|
||||
|
||||
conversionSortReserve(it) {
|
||||
@@ -189,7 +190,7 @@ class _10_2_5_ArmesTirLancer extends Migration {
|
||||
get version() { return "10.2.5"; }
|
||||
|
||||
migrateArmeTirLancer(it) {
|
||||
let updates = mergeObject({ _id: it.id }, this.getMapping(it).updates);
|
||||
let updates = foundry.utils.mergeObject({ _id: it.id }, this.getMapping(it).updates);
|
||||
console.log(it.name, updates);
|
||||
return updates;
|
||||
}
|
||||
@@ -364,7 +365,7 @@ class _10_4_6_ServicesEnCommerces extends Migration {
|
||||
const item = await RdDItem.getCorrespondingItem(serviceRefItem);
|
||||
const itemToCreate = {
|
||||
name: item.name, img: item.img, type: item.type,
|
||||
system: mergeObject({ cout: serviceRefItem.system.cout, quantite: serviceRefItem.system.quantite }, item.system, { overwrite: false })
|
||||
system: foundry.utils.mergeObject({ cout: serviceRefItem.system.cout, quantite: serviceRefItem.system.quantite }, item.system, { overwrite: false })
|
||||
};
|
||||
return itemToCreate;
|
||||
}
|
||||
@@ -464,7 +465,7 @@ class _10_7_19_CategorieCompetenceCreature extends Migration {
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => TYPES.competencecreature == it.type)
|
||||
.filter(it => ITEM_TYPES.competencecreature == it.type)
|
||||
.map(it => this.migrateCompetenceCreature(it))
|
||||
);
|
||||
}
|
||||
@@ -501,19 +502,34 @@ class _10_7_19_PossessionsEntiteVictime extends Migration {
|
||||
|
||||
async migrate() {
|
||||
await this.applyItemsUpdates(items => items
|
||||
.filter(it => TYPES.possession == it.type)
|
||||
.filter(it => ITEM_TYPES.possession == it.type)
|
||||
.map(it => this.migratePossession(it))
|
||||
);
|
||||
}
|
||||
|
||||
migratePossession(it) {
|
||||
return { _id: it.id,
|
||||
return {
|
||||
_id: it.id,
|
||||
'system.entite.actorid': it.system.possesseurid,
|
||||
'system.victime.actorid': it.system.possedeid
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _11_2_20_MigrationAstrologie extends Migration {
|
||||
get code() { return "migration-astrologie" }
|
||||
get version() { return "11.2.20" }
|
||||
|
||||
async migrate() {
|
||||
const nombresAstraux = game.system.rdd.calendrier.getNombresAstraux()
|
||||
nombresAstraux.forEach(na => {
|
||||
na.lectures = na.valeursFausses
|
||||
na.valeursFausses = undefined
|
||||
})
|
||||
await game.system.rdd.calendrier.setNombresAstraux(nombresAstraux)
|
||||
}
|
||||
}
|
||||
|
||||
export class Migrations {
|
||||
static getMigrations() {
|
||||
return [
|
||||
@@ -532,6 +548,7 @@ export class Migrations {
|
||||
new _10_7_0_MigrationBlessures(),
|
||||
new _10_7_19_CategorieCompetenceCreature(),
|
||||
new _10_7_19_PossessionsEntiteVictime(),
|
||||
new _11_2_20_MigrationAstrologie(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -546,15 +563,18 @@ export class Migrations {
|
||||
}
|
||||
|
||||
migrate() {
|
||||
const currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion");
|
||||
if (isNewerVersion(game.system.version, currentVersion)) {
|
||||
let currentVersion = game.settings.get(SYSTEM_RDD, "systemMigrationVersion")
|
||||
if (currentVersion.startsWith("v")) {
|
||||
currentVersion = currentVersion.substring(1)
|
||||
}
|
||||
if (foundry.utils.isNewerVersion(game.system.version, currentVersion)) {
|
||||
// if (true) { /* comment previous and uncomment here to test before upgrade */
|
||||
const migrations = Migrations.getMigrations().filter(m => isNewerVersion(m.version, currentVersion));
|
||||
const migrations = Migrations.getMigrations().filter(m => foundry.utils.isNewerVersion(m.version, currentVersion));
|
||||
if (migrations.length > 0) {
|
||||
migrations.sort((a, b) => this.compareVersions(a, b));
|
||||
migrations.forEach(async (m) => {
|
||||
ui.notifications.info(
|
||||
`Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}`
|
||||
`${LOG_HEAD} Executing migration ${m.code}: version ${currentVersion} is lower than ${m.version}`
|
||||
);
|
||||
await m.migrate();
|
||||
});
|
||||
@@ -562,9 +582,7 @@ export class Migrations {
|
||||
`Migrations done, version will change to ${game.system.version}`
|
||||
);
|
||||
} else {
|
||||
console.log(
|
||||
LOG_HEAD +
|
||||
`No migration needeed, version will change to ${game.system.version}`
|
||||
console.log(`${LOG_HEAD} No migration needeed, version will change to ${game.system.version}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -574,7 +592,7 @@ export class Migrations {
|
||||
game.system.version
|
||||
);
|
||||
} else {
|
||||
console.log(LOG_HEAD + `No system version changed`);
|
||||
console.log(`${LOG_HEAD} No system version changed`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ export class Misc {
|
||||
}
|
||||
|
||||
static typeName(type, subType) {
|
||||
return subType ? game.i18n.localize(`TYPES.${type}.${Misc.upperFirst(subType)}`)
|
||||
return subType ? game.i18n.localize(`TYPES.${type}.${subType}`)
|
||||
: '';
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ export class Misc {
|
||||
}
|
||||
|
||||
static join(params, separator = '') {
|
||||
return params?.reduce(Misc.joining(separator)) ?? '';
|
||||
return (!params || params.length == 0) ? '' : params.reduce(Misc.joining(separator))
|
||||
}
|
||||
|
||||
static joining(separator = '') {
|
||||
@@ -166,22 +166,54 @@ export class Misc {
|
||||
}
|
||||
|
||||
static firstConnectedGM() {
|
||||
return game.users.filter(u => u.isGM && u.active).sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active);
|
||||
if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
|
||||
return game.users.activeGM
|
||||
}
|
||||
return game.users.find(u => u.isGM && u.active);
|
||||
}
|
||||
|
||||
static isOwnerPlayer(actor, user = undefined) {
|
||||
return actor.testUserPermission(user ?? game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER)
|
||||
static connectedGMs() {
|
||||
return game.users.filter(u => u.isGM && u.active);
|
||||
}
|
||||
|
||||
static isOwnerPlayerOrUniqueConnectedGM(actor, user = undefined) {
|
||||
return Misc.isOwnerPlayer(actor, user) ?? Misc.isUniqueConnectedGM();
|
||||
/**
|
||||
* This helper method allows to get the docuument, for a single user (either first connected GM, or the owner
|
||||
* if there is no connected GMs), or else return undefined.
|
||||
*
|
||||
* This allows for example update hooks that should apply modifications to actors to be called only for one
|
||||
* user (preventing the "User ... lacks permission to update Item" that was occuring on hooks when Item updates
|
||||
* were triggering other changes)
|
||||
*
|
||||
* @param {*} document the Document with is potentially an Actor
|
||||
* @returns the actor if either the game.user is the first connected GM, or if the game.user is the owner
|
||||
* and there is no connected GM
|
||||
*/
|
||||
static documentIfResponsible(document) {
|
||||
if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
|
||||
if (game.users.activeGM || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document)))
|
||||
{
|
||||
return document
|
||||
}
|
||||
}
|
||||
else if (Misc.isFirstConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) {
|
||||
return document
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static isOwnerPlayer(document) {
|
||||
return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
|
||||
}
|
||||
|
||||
static isOwnerPlayerOrUniqueConnectedGM(actor) {
|
||||
return Misc.isOwnerPlayer(actor) ?? Misc.isFirstConnectedGM();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true pour un seul utilisateur: le premier GM connecté par ordre d'id
|
||||
*/
|
||||
static isUniqueConnectedGM() {
|
||||
return game.user.id == Misc.firstConnectedGMId();
|
||||
static isFirstConnectedGM() {
|
||||
return game.user == Misc.firstConnectedGM();
|
||||
}
|
||||
|
||||
static firstConnectedGMId() {
|
||||
@@ -200,7 +232,7 @@ export class Misc {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static findFirstLike(value, elements, options = {}) {
|
||||
options = mergeObject({
|
||||
options = foundry.utils.mergeObject({
|
||||
mapper: it => it.name,
|
||||
preFilter: it => true,
|
||||
description: 'valeur',
|
||||
@@ -225,7 +257,7 @@ export class Misc {
|
||||
}
|
||||
|
||||
static findAllLike(value, elements, options = {}) {
|
||||
options = mergeObject({
|
||||
options = foundry.utils.mergeObject({
|
||||
mapper: it => it.name,
|
||||
preFilter: it => true,
|
||||
description: 'valeur',
|
||||
|
||||
@@ -15,7 +15,7 @@ export class RdDAudio {
|
||||
if ( audioData ) {
|
||||
let audioPath = "systems/foundryvtt-reve-de-dragon/sounds/" + audioData.file;
|
||||
console.log(`foundryvtt-reve-de-dragon | Playing Sound: ${audioPath}`)
|
||||
AudioHelper.play({ src: audioPath }, audioData.isGlobal);
|
||||
foundry.audio.AudioHelper.play({ src: audioPath }, audioData.isGlobal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ export class RdDBonus {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static dmg(rollData, dmgActor, isEntiteIncarnee = false) {
|
||||
const dmgArme = RdDBonus._dmgArme(rollData)
|
||||
static dmg(rollData, actor, isEntiteIncarnee = false) {
|
||||
const dmgArme = RdDBonus.dmgArme(rollData.arme)
|
||||
let dmg = {
|
||||
total: 0,
|
||||
dmgArme: dmgArme,
|
||||
@@ -41,7 +41,7 @@ export class RdDBonus {
|
||||
dmgParticuliere: RdDBonus._dmgParticuliere(rollData),
|
||||
dmgSurprise: RdDBonus.dmgBonus(rollData.ajustements?.attaqueDefenseurSurpris.used),
|
||||
mortalite: RdDBonus._calculMortalite(rollData, isEntiteIncarnee),
|
||||
dmgActor: RdDBonus._dmgPerso(dmgActor, rollData.selectedCarac?.label, dmgArme)
|
||||
dmgActor: RdDBonus.bonusDmg(actor, rollData.selectedCarac?.label.toLowerCase(), dmgArme)
|
||||
}
|
||||
dmg.total = dmg.dmgSurprise + dmg.dmgTactique + dmg.dmgArme + dmg.dmgActor + dmg.dmgParticuliere;
|
||||
return dmg;
|
||||
@@ -71,11 +71,11 @@ export class RdDBonus {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _dmgArme(rollData) {
|
||||
if (rollData.arme) {
|
||||
let dmgBase = rollData.arme.system.dommagesReels ?? Number(rollData.arme.system.dommages ?? 0);
|
||||
static dmgArme(arme) {
|
||||
if (arme) {
|
||||
let dmgBase = arme.system.dommagesReels ?? Number(arme.system.dommages ?? 0);
|
||||
//Le bonus dégats magiques ne peut pas faire dépasser le bonus de l'arme (cf p.278)
|
||||
return dmgBase + Math.min(dmgBase, rollData.arme.system.magique ? rollData.arme.system.ecaille_efficacite : 0);
|
||||
return dmgBase + Math.min(dmgBase, arme.system.magique ? arme.system.ecaille_efficacite : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -86,13 +86,14 @@ export class RdDBonus {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _dmgPerso(dmgActor, categorie, dmgArme) {
|
||||
static bonusDmg(actor, categorie, dmgArme) {
|
||||
const dmgActor = actor.getBonusDegat()
|
||||
if (categorie == undefined) {
|
||||
return 0
|
||||
}
|
||||
switch (categorie) {
|
||||
case "Tir": return 0;
|
||||
case "Lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
|
||||
case "tir": return 0;
|
||||
case "lancer": return Math.max(0, Math.min(dmgArme, dmgActor));
|
||||
}
|
||||
return dmgActor;
|
||||
}
|
||||
|
||||
@@ -3,38 +3,38 @@ import { Misc } from "./misc.js";
|
||||
|
||||
const TABLE_CARACTERISTIQUES_DERIVEES = {
|
||||
// xp: coût pour passer du niveau inférieur à ce niveau
|
||||
1: { xp: 3, poids: "moins de 1kg", plusdom: -5, sconst: 0.5, sust: 0.1 },
|
||||
2: { xp: 3, poids: "1-5", plusdom: -4, sconst: 0.5, sust: 0.3 },
|
||||
3: { xp: 4, poids: "6-10", plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
|
||||
4: { xp: 4, poids: "11-20", plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
|
||||
5: { xp: 5, poids: "21-30", plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
|
||||
6: { xp: 5, poids: "31-40", plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
|
||||
7: { xp: 6, poids: "41-50", plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
|
||||
8: { xp: 6, poids: "51-60", plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
|
||||
9: { xp: 7, poids: "61-65", plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
|
||||
10: { xp: 7, poids: "66-70", plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
|
||||
11: { xp: 8, poids: "71-75", plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
|
||||
12: { xp: 8, poids: "76-80", plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
|
||||
13: { xp: 9, poids: "81-90", plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
|
||||
14: { xp: 9, poids: "91-100", plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
|
||||
15: { xp: 10, poids: "101-110", plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
|
||||
16: { xp: 20, poids: "111-120", plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
|
||||
17: { xp: 30, poids: "121-131", plusdom: +3, sconst: 5, sust: 5 },
|
||||
18: { xp: 40, poids: "131-141", plusdom: +4, sconst: 6, sust: 5 },
|
||||
19: { xp: 50, poids: "141-150", plusdom: +4, sconst: 6, sust: 5 },
|
||||
20: { xp: 60, poids: "151-160", plusdom: +4, sconst: 6, sust: 6 },
|
||||
21: { xp: 70, poids: "161-180", plusdom: +5, sconst: 7, sust: 6 },
|
||||
22: { xp: 80, poids: "181-200", plusdom: +5, sconst: 7, sust: 7 },
|
||||
23: { xp: 90, poids: "201-300", plusdom: +6, sconst: 7, sust: 8 },
|
||||
24: { xp: 100, poids: "301-400", plusdom: +6, sconst: 8, sust: 9 },
|
||||
25: { xp: 110, poids: "401-500", plusdom: +7, sconst: 8, sust: 10 },
|
||||
26: { xp: 120, poids: "501-600", plusdom: +7, sconst: 8, sust: 11 },
|
||||
27: { xp: 130, poids: "601-700", plusdom: +8, sconst: 9, sust: 12 },
|
||||
28: { xp: 140, poids: "701-800", plusdom: +8, sconst: 9, sust: 13 },
|
||||
29: { xp: 150, poids: "801-900", plusdom: +9, sconst: 9, sust: 14 },
|
||||
30: { xp: 160, poids: "901-1000", plusdom: +9, sconst: 10, sust: 15 },
|
||||
31: { xp: 170, poids: "1001-1500", plusdom: +10, sconst: 10, sust: 16 },
|
||||
32: { xp: 180, poids: "1501-2000", plusdom: +11, sconst: 10, sust: 17 }
|
||||
1: { xp: 3, poids: "moins de 1kg", poidsMin: 0, poidsMax: 1, plusdom: -5, sconst: 0.5, sust: 0.1 },
|
||||
2: { xp: 3, poids: "1-5", poidsMin: 1, poidsMax: 5, plusdom: -4, sconst: 0.5, sust: 0.3 },
|
||||
3: { xp: 4, poids: "6-10", poidsMin: 6, poidsMax: 10, plusdom: -3, sconst: 1, sust: 0.5, beaute: 'hideux' },
|
||||
4: { xp: 4, poids: "11-20", poidsMin: 11, poidsMax: 20, plusdom: -3, sconst: 1, sust: 1, beaute: 'repoussant' },
|
||||
5: { xp: 5, poids: "21-30", poidsMin: 21, poidsMax: 30, plusdom: -2, sconst: 1, sust: 1, beaute: 'franchement très laid' },
|
||||
6: { xp: 5, poids: "31-40", poidsMin: 31, poidsMax: 40, plusdom: -1, sconst: 2, sust: 2, beaute: 'laid' },
|
||||
7: { xp: 6, poids: "41-50", poidsMin: 41, poidsMax: 50, plusdom: -1, sconst: 2, sust: 2, beaute: 'très désavantagé' },
|
||||
8: { xp: 6, poids: "51-60", poidsMin: 51, poidsMax: 60, plusdom: 0, sconst: 2, sust: 2, beaute: 'désavantagé' },
|
||||
9: { xp: 7, poids: "61-65", poidsMin: 61, poidsMax: 65, plusdom: 0, sconst: 3, sust: 2, beaute: 'pas terrible' },
|
||||
10: { xp: 7, poids: "66-70", poidsMin: 66, poidsMax: 70, plusdom: 0, sconst: 3, sust: 3, beaute: 'commun' },
|
||||
11: { xp: 8, poids: "71-75", poidsMin: 71, poidsMax: 75, plusdom: 0, sconst: 3, sust: 3, beaute: 'pas mal' },
|
||||
12: { xp: 8, poids: "76-80", poidsMin: 76, poidsMax: 80, plusdom: +1, sconst: 4, sust: 3, beaute: 'avantagé' },
|
||||
13: { xp: 9, poids: "81-90", poidsMin: 81, poidsMax: 90, plusdom: +1, sconst: 4, sust: 3, beaute: 'mignon' },
|
||||
14: { xp: 9, poids: "91-100", poidsMin: 91, poidsMax: 100, plusdom: +2, sconst: 4, sust: 4, beaute: 'beau' },
|
||||
15: { xp: 10, poids: "101-110", poidsMin: 101, poidsMax: 110, plusdom: +2, sconst: 5, sust: 4, beaute: 'très beau' },
|
||||
16: { xp: 20, poids: "111-120", poidsMin: 111, poidsMax: 120, plusdom: +3, sconst: 5, sust: 4, beaute: 'éblouissant' },
|
||||
17: { xp: 30, poids: "121-131", poidsMin: 121, poidsMax: 131, plusdom: +3, sconst: 5, sust: 5 },
|
||||
18: { xp: 40, poids: "131-141", poidsMin: 131, poidsMax: 141, plusdom: +4, sconst: 6, sust: 5 },
|
||||
19: { xp: 50, poids: "141-150", poidsMin: 141, poidsMax: 150, plusdom: +4, sconst: 6, sust: 5 },
|
||||
20: { xp: 60, poids: "151-160", poidsMin: 151, poidsMax: 160, plusdom: +4, sconst: 6, sust: 6 },
|
||||
21: { xp: 70, poids: "161-180", poidsMin: 161, poidsMax: 180, plusdom: +5, sconst: 7, sust: 6 },
|
||||
22: { xp: 80, poids: "181-200", poidsMin: 181, poidsMax: 200, plusdom: +5, sconst: 7, sust: 7 },
|
||||
23: { xp: 90, poids: "201-300", poidsMin: 201, poidsMax: 300, plusdom: +6, sconst: 7, sust: 8 },
|
||||
24: { xp: 100, poids: "301-400", poidsMin: 301, poidsMax: 400, plusdom: +6, sconst: 8, sust: 9 },
|
||||
25: { xp: 110, poids: "401-500", poidsMin: 401, poidsMax: 500, plusdom: +7, sconst: 8, sust: 10 },
|
||||
26: { xp: 120, poids: "501-600", poidsMin: 501, poidsMax: 600, plusdom: +7, sconst: 8, sust: 11 },
|
||||
27: { xp: 130, poids: "601-700", poidsMin: 601, poidsMax: 700, plusdom: +8, sconst: 9, sust: 12 },
|
||||
28: { xp: 140, poids: "701-800", poidsMin: 701, poidsMax: 800, plusdom: +8, sconst: 9, sust: 13 },
|
||||
29: { xp: 150, poids: "801-900", poidsMin: 801, poidsMax: 900, plusdom: +9, sconst: 9, sust: 14 },
|
||||
30: { xp: 160, poids: "901-1000", poidsMin: 901, poidsMax: 1000, plusdom: +9, sconst: 10, sust: 15 },
|
||||
31: { xp: 170, poids: "1001-1500", poidsMin: 1001, poidsMax: 1500, plusdom: +10, sconst: 10, sust: 16 },
|
||||
32: { xp: 180, poids: "1501-2000", poidsMin: 1501, poidsMax: 2000, plusdom: +11, sconst: 10, sust: 17 }
|
||||
};
|
||||
|
||||
export class RdDCarac {
|
||||
|
||||
@@ -42,7 +42,8 @@ export class RdDCombatManager extends Combat {
|
||||
/* -------------------------------------------- */
|
||||
Hooks.on("getCombatTrackerEntryContext", (html, options) => { RdDCombatManager.pushInitiativeOptions(html, options); });
|
||||
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
|
||||
Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() });
|
||||
Hooks.on("preDeleteCombat", (combat, html, id) => { combat.onPreDeleteCombat() })
|
||||
Hooks.on("deleteCombat", (combat, html, id) => { combat.onDeleteCombat() })
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -53,102 +54,110 @@ export class RdDCombatManager extends Combat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onPreDeleteCombat() {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
await this.finDeRound({ terminer: true });
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
await this.finDeRound({ terminer: true })
|
||||
ChatUtility.removeChatMessageContaining(`<div data-combatid="${this.id}" data-combatmessage="actor-turn-summary">`)
|
||||
game.messages.filter(m => ChatUtility.getMessageData(m, 'attacker-roll') != undefined && ChatUtility.getMessageData(m, 'defender-roll') != undefined)
|
||||
.forEach(it => it.delete());
|
||||
.forEach(it => it.delete())
|
||||
RdDEmpoignade.deleteAllEmpoignades()
|
||||
}
|
||||
}
|
||||
async onDeleteCombat() {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
if (game.combats.size <= 1) {
|
||||
game.actors.forEach(actor => actor.resetItemUse())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async finDeRound(options = { terminer: false }) {
|
||||
this.turns.forEach(turn => turn.actor.resetItemUse());
|
||||
this.combatants.map(it => RdDCombatManager.getActorCombatant(it, { warning: false }))
|
||||
.filter(it => it != undefined)
|
||||
.forEach(async actor => {
|
||||
await actor.finDeRound(options)
|
||||
await actor.resetItemUse()
|
||||
})
|
||||
}
|
||||
|
||||
for (let combatant of this.combatants) {
|
||||
if (combatant.actor) {
|
||||
await combatant.actor.finDeRound(options);
|
||||
}
|
||||
else {
|
||||
static getActorCombatant(combatant, options = { warning: true }) {
|
||||
if (!combatant.actor) {
|
||||
if (options.warning) {
|
||||
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur!`)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
else if (!combatant.actor.isActorCombat()) {
|
||||
if (options.warning) {
|
||||
ui.notifications.warn(`${combatant.name} ne peut pas combattre!`)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
return combatant.actor
|
||||
}
|
||||
|
||||
static calculAjustementInit(actor, arme) {
|
||||
const efficacite = (arme?.system.magique) ? arme.system.ecaille_efficacite : 0
|
||||
const etatGeneral = actor.getEtatGeneral() ?? 0
|
||||
return efficacite + etatGeneral
|
||||
|
||||
}
|
||||
|
||||
/************************************************************************************/
|
||||
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
|
||||
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
|
||||
async rollInitiative(ids, messageOptions = {}) {
|
||||
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, messageOptions)
|
||||
ids = typeof ids === "string" ? [ids] : ids
|
||||
ids.forEach(async id =>
|
||||
await this.rollInitRdD(id, undefined, messageOptions)
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
ids = typeof ids === "string" ? [ids] : ids;
|
||||
// calculate initiative
|
||||
for (let cId = 0; cId < ids.length; cId++) {
|
||||
const combatant = this.combatants.get(ids[cId]);
|
||||
let rollFormula = formula ?? RdDCombatManager.formuleInitiative(2, 10, 0, 0);
|
||||
if (!formula) {
|
||||
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
|
||||
const competence = combatant.actor.items.find(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||
if (competence) {
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, competence.system.carac_value, competence.system.niveau, 0);
|
||||
}
|
||||
} else {
|
||||
const armeCombat = combatant.actor.itemTypes['arme'].find(it => it.system.equipe)
|
||||
let compName = "Corps à corps"
|
||||
if (armeCombat) {
|
||||
if (armeCombat.system.competence != "") {
|
||||
compName = armeCombat.system.competence
|
||||
}
|
||||
if (armeCombat.system.lancer != "") {
|
||||
compName = armeCombat.system.lancer
|
||||
}
|
||||
if (armeCombat.system.tir != "") {
|
||||
compName = armeCombat.system.tir
|
||||
}
|
||||
}
|
||||
const competence = RdDItemCompetence.findCompetence(combatant.actor.items, compName);
|
||||
if (competence && competence.system.defaut_carac) {
|
||||
const carac = combatant.actor.system.carac[competence.system.defaut_carac].value;
|
||||
const niveau = competence.system.niveau;
|
||||
const bonusEcaille = (armeCombat?.system.magique) ? armeCombat.system.ecaille_efficacite : 0;
|
||||
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
|
||||
} else {
|
||||
ui.notifications.warn(`Votre arme ${armeCombat.name} n'a pas de compétence renseignée`);
|
||||
}
|
||||
}
|
||||
}
|
||||
//console.log("Combatat", c);
|
||||
async rollInitRdD(id, formula, messageOptions = {}) {
|
||||
const combatant = this.combatants.get(id);
|
||||
const actor = RdDCombatManager.getActorCombatant(combatant)
|
||||
if (actor) {
|
||||
const rollFormula = formula ?? RdDCombatManager.getFirstInitRollFormula(actor)
|
||||
const roll = combatant.getInitiativeRoll(rollFormula);
|
||||
if (!roll.total) {
|
||||
roll.evaluate({ async: false });
|
||||
await roll.evaluate();
|
||||
}
|
||||
const total = Math.max(roll.total, 0.00);
|
||||
console.log("Compute init for", rollFormula, roll, total, combatant);
|
||||
let id = combatant._id || combatant.id;
|
||||
await this.updateEmbeddedDocuments("Combatant", [{ _id: id, initiative: total }]);
|
||||
await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id || combatant.id, initiative: total }]);
|
||||
|
||||
// Send a chat message
|
||||
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
|
||||
let messageData = mergeObject(
|
||||
{
|
||||
speaker: {
|
||||
scene: canvas.scene._id,
|
||||
actor: combatant.actor?._id,
|
||||
token: combatant.token._id,
|
||||
alias: combatant.token.name,
|
||||
sound: CONFIG.sounds.dice,
|
||||
},
|
||||
flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
|
||||
<br>
|
||||
`,
|
||||
let messageData = foundry.utils.mergeObject({
|
||||
speaker: {
|
||||
scene: canvas.scene._id,
|
||||
actor: combatant.actor?._id,
|
||||
token: combatant.token._id,
|
||||
alias: combatant.token.name,
|
||||
sound: CONFIG.sounds.dice,
|
||||
},
|
||||
messageOptions
|
||||
);
|
||||
flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.info})<br>`
|
||||
},
|
||||
messageOptions);
|
||||
roll.toMessage(messageData, { rollMode, create: true });
|
||||
|
||||
RdDCombatManager.processPremierRoundInit();
|
||||
}
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
static getFirstInitRollFormula(actor) {
|
||||
const actions = actor.listActionsCombat()
|
||||
if (actions.length > 0) {
|
||||
const action = actions[0]
|
||||
const init = RdDCombatManager.getInitData(actor, action)
|
||||
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
|
||||
return RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
|
||||
}
|
||||
|
||||
let ajustement = RdDCombatManager.calculAjustementInit(actor, undefined);
|
||||
return RdDCombatManager.formuleInitiative(2, 10, 0, ajustement);
|
||||
}
|
||||
|
||||
static formuleInitiative(rang, carac, niveau, bonusMalus) {
|
||||
return `${rang} +( (${RdDCombatManager.calculInitiative(niveau, carac, bonusMalus)} )/100)`;
|
||||
@@ -218,72 +227,23 @@ export class RdDCombatManager extends Combat {
|
||||
|
||||
static $prepareAttaqueArme(infoAttaque) {
|
||||
const comp = infoAttaque.competences.find(c => c.name == infoAttaque.competence);
|
||||
const attaque = duplicate(infoAttaque.arme);
|
||||
const arme = infoAttaque.arme;
|
||||
const attaque = foundry.utils.duplicate(arme);
|
||||
attaque.action = 'attaque';
|
||||
attaque.system.competence = infoAttaque.competence;
|
||||
attaque.system.dommagesReels = infoAttaque.dommagesReel;
|
||||
attaque.system.infoMain = infoAttaque.infoMain;
|
||||
attaque.system.niveau = comp.system.niveau;
|
||||
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value);
|
||||
|
||||
const ajustement = (arme?.parent?.getEtatGeneral() ?? 0) + (arme?.system.magique) ? arme.system.ecaille_efficacite : 0;
|
||||
attaque.system.initiative = RdDCombatManager.calculInitiative(comp.system.niveau, infoAttaque.carac[comp.system.defaut_carac].value, ajustement);
|
||||
return attaque;
|
||||
}
|
||||
|
||||
static listActionsCreature(competences) {
|
||||
return competences
|
||||
.filter(it => RdDItemCompetenceCreature.isCompetenceAttaque(it))
|
||||
.map(it => RdDItemCompetenceCreature.armeCreature(it))
|
||||
.filter(it => it != undefined);
|
||||
}
|
||||
|
||||
static listActionsPossessions(actor) {
|
||||
return RdDCombatManager._indexActions(actor.getPossessions().map(p => {
|
||||
return {
|
||||
name: p.name,
|
||||
action: 'possession',
|
||||
system: {
|
||||
competence: p.name,
|
||||
possessionid: p.system.possessionid,
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static listActionsCombat(combatant) {
|
||||
const actor = combatant.actor;
|
||||
let actions = RdDCombatManager.listActionsPossessions(actor);
|
||||
if (actions.length > 0) {
|
||||
return actions;
|
||||
}
|
||||
if (actor.isCreatureEntite()) {
|
||||
actions = RdDCombatManager.listActionsCreature(actor.itemTypes['competencecreature']);
|
||||
} else if (actor.isPersonnage()) {
|
||||
// Recupération des items 'arme'
|
||||
const competences = actor.itemTypes['competence'];
|
||||
const armes = actor.itemTypes['arme'].filter(it => RdDItemArme.isArmeUtilisable(it))
|
||||
.concat(RdDItemArme.empoignade(actor))
|
||||
.concat(RdDItemArme.mainsNues(actor));
|
||||
actions = RdDCombatManager.listActionsArmes(armes, competences, actor.system.carac);
|
||||
|
||||
if (actor.system.attributs.hautrevant.value) {
|
||||
actions.push({ name: "Draconic", action: 'haut-reve', system: { initOnly: true, competence: "Draconic" } });
|
||||
}
|
||||
}
|
||||
|
||||
return RdDCombatManager._indexActions(actions);
|
||||
}
|
||||
|
||||
static _indexActions(actions) {
|
||||
for (let index = 0; index < actions.length; index++) {
|
||||
actions[index].index = index;
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static processPremierRoundInit() {
|
||||
// Check if we have the whole init !
|
||||
if (Misc.isUniqueConnectedGM() && game.combat.current.round == 1) {
|
||||
if (Misc.isFirstConnectedGM() && game.combat.current.round == 1) {
|
||||
let initMissing = game.combat.combatants.find(it => !it.initiative);
|
||||
if (!initMissing) { // Premier round !
|
||||
for (let combatant of game.combat.combatants) {
|
||||
@@ -317,13 +277,13 @@ export class RdDCombatManager extends Combat {
|
||||
/* -------------------------------------------- */
|
||||
static pushInitiativeOptions(html, options) {
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
let option = options[i];
|
||||
let option = options[i]
|
||||
if (option.name == 'COMBAT.CombatantReroll') { // Replace !
|
||||
option.name = "Sélectionner l'initiative...";
|
||||
option.condition = true;
|
||||
option.icon = '<i class="far fa-question-circle"></i>';
|
||||
option.name = "Sélectionner l'initiative..."
|
||||
option.condition = true
|
||||
option.icon = '<i class="far fa-question-circle"></i>'
|
||||
option.callback = target => {
|
||||
RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id'));
|
||||
RdDCombatManager.displayInitiativeMenu(html, target.data('combatant-id'))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -334,97 +294,83 @@ export class RdDCombatManager extends Combat {
|
||||
}
|
||||
/* -------------------------------------------- */
|
||||
static rollInitiativeAction(combatantId, action) {
|
||||
const combatant = game.combat.combatants.get(combatantId);
|
||||
if (combatant.actor == undefined) {
|
||||
ui.notifications.warn(`Le combatant ${combatant.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
|
||||
return [];
|
||||
}
|
||||
const combatant = game.combat.combatants.get(combatantId)
|
||||
const actor = RdDCombatManager.getActorCombatant(combatant)
|
||||
if (actor == undefined) { return [] }
|
||||
|
||||
let initInfo = "";
|
||||
let initOffset = 0;
|
||||
let caracForInit = 0;
|
||||
let compNiveau = 0;
|
||||
let compData = { name: "Aucune" };
|
||||
if (combatant.actor.getSurprise() == "totale") {
|
||||
initOffset = -1; // To force 0
|
||||
initInfo = "Surprise Totale"
|
||||
} else if (combatant.actor.getSurprise() == "demi") {
|
||||
initOffset = 0;
|
||||
initInfo = "Demi Surprise"
|
||||
} else if (action.action == 'possession') {
|
||||
initOffset = 10;
|
||||
caracForInit = combatant.actor.getReveActuel();
|
||||
initInfo = "Possession"
|
||||
} else if (action.action == 'autre') {
|
||||
initOffset = 2;
|
||||
initInfo = "Autre Action"
|
||||
} else if (action.action == 'haut-reve') {
|
||||
initOffset = 9;
|
||||
initInfo = "Draconic"
|
||||
} else {
|
||||
compData = RdDItemCompetence.findCompetence(combatant.actor.items, action.system.competence);
|
||||
compNiveau = compData.system.niveau;
|
||||
initInfo = action.name + " / " + action.system.competence;
|
||||
|
||||
if (combatant.actor.type == 'creature' || combatant.actor.type == 'entite') {
|
||||
caracForInit = compData.system.carac_value;
|
||||
} else {
|
||||
caracForInit = combatant.actor.system.carac[compData.system.defaut_carac].value;
|
||||
}
|
||||
initOffset = RdDCombatManager._baseInitOffset(compData.system.categorie, action);
|
||||
}
|
||||
|
||||
let malus = combatant.actor.getEtatGeneral(); // Prise en compte état général
|
||||
// Cas des créatures et entités vs personnages
|
||||
let rollFormula = RdDCombatManager.formuleInitiative(initOffset, caracForInit, compNiveau, malus);
|
||||
// Garder la trace de l'arme/compétence utilisée pour l'iniative
|
||||
combatant.initiativeData = { arme: action } // pour reclasser l'init au round 0
|
||||
game.combat.rollInitiative(combatantId, rollFormula, { initInfo: initInfo });
|
||||
|
||||
const init = RdDCombatManager.getInitData(actor, action)
|
||||
const ajustement = RdDCombatManager.calculAjustementInit(actor, action)
|
||||
const rollFormula = RdDCombatManager.formuleInitiative(init.offset, init.carac, init.niveau, ajustement);
|
||||
|
||||
game.combat.rollInitRdD(combatantId, rollFormula, init);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static _baseInitOffset(categorie, arme) {
|
||||
if (categorie == "tir") { // Offset de principe pour les armes de jet
|
||||
return 8;
|
||||
static getInitData(actor, action) {
|
||||
if (actor.getSurprise() == "totale") { return { offset: -1, info: "Surprise Totale", carac: 0, niveau: 0 } }
|
||||
if (actor.getSurprise() == "demi") { return { offset: 0, info: "Demi Surprise", carac: 0, niveau: 0 } }
|
||||
if (action.action == 'autre') { return { offset: 2, info: "Autre Action", carac: 0, niveau: 0 } }
|
||||
if (action.action == 'possession') { return { offset: 10, info: "Possession", carac: actor.getReveActuel(), niveau: 0 } }
|
||||
if (action.action == 'haut-reve') { return { offset: 9, info: "Draconic", carac: actor.getReveActuel(), niveau: 0 } }
|
||||
|
||||
const comp = RdDItemCompetence.findCompetence(actor.items, action.system.competence);
|
||||
return {
|
||||
offset: RdDCombatManager.initOffset(comp?.system.categorie, action),
|
||||
info: action.name + " / " + action.system.competence,
|
||||
carac: actor.getCaracInit(comp),
|
||||
niveau: comp?.system.niveau ?? -8
|
||||
}
|
||||
if (categorie == "lancer") { // Offset de principe pour les armes de jet
|
||||
return 7;
|
||||
}
|
||||
|
||||
static initOffset(categorie, arme) {
|
||||
switch (categorie) {
|
||||
case "tir": return 8
|
||||
case "lancer": return 7
|
||||
default:
|
||||
switch (arme.system.cac) {
|
||||
case "empoignade": return 3
|
||||
case "pugilat": return 4
|
||||
case "naturelle": return 4
|
||||
default: return 5
|
||||
}
|
||||
}
|
||||
switch (arme.system.cac) {
|
||||
case "empoignade":
|
||||
return 3;
|
||||
case "pugilat":
|
||||
case "naturelle":
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static displayInitiativeMenu(html, combatantId) {
|
||||
console.log("Combatant ; ", combatantId);
|
||||
const combatant = game.combat.combatants.get(combatantId);
|
||||
if (!(combatant?.actor)) {
|
||||
ui.notifications.warn(`Le combatant ${combatant.name ?? combatantId} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
|
||||
return;
|
||||
}
|
||||
|
||||
let actions = RdDCombatManager.listActionsCombat(combatant);
|
||||
|
||||
// Build the relevant submenu
|
||||
if (actions) {
|
||||
let menuItems = [];
|
||||
for (let action of actions) {
|
||||
menuItems.push({
|
||||
const combatant = game.combat.combatants.get(combatantId)
|
||||
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
|
||||
if (actor) {
|
||||
const actions = RdDCombatManager.listActionsActorCombatant(actor)
|
||||
// Build the relevant submenu
|
||||
const menuItems = actions.map(action => {
|
||||
return {
|
||||
name: action.system.competence,
|
||||
icon: "<i class='fas fa-dice-d6'></i>",
|
||||
callback: target => { RdDCombatManager.rollInitiativeAction(combatantId, action) }
|
||||
});
|
||||
}
|
||||
})
|
||||
if (menuItems.length > 0) {
|
||||
new ContextMenu(html, ".directory-list", menuItems).render();
|
||||
}
|
||||
new ContextMenu(html, ".directory-list", menuItems).render();
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static listActionsActorCombatant( actor) {
|
||||
const possessions = actor.listActionsPossessions()
|
||||
const actions = possessions.length > 0
|
||||
? possessions
|
||||
: actor.listActionsCombat()
|
||||
|
||||
for (let index = 0; index < actions.length; index++) {
|
||||
actions[index].index = index
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -447,11 +393,11 @@ export class RdDCombat {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static combatNouveauTour(combat) {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId);
|
||||
if (turn?.actor) {
|
||||
RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token.id);
|
||||
// TODO Playaudio for player??
|
||||
RdDCombat.displayActorCombatStatus(combat, turn.actor, turn.token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,52 +408,51 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static rddCombatTarget(target, attacker) {
|
||||
const defender = target?.actor;
|
||||
const defenderTokenId = target?.id;
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
static rddCombatTarget(target, attacker, attackerToken) {
|
||||
return new RdDCombat(attacker, attackerToken?.id, target?.actor, target?.id, target)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static rddCombatForAttackerAndDefender(attackerId, defenderTokenId) {
|
||||
const attacker = game.actors.get(attackerId);
|
||||
let defender = defenderTokenId ? canvas.tokens.get(defenderTokenId)?.actor : undefined;
|
||||
static rddCombatForAttackerAndDefender(attackerId, attackerTokenId, defenderTokenId) {
|
||||
const attacker = game.actors.get(attackerId)
|
||||
const defenderToken = defenderTokenId ? canvas.tokens.get(defenderTokenId) : undefined
|
||||
let defender = defenderToken?.actor;
|
||||
let target = undefined
|
||||
if (!defenderTokenId || !defender) {
|
||||
console.warn(`RdDCombat.rddCombatForAttackerAndDefender: appel avec defenderTokenId ${defenderTokenId} incorrect, ou pas de defender correspondant`);
|
||||
target = Targets.getTarget()
|
||||
if (!target) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
defenderTokenId = target.id;
|
||||
defender = target.actor;
|
||||
if (!defenderTokenId || !defender) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
}
|
||||
return new RdDCombat(attacker, defender, defenderTokenId, target)
|
||||
return new RdDCombat(attacker, attackerTokenId, defender, defenderTokenId, target)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onMsgEncaisser(msg) {
|
||||
let defender = canvas.tokens.get(msg.defenderTokenId).actor;
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM()) {
|
||||
let attackerRoll = msg.attackerRoll;
|
||||
let attacker = msg.attackerId ? game.actors.get(msg.attackerId) : undefined;
|
||||
let defender = canvas.tokens.get(msg.defenderToken.id).actor;
|
||||
|
||||
defender.encaisserDommages(attackerRoll, attacker);
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
defender.encaisserDommages(attackerRoll, attacker, msg.attackerToken);
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id);
|
||||
rddCombat?.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onMsgDefense(msg) {
|
||||
let defenderToken = canvas.tokens.get(msg.defenderTokenId);
|
||||
if (defenderToken && Misc.isUniqueConnectedGM()) {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
|
||||
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme);
|
||||
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll);
|
||||
let defenderToken = canvas.tokens.get(msg.defenderToken.id)
|
||||
if (defenderToken && Misc.isFirstConnectedGM()) {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(msg.attackerId, msg.attackerToken.id, msg.defenderToken.id)
|
||||
rddCombat?.removeChatMessageActionsPasseArme(msg.defenderRoll.passeArme)
|
||||
rddCombat?._chatMessageDefense(msg.paramChatDefense, msg.defenderRoll)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,6 +483,7 @@ export class RdDCombat {
|
||||
html.on("click", button, event => {
|
||||
const rddCombat = RdDCombat.rddCombatForAttackerAndDefender(
|
||||
event.currentTarget.attributes['data-attackerId']?.value,
|
||||
event.currentTarget.attributes['data-attackerTokenId']?.value,
|
||||
event.currentTarget.attributes['data-defenderTokenId']?.value);
|
||||
if (rddCombat) {
|
||||
rddCombat.onEvent(button, event);
|
||||
@@ -553,22 +499,38 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
constructor(attacker, defender, defenderTokenId, target) {
|
||||
constructor(attacker, attackerTokenId, defender, defenderTokenId, target) {
|
||||
this.attacker = attacker
|
||||
this.defender = defender
|
||||
this.target = target
|
||||
this.attackerId = this.attacker.id
|
||||
this.defenderId = this.defender.id
|
||||
this.attackerTokenId = attackerTokenId
|
||||
this.defenderTokenId = defenderTokenId
|
||||
this.attackerToken = RdDCombat.$extractAttackerTokenData(attacker, attackerTokenId)
|
||||
this.defenderToken = RdDCombat.$extractDefenderTokenData(defender, defenderTokenId, target)
|
||||
}
|
||||
|
||||
static $extractAttackerTokenData(attacker, attackerTokenId) {
|
||||
const token = canvas.tokens.get(attackerTokenId);
|
||||
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(attackerTokenId, attacker)
|
||||
}
|
||||
|
||||
static $extractDefenderTokenData(defender, defenderTokenId, target) {
|
||||
if (target) {
|
||||
return Targets.extractTokenData(target)
|
||||
}
|
||||
const token = canvas.tokens.get(defenderTokenId);
|
||||
return token ? Targets.extractTokenData(token) : Targets.buildActorTokenData(defenderTokenId, defender)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onEvent(button, event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event);
|
||||
const defenderRoll = ChatUtility.getMessageData(chatMessage, 'defender-roll');
|
||||
const attackerRoll = defenderRoll?.attackerRoll ?? ChatUtility.getMessageData(chatMessage, 'attacker-roll');
|
||||
console.log('RdDCombat', attackerRoll, defenderRoll);
|
||||
const defenderTokenId = event.currentTarget.attributes['data-defenderTokenId']?.value;
|
||||
|
||||
const armeParadeId = event.currentTarget.attributes['data-armeid']?.value;
|
||||
const competence = event.currentTarget.attributes['data-competence']?.value;
|
||||
@@ -578,7 +540,7 @@ export class RdDCombat {
|
||||
case '#particuliere-attaque': return await this.choixParticuliere(attackerRoll, event.currentTarget.attributes['data-mode'].value);
|
||||
case '#parer-button': return this.parade(attackerRoll, armeParadeId);
|
||||
case '#esquiver-button': return this.esquive(attackerRoll, compId, competence);
|
||||
case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll, defenderTokenId);
|
||||
case '#encaisser-button': return this.encaisser(attackerRoll, defenderRoll);
|
||||
case '#echec-total-attaque': return this._onEchecTotal(attackerRoll);
|
||||
|
||||
case '#appel-chance-attaque': return this.attacker.rollAppelChance(
|
||||
@@ -691,11 +653,11 @@ export class RdDCombat {
|
||||
if (this.defender.isEntite([ENTITE_BLURETTE])) {
|
||||
ChatMessage.create({
|
||||
content: `<strong>La cible est une blurette, l'arme à distance sera perdue dans le blurêve`,
|
||||
whisper: ChatMessage.getWhisperRecipients("GM")
|
||||
whisper: ChatUtility.getGMs()
|
||||
})
|
||||
}
|
||||
else {
|
||||
const defenderToken = canvas.tokens.get(this.defenderTokenId);
|
||||
const defenderToken = canvas.tokens.get(this.defenderTokenId)
|
||||
const dist = this.distance(_token, defenderToken)
|
||||
const isVisible = this.isVisible(_token, defenderToken)
|
||||
const portee = this._ajustementPortee(dist, rollData.arme)
|
||||
@@ -714,7 +676,7 @@ export class RdDCombat {
|
||||
activite: activite,
|
||||
total: total
|
||||
}),
|
||||
whisper: ChatMessage.getWhisperRecipients("GM")
|
||||
whisper: ChatUtility.getGMs()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -762,7 +724,7 @@ export class RdDCombat {
|
||||
}
|
||||
RdDEmpoignade.checkEmpoignadeEnCours(this.attacker)
|
||||
|
||||
let rollData = this._prepareAttaque(competence, arme);
|
||||
let rollData = this._prepareAttaque(competence, arme)
|
||||
console.log("RdDCombat.attaque >>>", rollData);
|
||||
if (arme) {
|
||||
this.attacker.verifierForceMin(arme);
|
||||
@@ -788,15 +750,18 @@ export class RdDCombat {
|
||||
dialog.render(true);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_prepareAttaque(competence, arme) {
|
||||
let rollData = {
|
||||
passeArme: randomID(16),
|
||||
alias: this.attackerToken.name,
|
||||
passeArme: foundry.utils.randomID(16),
|
||||
mortalite: arme?.system.mortalite,
|
||||
competence: competence,
|
||||
surprise: this.attacker.getSurprise(true),
|
||||
surpriseDefenseur: this.defender.getSurprise(true),
|
||||
targetToken: Targets.extractTokenData(this.target),
|
||||
sourceToken: this.attackerToken,
|
||||
targetToken: this.defenderToken,
|
||||
essais: {}
|
||||
};
|
||||
|
||||
@@ -839,11 +804,12 @@ export class RdDCombat {
|
||||
|
||||
const choixParticuliere = await ChatMessage.create({
|
||||
alias: this.attacker.name,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
whisper: ChatUtility.getOwners(this.attacker),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-particuliere.html', {
|
||||
alias: this.attacker.name,
|
||||
alias: this.attackerToken.name,
|
||||
attackerId: this.attackerId,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken,
|
||||
isForce: isForce,
|
||||
isFinesse: isFinesse,
|
||||
isRapide: isRapide,
|
||||
@@ -857,10 +823,10 @@ export class RdDCombat {
|
||||
async _onAttaqueNormale(attackerRoll) {
|
||||
console.log("RdDCombat.onAttaqueNormale >>>", attackerRoll);
|
||||
|
||||
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker.getBonusDegat(), this.defender.isEntite());
|
||||
attackerRoll.dmg = RdDBonus.dmg(attackerRoll, this.attacker, this.defender.isEntite());
|
||||
let defenderRoll = { attackerRoll: attackerRoll, passeArme: attackerRoll.passeArme, show: {} }
|
||||
attackerRoll.show = {
|
||||
cible: this.target ? this.defender.name : 'la cible',
|
||||
cible: this.defenderToken?.name ?? 'la cible',
|
||||
isRecul: (attackerRoll.particuliere == 'force' || attackerRoll.tactique == 'charge')
|
||||
}
|
||||
await RdDResolutionTable.displayRollData(attackerRoll, this.attacker, 'chat-resultat-attaque.html');
|
||||
@@ -885,13 +851,13 @@ export class RdDCombat {
|
||||
|
||||
this.removeChatMessageActionsPasseArme(attackerRoll.passeArme);
|
||||
if (essaisPrecedents) {
|
||||
mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
|
||||
foundry.utils.mergeObject(attackerRoll.essais, essaisPrecedents, { overwrite: true });
|
||||
}
|
||||
|
||||
// # utilisation esquive
|
||||
const corpsACorps = this.defender.getCompetenceCorpsACorps({ onMessage: it => console.info(it, this.defender) });
|
||||
const esquives = duplicate(this.defender.getCompetencesEsquive())
|
||||
esquives.forEach(e => e.system.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
|
||||
const esquives = foundry.utils.duplicate(this.defender.getCompetencesEsquive())
|
||||
esquives.forEach(e => e.nbUsage = e?._id ? this.defender.getItemUse(e._id) : 0);
|
||||
|
||||
const paramChatDefense = {
|
||||
passeArme: attackerRoll.passeArme,
|
||||
@@ -901,7 +867,8 @@ export class RdDCombat {
|
||||
attacker: this.attacker,
|
||||
attackerId: this.attackerId,
|
||||
esquives: esquives,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken,
|
||||
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps,
|
||||
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
|
||||
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
|
||||
@@ -912,7 +879,7 @@ export class RdDCombat {
|
||||
dmg: attackerRoll.dmg,
|
||||
};
|
||||
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
await this._chatMessageDefense(paramChatDefense, defenderRoll);
|
||||
}
|
||||
else {
|
||||
@@ -925,8 +892,8 @@ export class RdDCombat {
|
||||
const choixDefense = await ChatMessage.create({
|
||||
// message privé: du défenseur à lui même (et aux GMs)
|
||||
speaker: ChatMessage.getSpeaker(this.defender, canvas.tokens.get(this.defenderTokenId)),
|
||||
alias: this.attacker.name,
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.defender.name),
|
||||
alias: this.attackerToken.name,
|
||||
whisper: ChatUtility.getOwners(this.defender),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-defense.html', paramDemandeDefense),
|
||||
});
|
||||
// flag pour garder les jets d'attaque/defense
|
||||
@@ -939,8 +906,9 @@ export class RdDCombat {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_defense", data: {
|
||||
attackerId: this.attacker?.id,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderId: this.defender?.id,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
defenderToken: this.defenderToken,
|
||||
defenderRoll: defenderRoll,
|
||||
paramChatDefense: paramChatDefense,
|
||||
rollMode: true
|
||||
@@ -949,31 +917,33 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_filterArmesParade(defender, competence) {
|
||||
let items = defender.items.filter(it => RdDItemArme.isArmeUtilisable(it) || RdDItemCompetenceCreature.isCompetenceParade(it))
|
||||
items.forEach(item => item.system.nbUsage = defender.getItemUse(item.id)); // Ajout du # d'utilisation ce round
|
||||
_filterArmesParade(defender, competence, armeAttaque) {
|
||||
let defenses = defender.items.filter(it => RdDItemArme.isParade(it))
|
||||
defenses = foundry.utils.duplicate(defenses)
|
||||
defenses.forEach(armeDefense => {
|
||||
// Ajout du # d'utilisation ce round
|
||||
armeDefense.nbUsage = defender.getItemUse(armeDefense.id)
|
||||
armeDefense.typeParade = RdDItemArme.defenseArmeParade(armeAttaque, armeDefense)
|
||||
})
|
||||
|
||||
switch (competence.system.categorie) {
|
||||
case 'tir':
|
||||
case 'lancer':
|
||||
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
|
||||
return defenses.filter(armeDefense => RdDItemArme.getCategorieParade(armeDefense) == 'boucliers')
|
||||
default:
|
||||
// Le fléau ne peut être paré qu’au bouclier p115
|
||||
if (competence.name == "Fléau") {
|
||||
return items.filter(item => RdDItemArme.getCategorieParade(item) == 'boucliers')
|
||||
}
|
||||
return items.filter(item => RdDItemArme.getCategorieParade(item));
|
||||
return defenses.filter(armeDefense => armeDefense.typeParade != '')
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async _onAttaqueEchecTotal(attackerRoll) {
|
||||
const choixEchecTotal = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
|
||||
whisper: ChatUtility.getOwners(this.attacker),
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
|
||||
attackerId: this.attackerId,
|
||||
attacker: this.attacker,
|
||||
defenderTokenId: this.defenderTokenId,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken,
|
||||
essais: attackerRoll.essais
|
||||
})
|
||||
});
|
||||
@@ -987,9 +957,9 @@ export class RdDCombat {
|
||||
const arme = rollData.arme;
|
||||
const avecArme = !['', 'sans-armes', 'armes-naturelles'].includes(arme?.system.categorie_parade ?? '');
|
||||
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
|
||||
ChatUtility.createChatWithRollMode(this.defender.name, {
|
||||
content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme })
|
||||
});
|
||||
ChatUtility.createChatWithRollMode(
|
||||
{ content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme }) },
|
||||
this.defender)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -1045,8 +1015,11 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_prepareParade(attackerRoll, armeParade, competenceParade) {
|
||||
let defenderRoll = {
|
||||
alias: this.defenderToken?.name,
|
||||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken,
|
||||
attackerRoll: attackerRoll,
|
||||
competence: this.defender.getCompetence(competenceParade),
|
||||
arme: armeParade,
|
||||
@@ -1069,9 +1042,9 @@ export class RdDCombat {
|
||||
console.log("RdDCombat._onParadeParticuliere >>>", defenderRoll);
|
||||
if (!defenderRoll.attackerRoll.isPart) {
|
||||
// TODO: attaquant doit jouer résistance et peut être désarmé p132
|
||||
ChatUtility.createChatWithRollMode(this.defender.name, {
|
||||
content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)`
|
||||
});
|
||||
ChatUtility.createChatWithRollMode(
|
||||
{ content: `(à gérer) L'attaquant doit jouer résistance et peut être désarmé (p132)` },
|
||||
this.defender)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1126,8 +1099,11 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_prepareEsquive(attackerRoll, competence) {
|
||||
let rollData = {
|
||||
alias: this.defenderToken?.name,
|
||||
passeArme: attackerRoll.passeArme,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken,
|
||||
attackerRoll: attackerRoll,
|
||||
competence: competence,
|
||||
surprise: this.defender.getSurprise(true),
|
||||
@@ -1145,9 +1121,9 @@ export class RdDCombat {
|
||||
/* -------------------------------------------- */
|
||||
_onEsquiveParticuliere(rollData) {
|
||||
console.log("RdDCombat._onEsquiveParticuliere >>>", rollData);
|
||||
ChatUtility.createChatWithRollMode(this.defender.name, {
|
||||
content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>"
|
||||
});
|
||||
ChatUtility.createChatWithRollMode(
|
||||
{ content: "<strong>Vous pouvez esquiver une deuxième fois!</strong>" },
|
||||
this.defender);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -1269,9 +1245,8 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async encaisser(attackerRoll, defenderRoll, defenderTokenId) {
|
||||
defenderTokenId = defenderTokenId || this.defenderTokenId;
|
||||
console.log("RdDCombat.encaisser >>>", attackerRoll, defenderTokenId);
|
||||
async encaisser(attackerRoll, defenderRoll) {
|
||||
console.log("RdDCombat.encaisser >>>", attackerRoll, defenderRoll);
|
||||
|
||||
if (defenderRoll?.rolled && RdDCombat.isEchecTotal(defenderRoll)) {
|
||||
this._onEchecTotal(defenderRoll);
|
||||
@@ -1279,18 +1254,19 @@ export class RdDCombat {
|
||||
|
||||
if (Misc.isOwnerPlayerOrUniqueConnectedGM(this.defender)) {
|
||||
attackerRoll.attackerId = this.attackerId;
|
||||
attackerRoll.defenderTokenId = defenderTokenId;
|
||||
attackerRoll.defenderTokenId = this.defenderToken.id;
|
||||
|
||||
await this.computeRecul(defenderRoll);
|
||||
this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show);
|
||||
await this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll?.show, this.attackerToken, this.defenderToken);
|
||||
}
|
||||
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_encaisser",
|
||||
data: {
|
||||
attackerId: this.attackerId,
|
||||
defenderTokenId: defenderTokenId,
|
||||
attackerRoll: attackerRoll
|
||||
attackerRoll: attackerRoll,
|
||||
attackerToken: this.attackerToken,
|
||||
defenderToken: this.defenderToken
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1298,28 +1274,31 @@ export class RdDCombat {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async displayActorCombatStatus(combat, actor, tokenId) {
|
||||
let formData = {
|
||||
static async displayActorCombatStatus(combat, actor, token) {
|
||||
if (!actor?.isActorCombat()) {
|
||||
return
|
||||
}
|
||||
const formData = {
|
||||
combatId: combat._id,
|
||||
alias: actor.name,
|
||||
alias: token.name ?? actor.name,
|
||||
etatGeneral: actor.getEtatGeneral(),
|
||||
isSonne: actor.getSonne(),
|
||||
isSonne: actor.isSonne(),
|
||||
blessuresStatus: actor.computeResumeBlessure(),
|
||||
SConst: actor.getSConst(),
|
||||
actorId: actor.id,
|
||||
actor: actor,
|
||||
tokenId: tokenId,
|
||||
tokenId: token.id,
|
||||
isGrave: actor.countBlessures(it => it.isGrave()) > 0,
|
||||
isCritique: actor.countBlessures(it => it.isCritique()) > 0
|
||||
}
|
||||
await ChatMessage.create({
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-acteur.hbs`, formData),
|
||||
alias: actor.name
|
||||
});
|
||||
alias: token.name ?? actor.name
|
||||
})
|
||||
await ChatMessage.create({
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-sante.hbs`, formData),
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name),
|
||||
alias: actor.name
|
||||
});
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
alias: token.name ?? actor.name
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@ import { RdDUtility } from "./rdd-utility.js";
|
||||
import { FenetreRechercheTirage } from "./tirage/fenetre-recherche-tirage.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { DialogFatigueVoyage } from "./voyage/dialog-fatigue-voyage.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
|
||||
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
|
||||
|
||||
@@ -81,7 +82,7 @@ export class RdDCommands {
|
||||
|
||||
this.registerCommand({ path: ["/sommeil"], func: (content, msg, params) => this.sommeil(msg, params), descr: "Prépare le passage de journée pour chateau dormant" });
|
||||
this.registerCommand({ path: ["/meteo"], func: (content, msg, params) => this.getMeteo(msg, params), descr: "Propose une météo marine" });
|
||||
this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.getName(msg, params), descr: "Génère un nom aléatoire" });
|
||||
this.registerCommand({ path: ["/nom"], func: (content, msg, params) => RdDNameGen.proposeName(msg, params), descr: "Génère un nom aléatoire" });
|
||||
|
||||
this.registerCommand({
|
||||
path: ["/tmr"], func: (content, msg, params) => this.findTMR(msg, params),
|
||||
@@ -206,26 +207,20 @@ export class RdDCommands {
|
||||
/* Manage chat commands */
|
||||
processChatCommand(commandLine, content = '', msg = {}) {
|
||||
// Setup new message's visibility
|
||||
let rollMode = game.settings.get("core", "rollMode");
|
||||
if (["gmroll", "blindroll"].includes(rollMode)) {
|
||||
msg["whisper"] = ChatMessage.getWhisperRecipients("GM");
|
||||
}
|
||||
if (rollMode === "blindroll") {
|
||||
msg["blind"] = true;
|
||||
}
|
||||
msg["type"] = 0;
|
||||
ChatUtility.applyRollMode(msg)
|
||||
msg.type = 0;
|
||||
|
||||
if (!this.commandsTable) {
|
||||
this._registerCommands();
|
||||
this._registerCommands()
|
||||
}
|
||||
|
||||
let command = commandLine[0].toLowerCase();
|
||||
if (this._isCommandHandled(command)) {
|
||||
let params = commandLine.slice(1);
|
||||
this._processCommand(this.commandsTable, command, params, content, msg);
|
||||
return true;
|
||||
this._processCommand(this.commandsTable, command, params, content, msg)
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
_isCommandHandled(command) {
|
||||
@@ -463,14 +458,13 @@ export class RdDCommands {
|
||||
|
||||
let motif = params.slice(1, params.length - 2);
|
||||
let name = params[params.length - 1];
|
||||
const personnages = game.actors.filter(actor => actor.isPersonnageJoueur());
|
||||
if (name == undefined) {
|
||||
for (let actor of game.actors) {
|
||||
// TODO: ne plus stresser les entités de cauchemar!
|
||||
for (let actor of personnages) {
|
||||
await actor.distribuerStress('stress', stress, motif);
|
||||
}
|
||||
} else {
|
||||
//console.log(stressValue, nomJoueur);
|
||||
let actor = Misc.findActor(name, game.actors.filter(it => it.hasPlayerOwner)) ?? Misc.findPlayer(name)?.character
|
||||
let actor = Misc.findActor(name, personnages) ?? Misc.findPlayer(name)?.character
|
||||
if (actor) {
|
||||
await actor.distribuerStress('stress', stress, motif);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,28 @@
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
|
||||
export class RdDConfirm {
|
||||
/* -------------------------------------------- */
|
||||
static confirmer(options, autresActions) {
|
||||
options.bypass = options.bypass || !(options.settingConfirmer == undefined || ReglesOptionnelles.isUsing(options.settingConfirmer));
|
||||
if (options.bypass) {
|
||||
options.onAction();
|
||||
if (options.settingConfirmer && !ReglesOptionnelles.isSet(options.settingConfirmer)) {
|
||||
return options.onAction()
|
||||
}
|
||||
else {
|
||||
let buttons = {
|
||||
"action": RdDConfirm._createButtonAction(options),
|
||||
"cancel": RdDConfirm._createButtonCancel()
|
||||
};
|
||||
if (options.settingConfirmer) {
|
||||
buttons = mergeObject(RdDConfirm._createButtonActionSave(options), buttons);
|
||||
}
|
||||
if (autresActions) {
|
||||
buttons = mergeObject(autresActions, buttons);
|
||||
}
|
||||
const dialogDetails = {
|
||||
title: options.title,
|
||||
content: options.content,
|
||||
default: "cancel",
|
||||
buttons: buttons
|
||||
};
|
||||
new Dialog(dialogDetails, { width: 150 * Object.keys(buttons).length }).render(true);
|
||||
let buttons = {
|
||||
"action": RdDConfirm._createButtonAction(options),
|
||||
"cancel": RdDConfirm._createButtonCancel()
|
||||
};
|
||||
if (options.settingConfirmer) {
|
||||
buttons = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons);
|
||||
}
|
||||
if (autresActions) {
|
||||
buttons = foundry.utils.mergeObject(autresActions, buttons, { inplace: false });
|
||||
}
|
||||
const dialogDetails = {
|
||||
title: options.title,
|
||||
content: options.content,
|
||||
default: "cancel",
|
||||
buttons: buttons
|
||||
};
|
||||
new Dialog(dialogDetails, { width: 150 * Object.keys(buttons).length }).render(true);
|
||||
}
|
||||
|
||||
static _createButtonCancel() {
|
||||
|
||||
@@ -2,19 +2,14 @@ import { ChatUtility } from "./chat-utility.js";
|
||||
import { HIDE_DICE, SHOW_DICE } from "./constants.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
function img(src) {
|
||||
return `<img src="${src}" class="dice-img" />`
|
||||
}
|
||||
|
||||
function iconHeure(heure) {
|
||||
const imgHeures = [1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12].map(heure => {
|
||||
if (heure < 10) {
|
||||
heure = '0' + heure;
|
||||
}
|
||||
return `systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure}.webp`
|
||||
}
|
||||
const imagesHeures = [1, 2, 3, 4, 5, 6, 7, 9, 9, 10, 11, 12].map(it => iconHeure(it));
|
||||
return `<img src="systems/foundryvtt-reve-de-dragon/icons/heures/hd${heure}.webp" class="dice-img" />`
|
||||
})
|
||||
|
||||
const imgSigneDragon = img(imagesHeures[4]);
|
||||
const imgSigneDragon = imgHeures[4]
|
||||
|
||||
/** De pour les jets de rencontre */
|
||||
export class DeTMR extends Die {
|
||||
@@ -25,7 +20,7 @@ export class DeTMR extends Die {
|
||||
return {
|
||||
type: "dt",
|
||||
font: "HeuresDraconiques",
|
||||
fontScale: 0.7,
|
||||
fontScale: 0.8,
|
||||
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
|
||||
system: system
|
||||
}
|
||||
@@ -36,14 +31,14 @@ export class DeTMR extends Die {
|
||||
super(termData);
|
||||
}
|
||||
|
||||
async evaluate() {
|
||||
super.evaluate();
|
||||
this.explode("x=8");
|
||||
async evaluate(options) {
|
||||
await super.evaluate(options)
|
||||
await this.reroll('r=8', { recursive: true })
|
||||
return this;
|
||||
}
|
||||
|
||||
get total() {
|
||||
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0);
|
||||
return this.values.map(it => Misc.modulo(it, 8)).reduce(Misc.sum(), 0);
|
||||
}
|
||||
|
||||
getResultLabel(diceTerm) {
|
||||
@@ -56,13 +51,14 @@ export class DeTMR extends Die {
|
||||
|
||||
/** DeDraconique pour le D8 sans limite avec 8=>0 */
|
||||
export class DeDraconique extends Die {
|
||||
/** @override */
|
||||
static DENOMINATION = "r";
|
||||
|
||||
static diceSoNiceData(system) {
|
||||
return {
|
||||
type: "dr",
|
||||
font: "HeuresDraconiques",
|
||||
fontScale: 0.7,
|
||||
fontScale: 0.8,
|
||||
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
|
||||
system: system
|
||||
}
|
||||
@@ -73,9 +69,9 @@ export class DeDraconique extends Die {
|
||||
super(termData);
|
||||
}
|
||||
|
||||
async evaluate() {
|
||||
super.evaluate();
|
||||
this.explode("x=7");
|
||||
async evaluate(options) {
|
||||
await super.evaluate(options);
|
||||
await this.explode("x=7");
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -85,7 +81,7 @@ export class DeDraconique extends Die {
|
||||
|
||||
getResultLabel(diceTerm) {
|
||||
switch (diceTerm.result) {
|
||||
case 7: return imgSigneDragon;
|
||||
case 7: return imgSigneDragon
|
||||
case 8: return '0';
|
||||
}
|
||||
return diceTerm.result.toString();
|
||||
@@ -102,6 +98,7 @@ export class DeHeure extends Die {
|
||||
return {
|
||||
type: "dh",
|
||||
font: "HeuresDraconiques",
|
||||
fontScale: 1.2,
|
||||
labels: ['v', 'i', 'f', 'o', 'd', 'e', 'l', 's', 'p', 'a', 'r', 'c'],
|
||||
system: system
|
||||
}
|
||||
@@ -113,15 +110,15 @@ export class DeHeure extends Die {
|
||||
}
|
||||
|
||||
getResultLabel(diceTerm) {
|
||||
return img(imagesHeures[diceTerm.result - 1]);
|
||||
return imgHeures[diceTerm.result - 1]
|
||||
}
|
||||
}
|
||||
|
||||
export class RdDDice {
|
||||
static init() {
|
||||
CONFIG.Dice.terms[DeTMR.DENOMINATION] = DeTMR;
|
||||
CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique;
|
||||
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure;
|
||||
CONFIG.Dice.terms[DeTMR.DENOMINATION] = DeTMR
|
||||
CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique
|
||||
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure
|
||||
}
|
||||
|
||||
static onReady() {
|
||||
@@ -132,13 +129,25 @@ export class RdDDice {
|
||||
}
|
||||
}
|
||||
|
||||
static diceSoNiceReady(dice3d) {
|
||||
dice3d.DiceFactory.systems.keys().forEach(system => {
|
||||
dice3d.addDicePreset(DeTMR.diceSoNiceData(system));
|
||||
dice3d.addDicePreset(DeDraconique.diceSoNiceData(system));
|
||||
dice3d.addDicePreset(DeHeure.diceSoNiceData(system));
|
||||
})
|
||||
}
|
||||
|
||||
static async rollHeure(options = { showDice: HIDE_DICE }) {
|
||||
return await RdDDice.rollTotal("1dh", options) - 1
|
||||
}
|
||||
|
||||
static async rollTotal(formula, options = { showDice: HIDE_DICE }) {
|
||||
return (await RdDDice.roll(formula, options)).total;
|
||||
}
|
||||
|
||||
static async roll(formula, options = { showDice: SHOW_DICE, rollMode: undefined }) {
|
||||
const roll = new Roll(RdDDice._formulaOrFake(formula, options));
|
||||
await roll.evaluate({ async: true });
|
||||
await roll.evaluate();
|
||||
await this.showDiceSoNice(roll, options);
|
||||
return roll;
|
||||
}
|
||||
@@ -151,21 +160,13 @@ export class RdDDice {
|
||||
return array[roll - 1];
|
||||
}
|
||||
|
||||
static diceSoNiceReady(dice3d) {
|
||||
for (const system of Object.keys(dice3d.DiceFactory.systems)) {
|
||||
dice3d.addDicePreset(DeTMR.diceSoNiceData(system));
|
||||
dice3d.addDicePreset(DeDraconique.diceSoNiceData(system));
|
||||
dice3d.addDicePreset(DeHeure.diceSoNiceData(system));
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async showDiceSoNice(roll, options) {
|
||||
if (options.showDice == HIDE_DICE || !game.modules.get("dice-so-nice")?.active || !game.dice3d) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { whisper, blind } = RdDDice._getWhisperBlind(options);
|
||||
let { whisper, blind } = ChatUtility.applyRollMode({}, options?.rollMode);
|
||||
if (options.forceDiceResult?.total) {
|
||||
let terms = await RdDDice._getForcedTerms(options);
|
||||
if (terms) {
|
||||
@@ -216,27 +217,7 @@ export class RdDDice {
|
||||
|
||||
static async fakeD10(faces) {
|
||||
let roll = new Roll(`1d${faces}`);
|
||||
await roll.evaluate({ async: true });
|
||||
await roll.evaluate();
|
||||
return roll.total;
|
||||
}
|
||||
|
||||
static _getWhisperBlind(options) {
|
||||
let whisper = undefined;
|
||||
let blind = false;
|
||||
let rollMode = options.rollMode ?? game.settings.get("core", "rollMode");
|
||||
switch (rollMode) {
|
||||
case "blindroll": //GM only
|
||||
blind = true;
|
||||
case "gmroll": //GM + rolling player
|
||||
whisper = ChatUtility.getUsers(user => user.isGM);
|
||||
break;
|
||||
case "roll": //everybody
|
||||
whisper = ChatUtility.getUsers(user => user.active);
|
||||
break;
|
||||
case "selfroll":
|
||||
whisper = [game.user.id];
|
||||
break;
|
||||
}
|
||||
return { whisper, blind };
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -92,23 +92,23 @@ export class RdDEmpoignade {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static isEmpoignadeEnCours(actor) {
|
||||
return actor.itemTypes[TYPES.empoignade].find(it => it.system.pointsemp > 0)
|
||||
return actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.pointsemp > 0)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getEmpoignadeById(actor, id) {
|
||||
let emp = actor.itemTypes[TYPES.empoignade].find(it => it.system.empoignadeid == id)
|
||||
return emp && duplicate(emp) || undefined;
|
||||
let emp = actor.itemTypes[ITEM_TYPES.empoignade].find(it => it.system.empoignadeid == id)
|
||||
return emp && foundry.utils.duplicate(emp) || undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getEmpoignade(attacker, defender) {
|
||||
let emp = attacker.itemTypes[TYPES.empoignade].find(it =>
|
||||
let emp = attacker.itemTypes[ITEM_TYPES.empoignade].find(it =>
|
||||
(it.system.empoigneurid == attacker.id && it.system.empoigneid == defender.id) ||
|
||||
(it.system.empoigneurid == defender.id && it.system.empoigneid == attacker.id)
|
||||
)
|
||||
if (emp) {
|
||||
return duplicate(emp);
|
||||
return foundry.utils.duplicate(emp);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -158,9 +158,12 @@ export class RdDEmpoignade {
|
||||
empoignade = empoignade ?? (await RdDEmpoignade.createEmpoignade(attacker, defender))
|
||||
//console.log("W.", empoignade, defender.hasArmeeMeleeEquipee())
|
||||
if ((isNouvelle || empoignade.system.pointsemp == 0) && defender.hasArmeeMeleeEquipee()) {
|
||||
ChatUtility.createChatWithRollMode(attacker.name, {
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
|
||||
})
|
||||
ChatUtility.createChatWithRollMode(
|
||||
{
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-valider.html`, { attacker: attacker, defender: defender })
|
||||
},
|
||||
attacker
|
||||
)
|
||||
} else {
|
||||
await this.onAttaqueEmpoignadeValidee(attacker, defender)
|
||||
}
|
||||
@@ -213,7 +216,7 @@ export class RdDEmpoignade {
|
||||
competence: attacker.getCompetenceCorpsACorps()
|
||||
}
|
||||
const msg = await ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(attacker.name),
|
||||
whisper: ChatUtility.getOwners(attacker),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-empoignade-immobilise.html`, rollData)
|
||||
})
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
@@ -248,7 +251,7 @@ export class RdDEmpoignade {
|
||||
if (rollData.rolled.isPart) {
|
||||
rollData.particuliere = "finesse";
|
||||
}
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html');
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, defender, 'chat-empoignade-resultat.html');
|
||||
RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
|
||||
}
|
||||
|
||||
@@ -267,7 +270,7 @@ export class RdDEmpoignade {
|
||||
return
|
||||
}
|
||||
|
||||
empoignade = duplicate(empoignade)
|
||||
empoignade = foundry.utils.duplicate(empoignade)
|
||||
let defenderRoll = {
|
||||
mode, attacker, defender, empoignade, attackerRoll,
|
||||
diffLibre: attackerRoll.diffLibre,
|
||||
@@ -300,7 +303,7 @@ export class RdDEmpoignade {
|
||||
/* -------------------------------------------- */
|
||||
static async $onRollContrerLiberer(rollData) {
|
||||
let empoignade = rollData.empoignade
|
||||
|
||||
|
||||
if (rollData.mode == "contrer-empoigner" && !rollData.rolled.isSuccess) {
|
||||
empoignade.system.pointsemp++
|
||||
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
|
||||
@@ -309,7 +312,7 @@ export class RdDEmpoignade {
|
||||
empoignade.system.pointsemp--
|
||||
RdDEmpoignade.$updateEtatEmpoignade(empoignade)
|
||||
}
|
||||
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-empoignade-resultat.html')
|
||||
if (empoignade.system.pointsemp >= 2) {
|
||||
let msg = await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-empoignade-entrainer.html');
|
||||
@@ -427,7 +430,7 @@ export class RdDEmpoignade {
|
||||
name: "Empoignade en cours de " + attacker.name + ' sur ' + defender.name,
|
||||
type: 'empoignade',
|
||||
img: "systems/foundryvtt-reve-de-dragon/icons/entites/possession2.webp",
|
||||
system: { description: "", empoignadeid: randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
|
||||
system: { description: "", empoignadeid: foundry.utils.randomID(16), compteempoigne: 0, empoigneurid: attacker.id, empoigneid: defender.id, ptsemp: 0, empoigneurname: attacker.name, empoignename: defender.name }
|
||||
},
|
||||
{
|
||||
temporary: true
|
||||
|
||||
@@ -6,7 +6,7 @@ import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
export class RdDHerbes extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async initializeHerbes() {
|
||||
static async onReady() {
|
||||
this.herbesSoins = await RdDHerbes.listCategorieHerbes('Soin');
|
||||
this.herbesRepos = await RdDHerbes.listCategorieHerbes('Repos');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RdDItemArme } from "./item-arme.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
|
||||
export class RdDHotbar {
|
||||
|
||||
@@ -35,7 +35,7 @@ export class RdDHotbar {
|
||||
|
||||
static async addToHotbar(item, slot) {
|
||||
switch (item?.type ?? '') {
|
||||
case TYPES.arme:
|
||||
case ITEM_TYPES.arme:
|
||||
{
|
||||
// Les armes peuvent avoir plusieurs usages
|
||||
if (item.system.competence != '') {
|
||||
@@ -54,12 +54,12 @@ export class RdDHotbar {
|
||||
}
|
||||
}
|
||||
return
|
||||
case TYPES.competencecreature:
|
||||
case ITEM_TYPES.competencecreature:
|
||||
const categorie = RdDItemCompetenceCreature.getCategorieAttaque(item) ?? 'competence';
|
||||
await this.createItemMacro(item, slot, categorie)
|
||||
return
|
||||
default:
|
||||
case TYPES.competence:
|
||||
case ITEM_TYPES.competence:
|
||||
await this.createItemMacro(item, slot++, 'competence')
|
||||
if (item.isCorpsACorps()) {
|
||||
await this.createItemMacro(item, slot++, 'pugilat')
|
||||
@@ -79,8 +79,7 @@ export class RdDHotbar {
|
||||
* Actor - open actor sheet
|
||||
* Journal - open journal sheet
|
||||
*/
|
||||
static initDropbar() {
|
||||
|
||||
static initHooks() {
|
||||
Hooks.on('hotbarDrop', (bar, documentData, slot) => {
|
||||
|
||||
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
|
||||
@@ -88,9 +87,9 @@ export class RdDHotbar {
|
||||
const item = fromUuidSync(documentData.uuid) ?? this.actor.items.get(documentData.uuid)
|
||||
console.log('DROP', documentData, item)
|
||||
switch (item?.type) {
|
||||
case TYPES.arme:
|
||||
case TYPES.competence:
|
||||
case TYPES.competencecreature:
|
||||
case ITEM_TYPES.arme:
|
||||
case ITEM_TYPES.competence:
|
||||
case ITEM_TYPES.competencecreature:
|
||||
this.addToHotbar(item, slot)
|
||||
return false
|
||||
}
|
||||
@@ -116,9 +115,9 @@ export class RdDHotbar {
|
||||
|
||||
// Trigger the item roll
|
||||
switch (item.type) {
|
||||
case TYPES.arme:
|
||||
case ITEM_TYPES.arme:
|
||||
return actor.rollArme(item, categorieArme);
|
||||
case TYPES.competence:
|
||||
case ITEM_TYPES.competence:
|
||||
if (item.isCorpsACorps()) {
|
||||
switch (categorieArme) {
|
||||
case 'pugilat':
|
||||
@@ -128,7 +127,7 @@ export class RdDHotbar {
|
||||
}
|
||||
}
|
||||
return actor.rollCompetence(item);
|
||||
case TYPES.competencecreature:
|
||||
case ITEM_TYPES.competencecreature:
|
||||
return item.system.iscombat && !item.system.isparade
|
||||
? actor.rollArme(item, categorieArme)
|
||||
: actor.rollCompetence(item);
|
||||
|
||||
@@ -1,69 +1,74 @@
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
|
||||
import { Migrations } from './migrations.js';
|
||||
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG } from "./constants.js"
|
||||
import { Migrations } from './migrations.js'
|
||||
|
||||
import { RdDUtility } from "./rdd-utility.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { TMRRencontres } from "./tmr-rencontres.js";
|
||||
import { RdDCalendrier } from "./time/rdd-calendrier.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { DialogChronologie } from "./dialog-chronologie.js";
|
||||
import { RdDUtility } from "./rdd-utility.js"
|
||||
import { TMRUtility } from "./tmr-utility.js"
|
||||
import { TMRRencontres } from "./tmr-rencontres.js"
|
||||
import { RdDCalendrier } from "./time/rdd-calendrier.js"
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js"
|
||||
import { DialogChronologie } from "./dialog-chronologie.js"
|
||||
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDTokenHud } from "./rdd-token-hud.js";
|
||||
import { RdDCommands } from "./rdd-commands.js";
|
||||
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { StatusEffects } from "./settings/status-effects.js";
|
||||
import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { RdDResolutionTable } from "./rdd-resolution-table.js"
|
||||
import { RdDTokenHud } from "./rdd-token-hud.js"
|
||||
import { RdDCommands } from "./rdd-commands.js"
|
||||
import { RdDCombatManager, RdDCombat } from "./rdd-combat.js"
|
||||
import { ChatUtility } from "./chat-utility.js"
|
||||
import { StatusEffects } from "./settings/status-effects.js"
|
||||
import { RdDCompendiumOrganiser } from "./rdd-compendium-organiser.js"
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js"
|
||||
import { RdDHotbar } from "./rdd-hotbar-drop.js"
|
||||
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
|
||||
import { RdDHerbes } from "./rdd-herbes.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { RdDPossession } from "./rdd-possession.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { EffetsDraconiques } from "./tmr/effets-draconiques.js"
|
||||
import { RdDHerbes } from "./rdd-herbes.js"
|
||||
import { RdDDice } from "./rdd-dice.js"
|
||||
import { RdDPossession } from "./rdd-possession.js"
|
||||
import { Misc } from "./misc.js"
|
||||
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js";
|
||||
import { Environnement } from "./environnement.js";
|
||||
import { SystemCompendiums } from "./settings/system-compendiums.js"
|
||||
import { Environnement } from "./environnement.js"
|
||||
|
||||
import { RdDActor } from "./actor.js";
|
||||
import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { RdDCommerce } from "./actor/commerce.js";
|
||||
import { RdDEntite } from "./actor/entite.js";
|
||||
import { RdDVehicule } from "./actor/vehicule.js";
|
||||
import { RdDActorSheet } from "./actor-sheet.js";
|
||||
import { RdDCommerceSheet } from "./actor/commerce-sheet.js";
|
||||
import { RdDCreatureSheet } from "./actor/creature-sheet.js";
|
||||
import { RdDActorEntiteSheet } from "./actor/entite-sheet.js";
|
||||
import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js";
|
||||
import { RdDActor } from "./actor.js"
|
||||
import { RdDBaseActor } from "./actor/base-actor.js"
|
||||
import { RdDCommerce } from "./actor/commerce.js"
|
||||
import { RdDEntite } from "./actor/entite.js"
|
||||
import { RdDVehicule } from "./actor/vehicule.js"
|
||||
import { RdDActorSheet } from "./actor-sheet.js"
|
||||
import { RdDCommerceSheet } from "./actor/commerce-sheet.js"
|
||||
import { RdDCreatureSheet } from "./actor/creature-sheet.js"
|
||||
import { RdDActorEntiteSheet } from "./actor/entite-sheet.js"
|
||||
import { RdDActorVehiculeSheet } from "./actor/vehicule-sheet.js"
|
||||
|
||||
import { RdDItem } from "./item.js";
|
||||
import { RdDItemBlessure } from "./item/blessure.js";
|
||||
import { RdDItemService } from "./item/service.js";
|
||||
import { RdDItemMaladie } from "./item/maladie.js";
|
||||
import { RdDItemPoison } from "./item/poison.js";
|
||||
import { RdDItemSigneDraconique } from "./item/signedraconique.js";
|
||||
import { RdDItemQueue } from "./item/queue.js";
|
||||
import { RdDItemOmbre } from "./item/ombre.js";
|
||||
import { RdDItemSouffle } from "./item/souffle.js";
|
||||
import { RdDRencontre } from "./item/rencontre.js";
|
||||
import { RdDItem } from "./item.js"
|
||||
import { RdDItemBlessure } from "./item/blessure.js"
|
||||
import { RdDItemService } from "./item/service.js"
|
||||
import { RdDItemMaladie } from "./item/maladie.js"
|
||||
import { RdDItemPoison } from "./item/poison.js"
|
||||
import { RdDItemSigneDraconique } from "./item/signedraconique.js"
|
||||
import { RdDItemQueue } from "./item/queue.js"
|
||||
import { RdDItemOmbre } from "./item/ombre.js"
|
||||
import { RdDItemSouffle } from "./item/souffle.js"
|
||||
import { RdDRencontre } from "./item/rencontre.js"
|
||||
|
||||
import { RdDItemSheet } from "./item-sheet.js";
|
||||
import { RdDBlessureItemSheet } from "./item/sheet-blessure.js";
|
||||
import { RdDServiceItemSheet } from "./item/sheet-service.js";
|
||||
import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js";
|
||||
import { RdDHerbeItemSheet } from "./item/sheet-herbe.js";
|
||||
import { RdDPlanteItemSheet } from "./item/sheet-plante.js";
|
||||
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js";
|
||||
import { RdDFauneItemSheet } from "./item/sheet-faune.js";
|
||||
import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js";
|
||||
import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js";
|
||||
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js";
|
||||
import { AppAstrologie } from "./sommeil/app-astrologie.js";
|
||||
import { RdDItemArmure } from "./item/armure.js";
|
||||
import { AutoAdjustDarkness as AutoAdjustDarkness } from "./time/auto-adjust-darkness.js";
|
||||
import { RdDCreature } from "./actor/creature.js";
|
||||
import { RdDTMRDialog } from "./rdd-tmr-dialog.js";
|
||||
import { RdDItemSheet } from "./item-sheet.js"
|
||||
import { RdDBlessureItemSheet } from "./item/sheet-blessure.js"
|
||||
import { RdDServiceItemSheet } from "./item/sheet-service.js"
|
||||
import { RdDRencontreItemSheet } from "./item/sheet-rencontre.js"
|
||||
import { RdDHerbeItemSheet } from "./item/sheet-herbe.js"
|
||||
import { RdDPlanteItemSheet } from "./item/sheet-plante.js"
|
||||
import { RdDIngredientItemSheet } from "./item/sheet-ingredient.js"
|
||||
import { RdDFauneItemSheet } from "./item/sheet-faune.js"
|
||||
import { RdDConteneurItemSheet } from "./item/sheet-conteneur.js"
|
||||
import { RdDSigneDraconiqueItemSheet } from "./item/sheet-signedraconique.js"
|
||||
import { RdDItemInventaireSheet } from "./item/sheet-base-inventaire.js"
|
||||
import { AppAstrologie } from "./sommeil/app-astrologie.js"
|
||||
import { RdDItemArmure } from "./item/armure.js"
|
||||
import { AutoAdjustDarkness } from "./time/auto-adjust-darkness.js"
|
||||
import { RdDCreature } from "./actor/creature.js"
|
||||
import { RdDTMRDialog } from "./rdd-tmr-dialog.js"
|
||||
import { OptionsAvancees } from "./settings/options-avancees.js"
|
||||
import { ExportScriptarium } from "./actor/export-scriptarium/export-scriptarium.js"
|
||||
import { AppPersonnageAleatoire } from "./actor/random/app-personnage-aleatoire.js"
|
||||
import { RdDActorExportSheet } from "./actor/export-scriptarium/actor-encart-sheet.js"
|
||||
import { RdDStatBlockParser } from "./apps/rdd-import-stats.js"
|
||||
|
||||
/**
|
||||
* RdD system
|
||||
@@ -76,12 +81,14 @@ export class SystemReveDeDragon {
|
||||
const system = new SystemReveDeDragon()
|
||||
Hooks.once('init', async () => await system.onInit())
|
||||
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d))
|
||||
Hooks.once('ready', () => system.onReady())
|
||||
Hooks.once('ready', async () => await system.onReady())
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.RdDUtility = RdDUtility;
|
||||
this.RdDHotbar = RdDHotbar;
|
||||
this.config = RDD_CONFIG
|
||||
this.RdDUtility = RdDUtility
|
||||
this.RdDHotbar = RdDHotbar
|
||||
this.RdDStatBlockParser = RdDStatBlockParser
|
||||
this.itemClasses = {
|
||||
armure: RdDItemArmure,
|
||||
blessure: RdDItemBlessure,
|
||||
@@ -107,42 +114,51 @@ export class SystemReveDeDragon {
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
async onInit() {
|
||||
game.system.rdd = this;
|
||||
this.AppAstrologie = AppAstrologie;
|
||||
game.system.rdd = this
|
||||
this.AppAstrologie = AppAstrologie
|
||||
|
||||
|
||||
console.log(`Initializing Reve de Dragon System`);
|
||||
console.log(`Initializing Reve de Dragon System Settings`)
|
||||
|
||||
// preload handlebars templates
|
||||
RdDUtility.preloadHandlebarsTemplates();
|
||||
RdDUtility.preloadHandlebarsTemplates()
|
||||
AppPersonnageAleatoire.preloadHandlebars()
|
||||
|
||||
/* -------------------------------------------- */
|
||||
this.initSystemSettings();
|
||||
ReglesOptionnelles.initSettings()
|
||||
OptionsAvancees.initSettings()
|
||||
AutoAdjustDarkness.initSettings()
|
||||
RdDTimestamp.initSettings()
|
||||
RdDCalendrier.initSettings()
|
||||
SystemCompendiums.initSettings()
|
||||
DialogChronologie.initSettings()
|
||||
RdDTMRDialog.initSettings()
|
||||
Environnement.initSettings()
|
||||
|
||||
this.initSettings()
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Set an initiative formula for the system
|
||||
CONFIG.Combat.initiative = {
|
||||
formula: "1+(1d6/10)",
|
||||
decimals: 2
|
||||
};
|
||||
CONFIG.Combat.initiative = { formula: "1+(1d6/10)", decimals: 2 }
|
||||
|
||||
/* -------------------------------------------- */
|
||||
console.log(`Initializing Reve de Dragon Socket handlers`)
|
||||
game.socket.on(SYSTEM_SOCKET_ID, async (sockmsg) => {
|
||||
console.log(">>>>> MSG RECV", sockmsg);
|
||||
console.log(">>>>> MSG RECV", sockmsg)
|
||||
try {
|
||||
RdDUtility.onSocketMessage(sockmsg);
|
||||
RdDCombat.onSocketMessage(sockmsg);
|
||||
ChatUtility.onSocketMessage(sockmsg);
|
||||
RdDBaseActor.onSocketMessage(sockmsg);
|
||||
RdDUtility.onSocketMessage(sockmsg)
|
||||
RdDCombat.onSocketMessage(sockmsg)
|
||||
ChatUtility.onSocketMessage(sockmsg)
|
||||
RdDBaseActor.onSocketMessage(sockmsg)
|
||||
} catch (e) {
|
||||
console.error('game.socket.on(SYSTEM_SOCKET_ID) Exception: ', sockmsg, ' => ', e)
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Define custom Entity classes
|
||||
CONFIG.Actor.documentClass = RdDBaseActor;
|
||||
CONFIG.Item.documentClass = RdDItem;
|
||||
console.log(`Initializing Reve de Dragon Documents`)
|
||||
CONFIG.Actor.documentClass = RdDBaseActor
|
||||
CONFIG.Item.documentClass = RdDItem
|
||||
CONFIG.RDD = {
|
||||
resolutionTable: RdDResolutionTable.resolutionTable,
|
||||
carac_array: RdDUtility.getCaracArray(),
|
||||
@@ -152,30 +168,31 @@ export class SystemReveDeDragon {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register sheet application classes
|
||||
Actors.unregisterSheet("core", ActorSheet);
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDCreatureSheet, { types: ["creature"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
|
||||
Items.unregisterSheet("core", ItemSheet);
|
||||
Actors.unregisterSheet("core", ActorSheet)
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDCommerceSheet, { types: ["commerce"], makeDefault: true })
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorSheet, { types: ["personnage"], makeDefault: true })
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDCreatureSheet, { types: ["creature"], makeDefault: true })
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true })
|
||||
Actors.registerSheet(SYSTEM_RDD, RdDActorEntiteSheet, { types: ["entite"], makeDefault: true })
|
||||
Items.unregisterSheet("core", ItemSheet)
|
||||
await RdDActorExportSheet.init()
|
||||
|
||||
RdDItemSheet.register(RdDSigneDraconiqueItemSheet);
|
||||
RdDItemSheet.register(RdDRencontreItemSheet);
|
||||
RdDItemSheet.register(RdDConteneurItemSheet);
|
||||
RdDItemSheet.register(RdDHerbeItemSheet);
|
||||
RdDItemSheet.register(RdDFauneItemSheet);
|
||||
RdDItemSheet.register(RdDPlanteItemSheet);
|
||||
RdDItemSheet.register(RdDIngredientItemSheet);
|
||||
RdDItemSheet.register(RdDServiceItemSheet);
|
||||
RdDItemSheet.register(RdDBlessureItemSheet);
|
||||
RdDItemSheet.register(RdDSigneDraconiqueItemSheet)
|
||||
RdDItemSheet.register(RdDRencontreItemSheet)
|
||||
RdDItemSheet.register(RdDConteneurItemSheet)
|
||||
RdDItemSheet.register(RdDHerbeItemSheet)
|
||||
RdDItemSheet.register(RdDFauneItemSheet)
|
||||
RdDItemSheet.register(RdDPlanteItemSheet)
|
||||
RdDItemSheet.register(RdDIngredientItemSheet)
|
||||
RdDItemSheet.register(RdDServiceItemSheet)
|
||||
RdDItemSheet.register(RdDBlessureItemSheet)
|
||||
|
||||
Items.registerSheet(SYSTEM_RDD, RdDItemInventaireSheet, {
|
||||
types: [
|
||||
"objet", "arme", "armure", "livre", "potion", "munition",
|
||||
"monnaie", "nourritureboisson", "gemme",
|
||||
], makeDefault: true
|
||||
});
|
||||
})
|
||||
Items.registerSheet(SYSTEM_RDD, RdDItemSheet, {
|
||||
types: [
|
||||
"competence", "competencecreature",
|
||||
@@ -184,34 +201,29 @@ export class SystemReveDeDragon {
|
||||
"nombreastral", "tache", "maladie", "poison", "possession",
|
||||
"tarot", "extraitpoetique", "empoignade"
|
||||
], makeDefault: true
|
||||
});
|
||||
CONFIG.Combat.documentClass = RdDCombatManager;
|
||||
})
|
||||
|
||||
// préparation des différents modules
|
||||
AutoAdjustDarkness.init();
|
||||
RdDTimestamp.init();
|
||||
RdDCalendrier.init();
|
||||
SystemCompendiums.init();
|
||||
DialogChronologie.init();
|
||||
ReglesOptionnelles.init();
|
||||
RdDUtility.init();
|
||||
RdDDice.init();
|
||||
RdDCommands.init();
|
||||
RdDCombatManager.init();
|
||||
RdDTokenHud.init();
|
||||
RdDBaseActor.init();
|
||||
RdDCompendiumOrganiser.init();
|
||||
console.log(`Initializing Reve de Dragon Hooks and handlers`)
|
||||
CONFIG.Combat.documentClass = RdDCombatManager
|
||||
ChatUtility.init()
|
||||
RdDUtility.initHooks()
|
||||
RdDDice.init()
|
||||
RdDCommands.init()
|
||||
RdDCombatManager.init()
|
||||
RdDTokenHud.init()
|
||||
RdDBaseActor.init()
|
||||
RdDCompendiumOrganiser.init()
|
||||
EffetsDraconiques.init()
|
||||
TMRUtility.init();
|
||||
await RdDTMRDialog.init()
|
||||
RdDHotbar.initDropbar();
|
||||
RdDPossession.init();
|
||||
TMRRencontres.init();
|
||||
Environnement.init();
|
||||
|
||||
TMRUtility.init()
|
||||
RdDHotbar.initHooks()
|
||||
RdDPossession.init()
|
||||
TMRRencontres.init()
|
||||
ExportScriptarium.init()
|
||||
}
|
||||
|
||||
initSystemSettings() {
|
||||
initSettings() {
|
||||
// TODO: déplacer vers les modules correspondants
|
||||
game.settings.register(SYSTEM_RDD, "accorder-entite-cauchemar", {
|
||||
name: "Accorder le rêve aux entités",
|
||||
hint: "A quel moment les personnages doivent accorder leur rêve aux entités de cauchemar",
|
||||
@@ -224,7 +236,7 @@ export class SystemReveDeDragon {
|
||||
"avant-encaissement": "Avant l'encaissement",
|
||||
},
|
||||
default: "avant-encaissement"
|
||||
});
|
||||
})
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "supprimer-dialogues-combat-chat", {
|
||||
@@ -234,7 +246,7 @@ export class SystemReveDeDragon {
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
})
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "activer-sons-audio", {
|
||||
@@ -244,7 +256,8 @@ export class SystemReveDeDragon {
|
||||
config: true,
|
||||
default: true,
|
||||
type: Boolean
|
||||
});
|
||||
})
|
||||
|
||||
/* -------------------------------------------- */
|
||||
game.settings.register(SYSTEM_RDD, "appliquer-famine-soif", {
|
||||
name: "Notifier de la famine et la soif pour",
|
||||
@@ -258,7 +271,17 @@ export class SystemReveDeDragon {
|
||||
"famine-soif": "la famine et la soif",
|
||||
},
|
||||
default: "aucun"
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
static async setupAccueil() {
|
||||
let exists = game.scenes.find(j => j.name == "Accueil RdD");
|
||||
if (!exists) {
|
||||
const scenes = await SystemCompendiums.loadCompendium("foundryvtt-reve-de-dragon.scenes-rdd")
|
||||
let newDocuments = scenes.filter(i => i.name == "Accueil RdD");
|
||||
await game.scenes.documentClass.create(newDocuments);
|
||||
game.scenes.find(i => i.name == "Accueil RdD").activate();
|
||||
}
|
||||
}
|
||||
|
||||
async onReady() {
|
||||
@@ -266,71 +289,50 @@ export class SystemReveDeDragon {
|
||||
/* -------------------------------------------- */
|
||||
/* Foundry VTT Initialization */
|
||||
/* -------------------------------------------- */
|
||||
// CSS patch for v9
|
||||
if (game.version) {
|
||||
let sidebar = document.getElementById("sidebar");
|
||||
sidebar.style.width = "min-content";
|
||||
}
|
||||
game.system.rdd.calendrier = new RdDCalendrier();
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
new Migrations().migrate();
|
||||
this.messageDeBienvenue();
|
||||
this.registerUsageCount(SYSTEM_RDD);
|
||||
game.system.rdd.calendrier = new RdDCalendrier()
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
new Migrations().migrate()
|
||||
this.messageDeBienvenue()
|
||||
import("https://www.uberwald.me/fvtt_appcount/count-class-ready.js").then(moduleCounter => {
|
||||
console.log("ClassCounter loaded", moduleCounter)
|
||||
moduleCounter.ClassCounter.registerUsageCount()
|
||||
}).catch(err =>
|
||||
console.log("No stats available, giving up.")
|
||||
)
|
||||
}
|
||||
|
||||
StatusEffects.onReady();
|
||||
RdDHerbes.initializeHerbes();
|
||||
RdDDice.onReady();
|
||||
StatusEffects.onReady()
|
||||
RdDHerbes.onReady()
|
||||
RdDDice.onReady()
|
||||
|
||||
RdDStatBlockParser.parseStatBlock()
|
||||
/* -------------------------------------------- */
|
||||
/* Affiche/Init le calendrier */
|
||||
game.system.rdd.calendrier.display();
|
||||
game.system.rdd.calendrier.display()
|
||||
// Avertissement si joueur sans personnage
|
||||
if (!game.user.isGM && game.user.character == undefined) {
|
||||
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !");
|
||||
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !")
|
||||
ChatMessage.create({
|
||||
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
|
||||
user: game.user.id
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
SystemReveDeDragon.setupAccueil()
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
messageDeBienvenue() {
|
||||
if (game.user.isGM) {
|
||||
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">');
|
||||
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">')
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
|
||||
<br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
|
||||
<br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
|
||||
` });
|
||||
` })
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// Register world usage statistics
|
||||
async registerUsageCount(registerKey) {
|
||||
if (game.user.isGM) {
|
||||
game.settings.register("world", "world-key", {
|
||||
name: "Unique world key",
|
||||
scope: "world",
|
||||
config: false,
|
||||
default: "NONE",
|
||||
type: String
|
||||
});
|
||||
|
||||
let worldKey = game.settings.get("world", "world-key")
|
||||
if (worldKey == undefined || worldKey == "") {
|
||||
worldKey = randomID(32)
|
||||
game.settings.set("world", "world-key", worldKey)
|
||||
}
|
||||
let regURL = `https://www.uberwald.me/fvtt_appcount/count.php?name="${registerKey}"&worldKey="${worldKey}"&version="${game.release.generation}.${game.release.build}"&system="${game.system.id}"&systemversion="${game.system.version}"`
|
||||
$.ajax(regURL)
|
||||
/* -------------------------------------------- */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SystemReveDeDragon.start();
|
||||
|
||||
SystemReveDeDragon.start()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ChatUtility } from "./chat-utility.js"
|
||||
|
||||
const vents = [
|
||||
{ min: 0, max: 0, valeur: 'Calme' },
|
||||
@@ -56,7 +57,7 @@ const temperatures = [
|
||||
export class RdDMeteo {
|
||||
static async getForce() {
|
||||
const roll = new Roll(`1dr`);
|
||||
await roll.evaluate({ async: true });
|
||||
await roll.evaluate();
|
||||
return roll.total;
|
||||
}
|
||||
|
||||
@@ -67,14 +68,14 @@ export class RdDMeteo {
|
||||
static async getTemperature() {
|
||||
const degre = await RdDMeteo.getForce();
|
||||
const rollChaudFroid = new Roll('1d2');
|
||||
await rollChaudFroid.evaluate({ async: true });
|
||||
await rollChaudFroid.evaluate();
|
||||
const chaudFroid = rollChaudFroid.total == 1;
|
||||
return chaudFroid.total ? degre : -degre;
|
||||
}
|
||||
|
||||
static async getDirection(direction) {
|
||||
const roll = new Roll(`1d16`);
|
||||
await roll.evaluate({ async: true });
|
||||
await roll.evaluate();
|
||||
switch (roll.total % 16) {
|
||||
case 0: return 'Nord';
|
||||
case 1: return 'Nord Nord Est';
|
||||
@@ -117,7 +118,7 @@ export class RdDMeteo {
|
||||
|
||||
ChatMessage.create({
|
||||
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-resultat-meteo.html', meteo),
|
||||
whisper: ChatMessage.getWhisperRecipients('GM')
|
||||
whisper: ChatUtility.getGMs()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { RdDBaseActor } from "./actor/base-actor.js";
|
||||
import { ChatUtility } from "./chat-utility.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
|
||||
@@ -11,11 +12,15 @@ const words = ['pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i',
|
||||
/* -------------------------------------------- */
|
||||
export class RdDNameGen {
|
||||
|
||||
static async getName(msg, params) {
|
||||
static async proposeName(msg, params) {
|
||||
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-command-nom.html`, {
|
||||
nom: Misc.upperFirst(await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words))
|
||||
nom: await RdDNameGen.generate()
|
||||
});
|
||||
ChatMessage.create({ content: html, whisper: ChatMessage.getWhisperRecipients("GM") });
|
||||
ChatMessage.create({ content: html, whisper: ChatUtility.getGMs() });
|
||||
}
|
||||
|
||||
static async generate() {
|
||||
return Misc.upperFirst(await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words));
|
||||
}
|
||||
|
||||
static async onCreerActeur(event) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import { RdDResolutionTable } from "./rdd-resolution-table.js";
|
||||
import { RdDRoll } from "./rdd-roll.js";
|
||||
import { RdDItemCompetenceCreature } from "./item-competencecreature.js";
|
||||
import { Targets } from "./targets.js";
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* On part du principe qu'une entité démarre tjs
|
||||
@@ -20,11 +20,11 @@ export class RdDPossession {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static searchPossessionFromEntite(attacker, defender) {
|
||||
let poss = attacker.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
let poss = attacker.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
if (!poss) {
|
||||
poss = defender.items.find(poss => poss.type == TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
poss = defender.items.find(poss => poss.type == ITEM_TYPES.possession && poss.system.victime.actorid == defender.id);
|
||||
}
|
||||
return poss && duplicate(poss) || undefined;
|
||||
return poss && foundry.utils.duplicate(poss) || undefined;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -52,7 +52,7 @@ export class RdDPossession {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async onConjurerPossession(attacker, possession) {
|
||||
possession = duplicate(possession);
|
||||
possession = foundry.utils.duplicate(possession);
|
||||
RdDPossession.$updateEtatPossession(possession)
|
||||
|
||||
const defender = game.actors.get(possession.system.entite.actorid);
|
||||
@@ -80,7 +80,7 @@ export class RdDPossession {
|
||||
ui.notifications.warn("Une erreur s'est produite : Aucune possession trouvée !!")
|
||||
return
|
||||
}
|
||||
possession = duplicate(possession)
|
||||
possession = foundry.utils.duplicate(possession)
|
||||
// Update for draconic roll
|
||||
let rollData = {
|
||||
mode: "defense",
|
||||
@@ -131,7 +131,7 @@ export class RdDPossession {
|
||||
}
|
||||
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
|
||||
RdDPossession.storePossessionAttaque(possession, rollData)
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html');
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html');
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -171,7 +171,7 @@ export class RdDPossession {
|
||||
rollData.possession = possession
|
||||
RdDPossession.$updateEtatPossession(rollData.possession)
|
||||
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html')
|
||||
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html')
|
||||
if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
|
||||
// conjuration
|
||||
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])
|
||||
@@ -230,7 +230,7 @@ export class RdDPossession {
|
||||
system: {
|
||||
description: "", typepossession: attacker.name,
|
||||
possede: false,
|
||||
possessionid: randomID(16),
|
||||
possessionid: foundry.utils.randomID(16),
|
||||
entite: { actorid: attacker.id },
|
||||
victime: { actorid: defender.id },
|
||||
compteur: 0
|
||||
|
||||
@@ -91,13 +91,14 @@ export class RdDResolutionTable {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async displayRollData(rollData, actor = undefined, template = 'chat-resultat-general.html') {
|
||||
return await ChatUtility.createChatWithRollMode(RdDResolutionTable.actorChatName(actor), {
|
||||
content: await RdDResolutionTable.buildRollDataHtml(rollData, template)
|
||||
});
|
||||
return await ChatUtility.createChatWithRollMode(
|
||||
{ content: await RdDResolutionTable.buildRollDataHtml(rollData, template) },
|
||||
actor
|
||||
)
|
||||
}
|
||||
|
||||
static actorChatName(actor) {
|
||||
return actor?.userName ?? game.user.name;
|
||||
return actor ?? game.user.name;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -114,7 +115,7 @@ export class RdDResolutionTable {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async roll(caracValue, finalLevel, rollData = {}) {
|
||||
let chances = duplicate(this.computeChances(caracValue, finalLevel));
|
||||
let chances = foundry.utils.duplicate(this.computeChances(caracValue, finalLevel));
|
||||
this._updateChancesWithBonus(chances, rollData.bonus, finalLevel);
|
||||
this._updateChancesFactor(chances, rollData.diviseurSignificative);
|
||||
chances.showDice = rollData.showDice;
|
||||
@@ -138,14 +139,14 @@ export class RdDResolutionTable {
|
||||
if (carac == 0) {
|
||||
return NaN;
|
||||
}
|
||||
if (rolled >= carac){
|
||||
const upper = Math.ceil(rolled/carac);
|
||||
return 2*upper -10
|
||||
if (rolled >= carac) {
|
||||
const upper = Math.ceil(rolled / carac);
|
||||
return 2 * upper - 10
|
||||
}
|
||||
if (rolled > Math.floor(carac/2)) {
|
||||
if (rolled > Math.floor(carac / 2)) {
|
||||
return -8
|
||||
}
|
||||
if (rolled > Math.floor(carac/4)) {
|
||||
if (rolled > Math.floor(carac / 4)) {
|
||||
return -9
|
||||
}
|
||||
if (rolled > 1) {
|
||||
@@ -158,7 +159,7 @@ export class RdDResolutionTable {
|
||||
static _updateChancesFactor(chances, diviseur) {
|
||||
if (chances.level > -11 && diviseur && diviseur > 1) {
|
||||
let newScore = Math.floor(chances.score / diviseur);
|
||||
mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
foundry.utils.mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,27 +167,27 @@ export class RdDResolutionTable {
|
||||
static _updateChancesWithBonus(chances, bonus, finalLevel) {
|
||||
if (bonus && finalLevel > -11) {
|
||||
let newScore = Number(chances.score) + bonus;
|
||||
mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
foundry.utils.mergeObject(chances, this._computeCell(undefined, newScore), { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static significativeRequise(chances) {
|
||||
chances.roll = Math.floor(chances.score / 2);
|
||||
mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
|
||||
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static succesRequis(chances) {
|
||||
chances.roll = chances.score;
|
||||
mergeObject(chances, reussites.find(x => x.code == 'norm'), { overwrite: true });
|
||||
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'norm'), { overwrite: true });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async rollChances(chances, diviseur, forceDiceResult = -1) {
|
||||
chances.forceDiceResult = forceDiceResult <= 0 || forceDiceResult > 100 ? undefined : { total: forceDiceResult };
|
||||
chances.roll = await RdDDice.rollTotal("1d100", chances);
|
||||
mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
|
||||
foundry.utils.mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
|
||||
return chances;
|
||||
}
|
||||
|
||||
@@ -265,7 +266,7 @@ export class RdDResolutionTable {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static subTable(carac, level, delta = { carac: 2, level: 5}) {
|
||||
static subTable(carac, level, delta = { carac: 2, level: 5 }) {
|
||||
return {
|
||||
carac,
|
||||
level,
|
||||
@@ -287,8 +288,8 @@ export class RdDResolutionTable {
|
||||
carac: carac,
|
||||
difficulte: level,
|
||||
min: minLevel,
|
||||
rows: Misc.intArray(minCarac, maxCarac+1),
|
||||
cols: Misc.intArray(minLevel, maxLevel+1)
|
||||
rows: Misc.intArray(minCarac, maxCarac + 1),
|
||||
cols: Misc.intArray(minLevel, maxLevel + 1)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -72,6 +72,6 @@ export class RdDEncaisser extends Dialog {
|
||||
encaisserSpecial: this.encaisserSpecial,
|
||||
mortalite: mortalite
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export class RdDRollResolutionTable extends Dialog {
|
||||
diffLibre: 0,
|
||||
use: { conditions:true, libre:true }
|
||||
}
|
||||
mergeObject(rollData, defRollData, { overwrite: false });
|
||||
foundry.utils.mergeObject(rollData, defRollData, { overwrite: false });
|
||||
for (let i = 1; i < 21; i++) {
|
||||
const key = `${i}`;
|
||||
rollData.carac[key] = { type: "number", value: i, label: key }
|
||||
|
||||
@@ -65,7 +65,7 @@ export class RdDRoll extends Dialog {
|
||||
defaultRollData.carac["reve-actuel"] = actor.system.reve.reve
|
||||
}
|
||||
|
||||
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
|
||||
foundry.utils.mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
|
||||
if (rollData.forceCarac) {
|
||||
rollData.carac = rollData.forceCarac;
|
||||
}
|
||||
@@ -307,7 +307,7 @@ export class RdDRoll extends Dialog {
|
||||
async updateRollResult(html) {
|
||||
const rollData = this.rollData;
|
||||
|
||||
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor.getBonusDegat())
|
||||
rollData.dmg = rollData.attackerRoll?.dmg ?? RdDBonus.dmg(rollData, this.actor)
|
||||
rollData.caracValue = parseInt(rollData.selectedCarac.value)
|
||||
rollData.dmg.mortalite = rollData.dmg.mortalite ?? 'mortel';
|
||||
rollData.use.appelAuMoral = this.actor.isPersonnage() && RdDCarac.isActionPhysique(rollData.selectedCarac);
|
||||
|
||||
@@ -16,7 +16,7 @@ export class RdDSheetUtility {
|
||||
isObserver: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OBSERVER,
|
||||
isOwner: userRightLevel >= CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER
|
||||
}
|
||||
mergeObject(options, newOptions);
|
||||
foundry.utils.mergeObject(options, newOptions);
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ export class RdDSheetUtility {
|
||||
static async _onSplitItem(item, split, actor) {
|
||||
if (split >= 1 && split < item.system.quantite) {
|
||||
await item.diminuerQuantite(split);
|
||||
const splitItem = duplicate(item);
|
||||
const splitItem = foundry.utils.duplicate(item);
|
||||
// todo: ajouter dans le même conteneur?
|
||||
splitItem.system.quantite = split;
|
||||
await actor.createEmbeddedDocuments('Item', [splitItem])
|
||||
|
||||
@@ -16,7 +16,7 @@ import { RdDDice } from "./rdd-dice.js";
|
||||
import { STATUSES } from "./settings/status-effects.js";
|
||||
import { RdDRencontre } from "./item/rencontre.js";
|
||||
import { RdDTimestamp } from "./time/rdd-timestamp.js";
|
||||
import { TYPES } from "./item.js";
|
||||
import { ITEM_TYPES } from "./item.js";
|
||||
import { Misc } from "./misc.js";
|
||||
|
||||
const TMR_DISPLAY_SIZE = {
|
||||
@@ -34,7 +34,7 @@ const TMR_DISPLAY_SIZE = {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
export class RdDTMRDialog extends Dialog {
|
||||
static async init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, TMR_DISPLAY_SIZE.code, {
|
||||
name: 'Taille des cases des TMR',
|
||||
hint: "Taille en pixel des cases des TMR (réglable directement dans la fenêtre des TMR)",
|
||||
@@ -44,16 +44,15 @@ export class RdDTMRDialog extends Dialog {
|
||||
type: Number,
|
||||
range: TMR_DISPLAY_SIZE.range
|
||||
})
|
||||
await PixiTMR.init()
|
||||
}
|
||||
|
||||
static async create(actor, tmrData) {
|
||||
await PixiTMR.init()
|
||||
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html', tmrData);
|
||||
|
||||
if (tmrData.mode != 'visu' && !game.user.isGM) {
|
||||
ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatMessage.getWhisperRecipients("GM") });
|
||||
ChatMessage.create({ content: actor.name + " est monté dans les TMR en mode : " + tmrData.mode, whisper: ChatUtility.getGMs() });
|
||||
}
|
||||
return new RdDTMRDialog(html, actor, tmrData);
|
||||
return new RdDTMRDialog(html, actor, tmrData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -71,7 +70,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
'z-index': 40
|
||||
}
|
||||
super(dialogConf, dialogOptions);
|
||||
this.tmrdata = duplicate(tmrData);
|
||||
this.tmrdata = foundry.utils.duplicate(tmrData);
|
||||
this.actor = actor;
|
||||
this.actor.tmrApp = this; // reference this app in the actor structure
|
||||
this.viewOnly = tmrData.mode == "visu"
|
||||
@@ -83,7 +82,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.rencontreState = 'aucune';
|
||||
this.subdialog = undefined
|
||||
this.displaySize = undefined
|
||||
if (!this.viewOnly) {
|
||||
if (!this.viewOnly && !game.user.isGM) {
|
||||
this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
|
||||
}
|
||||
this.callbacksOnAnimate = [];
|
||||
@@ -130,7 +129,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop());
|
||||
|
||||
// Roll Sort
|
||||
this.html.find('.lancer-sort').click(event => this.actor.rollUnSort(this._getCoordActor()));
|
||||
this.html.find('.lancer-sort').click(event => this.lancerUnSort());
|
||||
this.html.find('.lire-signe-draconique').click(event => this.actor.rollLireSigneDraconique(this._getCoordActor()));
|
||||
|
||||
this.html.find('img.tmr-move').click(event => this.deplacementTMR(this.html.find(event.currentTarget)?.data('move')));
|
||||
@@ -143,6 +142,13 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.updateValuesDisplay();
|
||||
}
|
||||
|
||||
lancerUnSort() {
|
||||
if (this.subdialog) {
|
||||
return this.forceTMRContinueAction();
|
||||
}
|
||||
return this.actor.rollUnSort(this._getCoordActor());
|
||||
}
|
||||
|
||||
async onDeplacement() {
|
||||
await this.manageRencontre(TMRUtility.getTMR(this._getCoordActor()));
|
||||
}
|
||||
@@ -165,23 +171,25 @@ export class RdDTMRDialog extends Dialog {
|
||||
async forceTMRDisplay() {
|
||||
if (this.rendered) {
|
||||
this.bringToTop()
|
||||
if (this.subdialog?.bringToTop) {
|
||||
this.subdialog.bringToTop();
|
||||
}
|
||||
this.bringSubDialogToTop();
|
||||
}
|
||||
}
|
||||
|
||||
bringSubDialogToTop() {
|
||||
if (this.subdialog?.bringToTop && this.subdialog?.element[0]) {
|
||||
this.subdialog.bringToTop();
|
||||
}
|
||||
}
|
||||
|
||||
async restoreTMRAfterAction() {
|
||||
this.subdialog = undefined
|
||||
await this.maximize();
|
||||
this.bringToTop();
|
||||
await this.maximize()
|
||||
this.bringToTop()
|
||||
}
|
||||
|
||||
forceTMRContinueAction() {
|
||||
ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR');
|
||||
if (this.subdialog?.bringToTop) {
|
||||
this.subdialog.bringToTop();
|
||||
}
|
||||
this.bringSubDialogToTop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -200,11 +208,11 @@ export class RdDTMRDialog extends Dialog {
|
||||
}
|
||||
|
||||
get sortsReserve() {
|
||||
return this.actor.itemTypes[TYPES.sortreserve];
|
||||
return this.actor.itemTypes[ITEM_TYPES.sortreserve];
|
||||
}
|
||||
|
||||
getSortsReserve(coord) {
|
||||
return this.actor.itemTypes[TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale
|
||||
return this.actor.itemTypes[ITEM_TYPES.sortreserve].filter(// Reserve sur une case fleuve ou normale
|
||||
TMRUtility.getTMR(coord).type == 'fleuve'
|
||||
? it => TMRUtility.getTMR(it.system.coord).type == 'fleuve'
|
||||
: it => it.system.coord == coord
|
||||
@@ -213,7 +221,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
loadRencontres() {
|
||||
this.rencontresExistantes = this.actor.getTMRRencontres();
|
||||
this.rencontresExistantes = this.actor.getRencontresTMR();
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -262,7 +270,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
}
|
||||
|
||||
_getTokensSortsReserve() {
|
||||
const sortsReserve = this.actor.itemTypes[TYPES.sortreserve];
|
||||
const sortsReserve = this.actor.itemTypes[ITEM_TYPES.sortreserve];
|
||||
return Misc.concat(sortsReserve.map(sortReserve =>
|
||||
EffetsDraconiques.sortReserve.tokens(this.pixiTMR, sortReserve, () => sortReserve.system.coord)))
|
||||
}
|
||||
@@ -298,11 +306,10 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async updateValuesDisplay() {
|
||||
if (!this.rendered) {
|
||||
if (this.viewOnly || !this.rendered) {
|
||||
return;
|
||||
}
|
||||
const coord = this._getCoordActor();
|
||||
|
||||
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
|
||||
|
||||
let ptsreve = document.getElementById("tmr-pointsreve-value");
|
||||
@@ -384,7 +391,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async refouler() {
|
||||
console.log("-> refouler", this.currentRencontre);
|
||||
await this.actor.ajouterRefoulement(this.currentRencontre.system.refoulement, `${this.currentRencontre.system.genre == 'f' ? 'une' : 'un'} ${this.currentRencontre.name}`);
|
||||
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
|
||||
await this.actor.deleteRencontreTMRAtPosition()
|
||||
this.updateTokens();
|
||||
this.updateValuesDisplay();
|
||||
this.nettoyerRencontre();
|
||||
@@ -394,7 +401,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async ignorerRencontre() {
|
||||
console.log("-> ignorer", this.currentRencontre);
|
||||
this._tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name);
|
||||
await this.actor.deleteTMRRencontreAtPosition(); // Remove the stored rencontre if necessary
|
||||
await this.actor.deleteRencontreTMRAtPosition()
|
||||
this.updateTokens();
|
||||
this.updateValuesDisplay();
|
||||
this.nettoyerRencontre();
|
||||
@@ -409,7 +416,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$marquerCasesTMR(listCoordTMR) {
|
||||
this.currentRencontre.locList = duplicate(listCoordTMR); // And track of allowed location
|
||||
this.currentRencontre.locList = foundry.utils.duplicate(listCoordTMR); // And track of allowed location
|
||||
this.currentRencontre.graphics = listCoordTMR.map(coordTMR => this.pixiTMR.addMarkTMR(coordTMR))
|
||||
}
|
||||
|
||||
@@ -448,7 +455,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async maitriserRencontre() {
|
||||
console.log("-> maitriser", this.currentRencontre);
|
||||
|
||||
await this.actor.deleteTMRRencontreAtPosition();
|
||||
await this.actor.deleteRencontreTMRAtPosition()
|
||||
this.updateTokens();
|
||||
|
||||
let rencontreData = {
|
||||
@@ -489,7 +496,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
rencData.message = this.formatMessageRencontre(rencData, result.message);
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(this.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData)
|
||||
});
|
||||
|
||||
@@ -538,7 +545,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
/* -------------------------------------------- */
|
||||
_rollPresentCite(rencData) {
|
||||
let rolled = RdDResolutionTable.computeChances(rencData.reve, 0);
|
||||
mergeObject(rolled, { caracValue: rencData.reve, finalLevel: 0, roll: rolled.score });
|
||||
foundry.utils.mergeObject(rolled, { caracValue: rencData.reve, finalLevel: 0, roll: rolled.score });
|
||||
RdDResolutionTable.succesRequis(rolled);
|
||||
return rolled;
|
||||
}
|
||||
@@ -564,12 +571,20 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_tellToGM(message) {
|
||||
ChatMessage.create({ content: message, user: game.user.id, whisper: ChatMessage.getWhisperRecipients("GM") });
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getGMs()
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_tellToUserAndGM(message) {
|
||||
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id].concat(ChatMessage.getWhisperRecipients("GM")) });
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getUserAndGMs()
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -681,7 +696,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
if (this.isCaseHumide(tmr)) {
|
||||
let rollData = {
|
||||
actor: this.actor,
|
||||
competence: duplicate(this.actor.getBestDraconic()),
|
||||
competence: foundry.utils.duplicate(this.actor.getBestDraconic()),
|
||||
tmr: tmr,
|
||||
canClose: false,
|
||||
diffLibre: -7,
|
||||
@@ -708,7 +723,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
}
|
||||
rollData.poesie = await Poetique.getExtrait();
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(this.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
|
||||
});
|
||||
if (rollData.rolled.isEchec) {
|
||||
@@ -732,7 +747,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
if (this.isCaseMaitrisee(tmr.coord)) {
|
||||
ChatMessage.create({
|
||||
content: tmr.label + ": cette case humide est déja maitrisée grâce à votre Tête <strong>Quête des Eaux</strong>",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
});
|
||||
return false;
|
||||
}
|
||||
@@ -744,14 +759,14 @@ export class RdDTMRDialog extends Dialog {
|
||||
if (tmr.type == 'pont' && EffetsDraconiques.isPontImpraticable(this.actor)) {
|
||||
ChatMessage.create({
|
||||
content: tmr.label + ": Vous êtes sous le coup d'une Impraticabilité des Ponts : ce pont doit être maîtrisé comme une case humide.",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
});
|
||||
return true;
|
||||
}
|
||||
if (this.isCaseInondee(tmr.coord)) {
|
||||
ChatMessage.create({
|
||||
content: tmr.label + ": cette case est inondée, elle doit être maîtrisée comme une case humide.",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
});
|
||||
return true;
|
||||
}
|
||||
@@ -806,7 +821,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async _conquerir(tmr, options) {
|
||||
let rollData = {
|
||||
actor: this.actor,
|
||||
competence: duplicate(this.actor.getBestDraconic()),
|
||||
competence: foundry.utils.duplicate(this.actor.getBestDraconic()),
|
||||
tmr: tmr,
|
||||
canClose: options.canClose ?? false,
|
||||
diffLibre: options.difficulte ?? -7,
|
||||
@@ -825,7 +840,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
}
|
||||
rollData.poesie = await Poetique.getExtrait();
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(this.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
|
||||
});
|
||||
if (rollData.rolled.isEchec) {
|
||||
@@ -875,17 +890,16 @@ export class RdDTMRDialog extends Dialog {
|
||||
const reserveSecurite = EffetsDraconiques.isReserveEnSecurite(this.actor);
|
||||
const reserveExtensible = this.isReserveExtensible(coord);
|
||||
if (!EffetsDraconiques.isUrgenceDraconique(this.actor) && (reserveSecurite || reserveExtensible)) {
|
||||
const msg = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-demande-declencher-sort.hbs`, {
|
||||
actor: this.actor,
|
||||
sorts: sorts,
|
||||
coord: coord,
|
||||
tete: { reserveSecurite: reserveSecurite, reserveExtensible: reserveExtensible }
|
||||
})
|
||||
ChatMessage.create({
|
||||
content: msg,
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name)
|
||||
});
|
||||
return;
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-demande-declencher-sort.hbs`, {
|
||||
actor: this.actor,
|
||||
sorts: sorts,
|
||||
coord: coord,
|
||||
tete: { reserveSecurite: reserveSecurite, reserveExtensible: reserveExtensible }
|
||||
}),
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
})
|
||||
return
|
||||
}
|
||||
await this.processSortReserve(sorts[0]);
|
||||
}
|
||||
@@ -899,9 +913,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.processSortReserve(sort);
|
||||
} else {
|
||||
ChatMessage.create({
|
||||
content:
|
||||
"Une erreur est survenue : impossible de récupérer le sort en réserve demandé.",
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name),
|
||||
content: "Une erreur est survenue : impossible de récupérer le sort en réserve demandé.",
|
||||
whisper: ChatUtility.getOwners(this.actor)
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1084,7 +1097,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async notifierResonanceSigneDraconique(coord) {
|
||||
if (!this.viewOnly && this.actor.isResonanceSigneDraconique(coord)) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(this.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) })
|
||||
});
|
||||
}
|
||||
|
||||
@@ -28,16 +28,15 @@ export class RdDTokenHud {
|
||||
await RdDTokenHud.addExtensionHudSoins(html, actor);
|
||||
|
||||
if (isCombat) {
|
||||
let combatant = game.combat.combatants.find(c => c.tokenId == tokenId);
|
||||
if (!(combatant?.actor)) {
|
||||
ui.notifications.warn(`Le combatant ${token.name} n'est pas associé à un acteur, impossible de déterminer ses actions de combat!`)
|
||||
return;
|
||||
const combatant = game.combat.combatants.find(c => c.tokenId == tokenId)
|
||||
const actor = RdDCombatManager.getActorCombatant(combatant, { warning: false })
|
||||
if (actor) {
|
||||
let actions = RdDCombatManager.listActionsActorCombatant(actor)
|
||||
// initiative
|
||||
await RdDTokenHud.addExtensionHudInit(html, combatant, actions)
|
||||
// combat
|
||||
await RdDTokenHud.addExtensionHudCombat(html, combatant, token, actions)
|
||||
}
|
||||
let actions = RdDCombatManager.listActionsCombat(combatant);
|
||||
// initiative
|
||||
await RdDTokenHud.addExtensionHudInit(html, combatant, actions);
|
||||
// combat
|
||||
await RdDTokenHud.addExtensionHudCombat(html, combatant, actions);
|
||||
}
|
||||
|
||||
|
||||
@@ -68,8 +67,8 @@ export class RdDTokenHud {
|
||||
});
|
||||
}
|
||||
|
||||
static async addExtensionHudCombat(html, combatant, actions) {
|
||||
const hudData = { combatant, actions, commandes: [] };
|
||||
static async addExtensionHudCombat(html, combatant, token, actions) {
|
||||
const hudData = { combatant, token, actions, commandes: [] };
|
||||
const controlIconTarget = html.find('.control-icon[data-action=target]');
|
||||
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
|
||||
(event) => {
|
||||
@@ -80,7 +79,7 @@ export class RdDTokenHud {
|
||||
combatant.actor.conjurerPossession(possession);
|
||||
}
|
||||
else {
|
||||
combatant.actor.rollArme(action);
|
||||
combatant.actor.rollArme(action, 'competence', token)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { RdDCombat } from "./rdd-combat.js";
|
||||
import { Misc } from "./misc.js";
|
||||
import { Grammar } from "./grammar.js";
|
||||
import { TMRUtility } from "./tmr-utility.js";
|
||||
import { DialogItemAchat } from "./dialog-item-achat.js";
|
||||
import { DialogItemAchat } from "./achat-vente/dialog-item-achat.js";
|
||||
import { ReglesOptionnelles } from "./settings/regles-optionnelles.js";
|
||||
import { RdDDice } from "./rdd-dice.js";
|
||||
import { RdDItem } from "./item.js";
|
||||
@@ -18,6 +18,8 @@ import { RdDRaretes } from "./item/raretes.js";
|
||||
import { RdDEmpoignade } from "./rdd-empoignade.js";
|
||||
import { ExperienceLog } from "./actor/experience-log.js";
|
||||
import { RdDCoeur } from "./coeur/rdd-coeur.js";
|
||||
import { APP_ASTROLOGIE_REFRESH } from "./sommeil/app-astrologie.js";
|
||||
import { RDD_CONFIG } from "./constants.js";
|
||||
|
||||
/* -------------------------------------------- */
|
||||
// This table starts at 0 -> niveau -10
|
||||
@@ -31,7 +33,7 @@ function _buildAllSegmentsFatigue(max) {
|
||||
const cycle = [5, 2, 4, 1, 3, 0];
|
||||
const fatigue = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
|
||||
for (let i = 0; i <= max; i++) {
|
||||
const ligneFatigue = duplicate(fatigue[i]);
|
||||
const ligneFatigue = foundry.utils.duplicate(fatigue[i]);
|
||||
const caseIncrementee = cycle[i % 6];
|
||||
ligneFatigue[caseIncrementee]++;
|
||||
ligneFatigue[caseIncrementee + 6]++;
|
||||
@@ -45,7 +47,7 @@ function _buildAllSegmentsFatigue(max) {
|
||||
function _cumulSegmentsFatigue(matrix) {
|
||||
let cumulMatrix = [];
|
||||
for (let line of matrix) {
|
||||
let cumul = duplicate(line);
|
||||
let cumul = foundry.utils.duplicate(line);
|
||||
|
||||
for (let i = 1; i < 12; i++) {
|
||||
cumul[i] += cumul[i - 1];
|
||||
@@ -97,9 +99,8 @@ export class RdDUtility {
|
||||
// persistent handling of conteneur show/hide
|
||||
static afficheContenu = {}
|
||||
/* -------------------------------------------- */
|
||||
static async init() {
|
||||
Hooks.on("renderChatMessage", async (app, html, msg) => RdDUtility.onRenderChatMessage(app, html, msg));
|
||||
Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html));
|
||||
static async initHooks() {
|
||||
Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html))
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -205,6 +206,7 @@ export class RdDUtility {
|
||||
'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/common/timestamp.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/common/date-heure.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/common/periodicite.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/common/enum-duree.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/common/compendium-link.hbs',
|
||||
@@ -259,8 +261,6 @@ export class RdDUtility {
|
||||
];
|
||||
|
||||
Handlebars.registerHelper('either', (a, b) => a ?? b);
|
||||
Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col));
|
||||
Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col));
|
||||
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
|
||||
Handlebars.registerHelper('lowerFirst', str => Misc.lowerFirst(str ?? 'Null'));
|
||||
Handlebars.registerHelper('upper', str => str?.toUpperCase() ?? '');
|
||||
@@ -269,6 +269,10 @@ export class RdDUtility {
|
||||
Handlebars.registerHelper('apostrophe', (article, str) => Grammar.apostrophe(article, str));
|
||||
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
|
||||
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
|
||||
|
||||
Handlebars.registerHelper('RDD_CONFIG', path => RDD_CONFIG[path])
|
||||
Handlebars.registerHelper('computeResolutionScore', (row, col) => RdDResolutionTable.computePercentage(row, col));
|
||||
Handlebars.registerHelper('computeResolutionChances', (row, col) => RdDResolutionTable.computeChances(row, col));
|
||||
Handlebars.registerHelper('buildLigneInventaire', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildLigneInventaire(item, options)); });
|
||||
Handlebars.registerHelper('buildInventaireConteneur', (actorId, itemId, options) => { return new Handlebars.SafeString(RdDUtility.buildInventaireConteneur(actorId, itemId, options)); });
|
||||
Handlebars.registerHelper('buildContenuConteneur', (item, options) => { return new Handlebars.SafeString(RdDUtility.buildContenuConteneur(item, options)); });
|
||||
@@ -286,6 +290,7 @@ export class RdDUtility {
|
||||
|
||||
Handlebars.registerHelper('array-includes', (array, value) => array.includes(value));
|
||||
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
|
||||
Handlebars.registerHelper('isLastIndex', (index, list) => index + 1 >= list.length);
|
||||
Handlebars.registerHelper('regle-optionnelle', (option) => ReglesOptionnelles.isUsing(option));
|
||||
Handlebars.registerHelper('trier', list => list.sort((a, b) => a.name.localeCompare(b.name)));
|
||||
Handlebars.registerHelper('filtreTriCompetences', competences => RdDItemCompetence.triVisible(competences));
|
||||
@@ -297,6 +302,14 @@ export class RdDUtility {
|
||||
Handlebars.registerHelper('plusMoins', diff => (diff > 0 ? '+' : '') + Math.round(diff))
|
||||
Handlebars.registerHelper('experienceLog-topic', topic => ExperienceLog.labelTopic(topic));
|
||||
|
||||
// Handle v12 removal of this helper
|
||||
Handlebars.registerHelper('select', function (selected, options) {
|
||||
const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected));
|
||||
const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']');
|
||||
const html = options.fn(this);
|
||||
return html.replace(rgx, "$& selected");
|
||||
});
|
||||
|
||||
return loadTemplates(templatePaths);
|
||||
}
|
||||
|
||||
@@ -344,13 +357,15 @@ export class RdDUtility {
|
||||
let objetVersConteneur = {};
|
||||
// Attribution des objets aux conteneurs
|
||||
for (let conteneur of conteneurs) {
|
||||
conteneur.subItems = [];
|
||||
for (let id of conteneur.system.contenu ?? []) {
|
||||
let objet = inventaires.find(objet => (id == objet._id));
|
||||
if (objet) {
|
||||
objet.estContenu = true; // Permet de filtrer ce qui est porté dans le template
|
||||
objetVersConteneur[id] = conteneur._id;
|
||||
conteneur.subItems.push(objet);
|
||||
if (conteneur.isConteneur()) {
|
||||
conteneur.subItems = [];
|
||||
for (let id of conteneur.system.contenu ?? []) {
|
||||
let objet = inventaires.find(objet => (id == objet._id));
|
||||
if (objet) {
|
||||
objet.estContenu = true;
|
||||
objetVersConteneur[id] = conteneur._id;
|
||||
conteneur.subItems.push(objet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -548,50 +563,60 @@ export class RdDUtility {
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async jetEncaissement(rollData, armure, options = { showDice: HIDE_DICE }) {
|
||||
let formula = "2d10";
|
||||
static async jetEncaissement(actor, rollData, armure, options = { showDice: HIDE_DICE }) {
|
||||
const diff = Math.abs(rollData.diffLibre);
|
||||
let formula = RdDUtility.formuleEncaissement(diff, options)
|
||||
const roll = await RdDDice.roll(formula, options);
|
||||
|
||||
// Chaque dé fait au minmum la difficulté libre
|
||||
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
|
||||
if (rollData.diffLibre < 0) {
|
||||
let valeurMin = Math.abs(rollData.diffLibre);
|
||||
formula += "min" + valeurMin;
|
||||
}
|
||||
RdDUtility.remplaceDeMinParDifficulte(roll, diff, options);
|
||||
|
||||
return await RdDUtility.prepareEncaissement(actor, rollData, roll, armure);
|
||||
}
|
||||
|
||||
static remplaceDeMinParDifficulte(roll, diff, options) {
|
||||
if (!ReglesOptionnelles.isUsing('degat-minimum-malus-libre-simple')) {
|
||||
return
|
||||
}
|
||||
// Chaque dé fait au minmum la difficulté libre
|
||||
if (ReglesOptionnelles.isUsing('degat-ajout-malus-libre')) {
|
||||
if (rollData.diffLibre < 0) {
|
||||
let valeurMin = Math.abs(rollData.diffLibre);
|
||||
formula += "+" + valeurMin;
|
||||
}
|
||||
}
|
||||
|
||||
let roll = await RdDDice.roll(formula, options);
|
||||
|
||||
// 1 dé fait au minmum la difficulté libre
|
||||
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre-simple')) {
|
||||
if (rollData.diffLibre < 0) {
|
||||
let valeurMin = Math.abs(rollData.diffLibre);
|
||||
if (roll.terms[0].results[0].result < valeurMin) {
|
||||
roll.terms[0].results[0].result = valeurMin;
|
||||
} else if (roll.terms[0].results[1].result < valeurMin) {
|
||||
roll.terms[0].results[1].result = valeurMin;
|
||||
}
|
||||
roll._total = roll.terms[0].results[0].result + roll.terms[0].results[1].result;
|
||||
}
|
||||
const total = options.forceDiceResult?.total;
|
||||
if (total) {
|
||||
const reste = Math.max(total - diff, 1)
|
||||
roll.terms[0].number = reste + diff
|
||||
}
|
||||
else {
|
||||
if (roll.terms[0].results[0].result < diff) {
|
||||
roll.terms[0].results[0].result = diff;
|
||||
} else if (roll.terms[0].results[1].result < diff) {
|
||||
roll.terms[0].results[1].result = diff;
|
||||
}
|
||||
roll._total = roll.terms[0].results[0].result + roll.terms[0].results[1].result;
|
||||
}
|
||||
}
|
||||
|
||||
return await RdDUtility.prepareEncaissement(rollData, roll, armure);
|
||||
static formuleEncaissement(diff, options) {
|
||||
// Chaque dé fait au minimum la difficulté libre
|
||||
if (ReglesOptionnelles.isUsing('degat-minimum-malus-libre')) {
|
||||
return `2d10min${diff}`
|
||||
}
|
||||
return '2d10'
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async prepareEncaissement(rollData, roll, armure) {
|
||||
const jetTotal = roll.total + rollData.dmg.total - armure;
|
||||
let encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
|
||||
let over20 = Math.max(jetTotal - 20, 0);
|
||||
encaissement.dmg = rollData.dmg;
|
||||
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(this.type);
|
||||
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;';
|
||||
static async prepareEncaissement(actor, rollData, roll, armure) {
|
||||
// La difficulté d'ataque s'ajoute aux dégâts
|
||||
const bonusDegatsDiffLibre = ReglesOptionnelles.isUsing('degat-ajout-malus-libre') ? Math.abs(rollData.diffLibre ?? 0) : 0
|
||||
const jetTotal = roll.total + rollData.dmg.total - armure + bonusDegatsDiffLibre
|
||||
const encaissement = RdDUtility._selectEncaissement(jetTotal, rollData.dmg.mortalite);
|
||||
const over20 = Math.max(jetTotal - 20, 0);
|
||||
encaissement.dmg = rollData.dmg
|
||||
if (ReglesOptionnelles.isUsing('localisation-aleatoire')) {
|
||||
encaissement.dmg.loc = rollData.dmg.loc ?? await RdDUtility.getLocalisation(actor.type)
|
||||
encaissement.dmg.loc.label = encaissement.dmg.loc.label ?? 'Corps;'
|
||||
}
|
||||
else {
|
||||
encaissement.dmg.loc = { label: '' }
|
||||
}
|
||||
encaissement.dmg.bonusDegatsDiffLibre = bonusDegatsDiffLibre
|
||||
encaissement.roll = roll;
|
||||
encaissement.armure = armure;
|
||||
encaissement.penetration = rollData.arme?.system.penetration ?? 0;
|
||||
@@ -607,40 +632,32 @@ export class RdDUtility {
|
||||
for (let encaissement of table) {
|
||||
if ((encaissement.minimum === undefined || encaissement.minimum <= degats)
|
||||
&& (encaissement.maximum === undefined || degats <= encaissement.maximum)) {
|
||||
return duplicate(encaissement);
|
||||
return foundry.utils.duplicate(encaissement);
|
||||
}
|
||||
}
|
||||
return duplicate(table[0]);
|
||||
return foundry.utils.duplicate(table[0]);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async _evaluatePerte(formula, over20) {
|
||||
let perte = new Roll(formula, { over20: over20 });
|
||||
await perte.evaluate({ async: true });
|
||||
await perte.evaluate();
|
||||
return perte.total;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async responseNombreAstral(callData) {
|
||||
let actor = game.actors.get(callData.id);
|
||||
actor.ajouteNombreAstral(callData);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static onSocketMessage(sockmsg) {
|
||||
switch (sockmsg.msg) {
|
||||
case "msg_gm_chat_message":
|
||||
return ChatUtility.handleGMChatMessage(sockmsg.data);
|
||||
case "msg_app_astrologie_refresh":
|
||||
return Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
||||
case "msg_request_nombre_astral":
|
||||
return game.system.rdd.calendrier.requestNombreAstral(sockmsg.data);
|
||||
case "msg_response_nombre_astral":
|
||||
return RdDUtility.responseNombreAstral(sockmsg.data);
|
||||
return game.system.rdd.calendrier.requestNombreAstral(sockmsg.data)
|
||||
case "msg_tmr_move":
|
||||
let actor = game.actors.get(sockmsg.data.actorId);
|
||||
if (actor.isOwner || game.user.isGM) {
|
||||
actor.refreshTMRView();
|
||||
actor.refreshTMRView()
|
||||
}
|
||||
break;
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,6 +746,15 @@ export class RdDUtility {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
static getSelectedToken(actor) {
|
||||
if (canvas.tokens.controlled.length > 0) {
|
||||
const tokens = canvas.tokens.controlled
|
||||
.filter(it => it.actor.id == actor.id)
|
||||
return tokens[0]
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static getSelectedActor(msgPlayer = undefined) {
|
||||
if (canvas.tokens.controlled.length == 1) {
|
||||
let token = canvas.tokens.controlled[0];
|
||||
@@ -754,7 +780,7 @@ export class RdDUtility {
|
||||
/* -------------------------------------------- */
|
||||
static createMonnaie(name, cout, img = "", enc = 0.01) {
|
||||
let piece = {
|
||||
name: name, type: 'monnaie', img: img, _id: randomID(16),
|
||||
name: name, type: 'monnaie', img: img, _id: foundry.utils.randomID(16),
|
||||
dasystemta: {
|
||||
quantite: 0,
|
||||
cout: cout,
|
||||
@@ -792,17 +818,13 @@ export class RdDUtility {
|
||||
user: game.user.id,
|
||||
rollMode: modeOverride || game.settings.get("core", "rollMode"),
|
||||
content: content
|
||||
};
|
||||
|
||||
if (["gmroll", "blindroll"].includes(chatData.rollMode)) chatData["whisper"] = ChatMessage.getWhisperRecipients("GM").map(u => u.id);
|
||||
if (chatData.rollMode === "blindroll") chatData["blind"] = true;
|
||||
else if (chatData.rollMode === "selfroll") chatData["whisper"] = [game.user];
|
||||
}
|
||||
ChatUtility.applyRollMode(chatData)
|
||||
|
||||
if (forceWhisper) { // Final force !
|
||||
chatData["speaker"] = ChatMessage.getSpeaker();
|
||||
chatData["whisper"] = ChatMessage.getWhisperRecipients(forceWhisper);
|
||||
chatData.speaker = ChatMessage.getSpeaker();
|
||||
chatData.whisper = ChatMessage.getWhisperRecipients(forceWhisper);
|
||||
}
|
||||
|
||||
return chatData;
|
||||
}
|
||||
|
||||
@@ -859,13 +881,13 @@ export class RdDUtility {
|
||||
/* -------------------------------------------- */
|
||||
static afficherHeuresChanceMalchance(heureNaissance) {
|
||||
if (game.user.isGM) {
|
||||
const heure = RdDTimestamp.findHeure(heureNaissance - 1);
|
||||
const heure = RdDTimestamp.findHeure(heureNaissance)
|
||||
if (heureNaissance && heure) {
|
||||
let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance);
|
||||
const current = game.system.rdd.calendrier.heureCourante();
|
||||
const ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance)
|
||||
const current = game.system.rdd.calendrier.heureCourante()
|
||||
ChatMessage.create({
|
||||
content: `A l'heure de <strong>${current.label}</strong>, le modificateur de Chance/Malchance est de <strong>${Misc.toSignedString(ajustement)}</strong> pour l'heure de naissance <strong>${heure.label}</strong>.`,
|
||||
whisper: ChatMessage.getWhisperRecipients("GM")
|
||||
whisper: ChatUtility.getGMs()
|
||||
});
|
||||
}
|
||||
else if (heureNaissance) {
|
||||
@@ -884,16 +906,10 @@ export class RdDUtility {
|
||||
if (compName.includes('Thanatos')) {
|
||||
let message = "Vous avez mis des points d'Expérience dans la Voie de Thanatos !<br>Vous devez réduire manuellement d'un même montant d'XP une autre compétence Draconique.";
|
||||
ChatMessage.create({
|
||||
whisper: ChatMessage.getWhisperRecipients(game.user.name),
|
||||
whisper: ChatUtility.getUserAndGMs(),
|
||||
content: message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------- */
|
||||
static async onRenderChatMessage(app, html, msg) {
|
||||
// TODO
|
||||
//console.log(app, html, msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ export const referenceAjustements = {
|
||||
isVisible: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0,
|
||||
isUsed: (rollData, actor) => rollData.arme?.system.magique && Number(rollData.arme?.system.ecaille_efficacite) > 0,
|
||||
getLabel: (rollData, actor) => "Ecaille d'Efficacité: ",
|
||||
getValue: (rollData, actor) => Math.max(Number(rollData.arme?.system.ecaille_efficacite), 0),
|
||||
getValue: (rollData, actor) => rollData.arme?.system.magique ? Math.max(Number(rollData.arme?.system.ecaille_efficacite), 0) : 0,
|
||||
},
|
||||
finesse: {
|
||||
isUsed: (rollData, actor) => RdDBonus.isDefenseAttaqueFinesse(rollData),
|
||||
@@ -166,7 +166,7 @@ export class RollDataAjustements {
|
||||
/* -------------------------------------------- */
|
||||
static calcul(rollData, actor) {
|
||||
// s'assurer de la correction des infos rollData
|
||||
mergeObject(rollData, { ajustements: {}, use: {} }, { overwrite: false })
|
||||
foundry.utils.mergeObject(rollData, { ajustements: {}, use: {} }, { overwrite: false })
|
||||
|
||||
for (var key in referenceAjustements) {
|
||||
const reference = referenceAjustements[key];
|
||||
|
||||
91
module/settings/options-avancees.js
Normal file
91
module/settings/options-avancees.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { SYSTEM_RDD } from "../constants.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
export const EXPORT_CSV_SCRIPTARIUM = 'export-csv-scriptarium'
|
||||
|
||||
const OPTIONS_AVANCEES = [
|
||||
{ group: 'Menus', name: EXPORT_CSV_SCRIPTARIUM, descr: "Proposer le menu d'export csv Scriptarium" },
|
||||
]
|
||||
|
||||
export class OptionsAvancees extends FormApplication {
|
||||
static initSettings() {
|
||||
for (const regle of OPTIONS_AVANCEES) {
|
||||
const name = regle.name
|
||||
const id = OptionsAvancees._getId(name)
|
||||
game.settings.register(SYSTEM_RDD, id, { name: id, scope: regle.scope ?? "world", config: false, default: regle.default == undefined ? true : regle.default, type: Boolean })
|
||||
}
|
||||
|
||||
game.settings.registerMenu(SYSTEM_RDD, "rdd-options-avancees", {
|
||||
name: "Configurer les options avancées",
|
||||
label: "Options avancées",
|
||||
hint: "Ouvre la fenêtre de configuration des options avancées",
|
||||
icon: "fas fa-bars",
|
||||
type: OptionsAvancees
|
||||
})
|
||||
}
|
||||
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
}
|
||||
|
||||
static _getId(name) {
|
||||
return `rdd-advanced-${name}`
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
id: "options-avancees",
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/settings/options-avancees.hbs",
|
||||
height: 650,
|
||||
width: 550,
|
||||
minimizable: false,
|
||||
closeOnSubmit: true,
|
||||
title: "Options avancées"
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
getData() {
|
||||
let formData = super.getData()
|
||||
const regles = OPTIONS_AVANCEES.filter(it => game.user.isGM || it.scope == "client")
|
||||
.map(it => {
|
||||
it = foundry.utils.duplicate(it)
|
||||
it.id = OptionsAvancees._getId(it.name)
|
||||
it.active = OptionsAvancees.isSet(it.name)
|
||||
return it
|
||||
})
|
||||
formData.regles = regles
|
||||
formData.groups = Misc.classify(regles, it => it.group)
|
||||
return formData
|
||||
}
|
||||
|
||||
static getSettingKey(name){
|
||||
return `${SYSTEM_RDD}.${this._getId(name)}`
|
||||
}
|
||||
|
||||
static isUsing(name) {
|
||||
return OptionsAvancees.isSet(name)
|
||||
}
|
||||
|
||||
static isSet(name) {
|
||||
return game.settings.get(SYSTEM_RDD, OptionsAvancees._getId(name))
|
||||
}
|
||||
|
||||
static set(name, value) {
|
||||
return game.settings.set(SYSTEM_RDD, OptionsAvancees._getId(name), value ? true : false)
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
html.find(".select-option").click((event) => {
|
||||
if (event.currentTarget.attributes.name) {
|
||||
let id = event.currentTarget.attributes.name.value
|
||||
let isChecked = event.currentTarget.checked
|
||||
game.settings.set(SYSTEM_RDD, id, isChecked)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async _updateObject(event, formData) {
|
||||
this.close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const listeReglesOptionnelles = [
|
||||
{ group: 'Récupération', name: 'recuperation-moral', descr: "Le moral revient vers 0 durant Château Dormant"},
|
||||
|
||||
|
||||
{ group: 'Règles de combat', name: 'localisation-aleatoire', descr: "Proposer une localisation aléatoire des blessures" },
|
||||
{ group: 'Règles de combat', name: 'recul', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
|
||||
{ group: 'Règles de combat', name: 'resistanceArmeParade', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
|
||||
{ group: 'Règles de combat', name: 'deteriorationArmure', descr: "Tenir compte de la détérioration des armures" },
|
||||
@@ -26,6 +27,7 @@ const listeReglesOptionnelles = [
|
||||
|
||||
{ group: 'Confirmations', name: 'confirmer-combat-sans-cible', descr: "Confirmer avant une attaque sans cible", scope: "client"},
|
||||
{ group: 'Confirmations', name: 'confirmation-tmr', descr: "Confirmer pour monter dans les TMR", scope: "client"},
|
||||
{ group: 'Confirmations', name: 'confirmation-tmr-rencontre', descr: "Confirmer pour monter dans les TMR avec rencontre en attente", scope: "client"},
|
||||
{ group: 'Confirmations', name: 'confirmation-refouler', descr: "Confirmer avant de refouler", scope: "client"},
|
||||
{ group: 'Confirmations', name: 'confirmation-vider', descr: "Confirmer pour vider l'équipement", scope: "client"},
|
||||
{ group: 'Confirmations', name: 'confirmation-supprimer-lien-acteur', descr: "Confirmer pour détacher un animal/suivant/véhicule", scope: "client"},
|
||||
@@ -45,7 +47,7 @@ const listeReglesOptionnelles = [
|
||||
const uniquementJoueur = listeReglesOptionnelles.filter(it => it.uniquementJoueur).map(it=>it.name);
|
||||
|
||||
export class ReglesOptionnelles extends FormApplication {
|
||||
static init() {
|
||||
static initSettings() {
|
||||
for (const regle of listeReglesOptionnelles) {
|
||||
const name = regle.name;
|
||||
const id = ReglesOptionnelles._getIdRegle(name);
|
||||
@@ -70,23 +72,21 @@ export class ReglesOptionnelles extends FormApplication {
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
const options = super.defaultOptions;
|
||||
mergeObject(options, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
id: "regles-optionnelles",
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionnelles.html",
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionnelles.hbs",
|
||||
height: 650,
|
||||
width: 550,
|
||||
minimizable: false,
|
||||
closeOnSubmit: true,
|
||||
title: "Règles optionnelles"
|
||||
});
|
||||
return options;
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
getData() {
|
||||
let formData = super.getData();
|
||||
const regles = listeReglesOptionnelles.filter(it => game.user.isGM || it.scope == "client").map(it => {
|
||||
it = duplicate(it);
|
||||
it = foundry.utils.duplicate(it);
|
||||
it.id = ReglesOptionnelles._getIdRegle(it.name);
|
||||
it.active = ReglesOptionnelles.isSet(it.name);
|
||||
return it;
|
||||
|
||||
@@ -18,8 +18,8 @@ const rddStatusEffects = [
|
||||
{ rdd: true, id: STATUSES.StatusStunned, label: 'EFFECT.StatusStunned', icon: 'icons/svg/stoned.svg', "duration.rounds": 1 },
|
||||
{ rdd: true, id: STATUSES.StatusBleeding, label: 'EFFECT.StatusBleeding', icon: 'icons/svg/blood.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusProne, label: 'EFFECT.StatusProne', icon: 'icons/svg/falling.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', label: 'EFFECT.StatusGrappling', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', label: 'EFFECT.StatusGrappled', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusGrappling, tint: '#33cc33', label: 'EFFECT.StatusGrappling', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
|
||||
{ rdd: true, id: STATUSES.StatusGrappled, tint: '#ff9900', label: 'EFFECT.StatusGrappled', icon: 'systems/foundryvtt-reve-de-dragon/icons/empoignade.webp' },
|
||||
{ rdd: true, id: STATUSES.StatusRestrained, label: 'EFFECT.StatusRestrained', icon: 'icons/svg/net.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusUnconscious, label: 'EFFECT.StatusUnconscious', icon: 'icons/svg/unconscious.svg' },
|
||||
{ rdd: true, id: STATUSES.StatusBlind, label: 'EFFECT.StatusBlind', icon: 'icons/svg/blind.svg' },
|
||||
@@ -65,7 +65,7 @@ export class StatusEffects extends FormApplication {
|
||||
|
||||
static valeurSurprise(effect, isCombat) {
|
||||
if (statusSurpriseTotale.intersects(effect.statuses)) {
|
||||
return 2;
|
||||
return 2
|
||||
}
|
||||
if (statusDemiSurprise.intersects(effect.statuses)) {
|
||||
return 1
|
||||
@@ -94,7 +94,7 @@ export class StatusEffects extends FormApplication {
|
||||
static prepareActiveEffect(effectId) {
|
||||
let status = rddStatusEffects.find(it => it.id == effectId)
|
||||
if (status) {
|
||||
status = duplicate(status)
|
||||
status = foundry.utils.duplicate(status)
|
||||
status.statuses = [effectId]
|
||||
}
|
||||
return status;
|
||||
@@ -110,7 +110,7 @@ export class StatusEffects extends FormApplication {
|
||||
|
||||
static get defaultOptions() {
|
||||
const options = super.defaultOptions;
|
||||
mergeObject(options, {
|
||||
foundry.utils.mergeObject(options, {
|
||||
id: "status-effects",
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/settings/status-effects.html",
|
||||
height: 800,
|
||||
@@ -125,7 +125,7 @@ export class StatusEffects extends FormApplication {
|
||||
getData() {
|
||||
const used = StatusEffects._getUseStatusEffects();
|
||||
let formData = super.getData();
|
||||
formData.effects = duplicate(CONFIG.RDD.allEffects);
|
||||
formData.effects = foundry.utils.duplicate(CONFIG.RDD.allEffects);
|
||||
formData.effects.forEach(it => it.active = used.includes(it.id))
|
||||
return formData;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ChatUtility } from "../chat-utility.js";
|
||||
import { HIDE_DICE, SYSTEM_RDD } from "../constants.js";
|
||||
import { RdDItem } from "../item.js";
|
||||
import { Misc } from "../misc.js";
|
||||
@@ -24,10 +25,10 @@ const CONFIGURABLE_COMPENDIUMS = {
|
||||
* ======= Gestion des accès aux compendiums systèmes (ou surchargés) =======
|
||||
*/
|
||||
export class SystemCompendiums extends FormApplication {
|
||||
static init() {
|
||||
static initSettings() {
|
||||
Object.keys(CONFIGURABLE_COMPENDIUMS).forEach(compendium => {
|
||||
const definition = CONFIGURABLE_COMPENDIUMS[compendium];
|
||||
mergeObject(definition, {
|
||||
foundry.utils.mergeObject(definition, {
|
||||
compendium: compendium,
|
||||
default: SystemCompendiums._getDefaultCompendium(compendium),
|
||||
setting: SystemCompendiums._getSettingCompendium(compendium)
|
||||
@@ -111,6 +112,19 @@ export class SystemCompendiums extends FormApplication {
|
||||
return elements;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async loadCompendiumData(compendium) {
|
||||
const pack = game.packs.get(compendium);
|
||||
return await pack?.getDocuments() ?? [];
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async loadCompendium(compendium, filter = item => true) {
|
||||
let compendiumData = await SystemCompendiums.loadCompendiumData(compendium);
|
||||
return compendiumData.filter(filter);
|
||||
}
|
||||
|
||||
|
||||
static async getDefaultItems(compendium) {
|
||||
const pack = game.packs.get(SystemCompendiums._getDefaultCompendium(compendium));
|
||||
if (pack.metadata.type == 'Item') {
|
||||
@@ -138,7 +152,7 @@ export class SystemCompendiums extends FormApplication {
|
||||
|
||||
static get defaultOptions() {
|
||||
const options = super.defaultOptions;
|
||||
mergeObject(options, {
|
||||
foundry.utils.mergeObject(options, {
|
||||
id: "system-compendiums",
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/settings/system-compendiums.html",
|
||||
height: 'fit-content',
|
||||
@@ -152,7 +166,7 @@ export class SystemCompendiums extends FormApplication {
|
||||
|
||||
getData() {
|
||||
const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS)
|
||||
.map(it => mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) }));
|
||||
.map(it => foundry.utils.mergeObject(it, { value: SystemCompendiums.getCompendium(it.compendium) }, { inplace: false }))
|
||||
const availableCompendiums = game.packs.map(pack => {
|
||||
return {
|
||||
name: pack.collection,
|
||||
@@ -160,10 +174,10 @@ export class SystemCompendiums extends FormApplication {
|
||||
type: pack.metadata.type
|
||||
}
|
||||
});
|
||||
return mergeObject(super.getData(), {
|
||||
return foundry.utils.mergeObject(super.getData(), {
|
||||
systemCompendiums: systemCompendiums,
|
||||
availableCompendiums: availableCompendiums
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
@@ -235,12 +249,12 @@ export class CompendiumTableHelpers {
|
||||
let max = 0;
|
||||
const total = rows.map(it => it.frequence).reduce(Misc.sum(), 0);
|
||||
return rows.map(row => {
|
||||
const frequence = row.frequence;
|
||||
row.min = max + 1;
|
||||
row.max = max + frequence;
|
||||
const frequence = row.frequence
|
||||
row.min = max + 1
|
||||
row.max = max + frequence
|
||||
row.total = total
|
||||
max += frequence;
|
||||
return row;
|
||||
max += frequence
|
||||
return row
|
||||
})
|
||||
}
|
||||
static async getRandom(table, type, subTypes = ['objet'], forcedRoll = undefined, localisation = undefined) {
|
||||
@@ -259,8 +273,8 @@ export class CompendiumTableHelpers {
|
||||
}
|
||||
const total = table[0].total;
|
||||
const formula = `1d${total}`;
|
||||
if (forcedRoll == undefined && (forcedRoll > total || forcedRoll <= 0)) {
|
||||
ui.notifications.warn(`Jet de rencontre ${forcedRoll} en dehors de la table [1..${total}], le jet est relancé`);
|
||||
if (forcedRoll != undefined && (forcedRoll > total || forcedRoll <= 0)) {
|
||||
ui.notifications.warn(`Jet forcé ${forcedRoll} en dehors de la table [1..${total}], le jet est relancé`);
|
||||
forcedRoll = undefined;
|
||||
}
|
||||
const roll = forcedRoll ? { total: forcedRoll, formula } : await RdDDice.roll(formula, { showDice: HIDE_DICE });
|
||||
@@ -275,7 +289,7 @@ export class CompendiumTableHelpers {
|
||||
return;
|
||||
}
|
||||
const percentages = (row.total == 100) ? '%' : ''
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.html', {
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll.hbs', {
|
||||
roll: row.roll,
|
||||
document: row.document,
|
||||
percentages,
|
||||
@@ -290,12 +304,12 @@ export class CompendiumTableHelpers {
|
||||
sound: CONFIG.sounds.dice,
|
||||
content: flavorContent
|
||||
};
|
||||
ChatMessage.create(messageData, { rollMode: "gmroll" });
|
||||
await ChatUtility.createChatWithRollMode(messageData)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static async tableToChatMessage(table, type, subTypes, typeName = undefined) {
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.html', {
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table.hbs', {
|
||||
img: RdDItem.getDefaultImg(subTypes[0]),
|
||||
typeName: typeName ?? Misc.typeName(type, subTypes[0]),
|
||||
table,
|
||||
@@ -303,10 +317,10 @@ export class CompendiumTableHelpers {
|
||||
});
|
||||
const messageData = {
|
||||
user: game.user.id,
|
||||
whisper: game.user.id,
|
||||
whisper: [game.user],
|
||||
content: flavorContent
|
||||
};
|
||||
ChatMessage.create(messageData, { rollMode: "gmroll" });
|
||||
await ChatUtility.createChatWithRollMode(messageData)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export class AppAstrologie extends Application {
|
||||
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/sommeil/app-astrologie.hbs",
|
||||
title: "Astrologie",
|
||||
width: 'fit-content',
|
||||
@@ -25,19 +25,18 @@ export class AppAstrologie extends Application {
|
||||
classes: ['calendar-astrologie'],
|
||||
popOut: true,
|
||||
resizable: false
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor(actor, options = {}) {
|
||||
super(options);
|
||||
this.actor = actor;
|
||||
this.hookReference = Hooks.on(APP_ASTROLOGIE_REFRESH, () => this.refreshAstrologie());
|
||||
}
|
||||
|
||||
getData(options) {
|
||||
this.appData = super.getData(options)
|
||||
const calendrier = game.system.rdd.calendrier;
|
||||
mergeObject(this.appData, {
|
||||
foundry.utils.mergeObject(this.appData, {
|
||||
isGM: game.user.isGM,
|
||||
isActor: this.actor != undefined,
|
||||
calendrier: calendrier.getTimestamp().toCalendrier(),
|
||||
@@ -50,7 +49,7 @@ export class AppAstrologie extends Application {
|
||||
signeNaissance: RdDTimestamp.definition(0)
|
||||
}
|
||||
})
|
||||
return this.appData;
|
||||
return this.appData
|
||||
}
|
||||
|
||||
getActorAstrologie() {
|
||||
@@ -85,9 +84,10 @@ export class AppAstrologie extends Application {
|
||||
const nbAstral = calendrier.getNombreAstral()
|
||||
const heures = RdDTimestamp.heures();
|
||||
return {
|
||||
ajustementsActors: game.actors.filter(it => it.isPersonnage() && it.hasPlayerOwner)
|
||||
ajustementsActors: game.actors.filter(actor => actor.isPersonnageJoueur())
|
||||
.map(actor => this.getAjustementActor(actor, nbAstral, heures)),
|
||||
nombresAstraux: calendrier.getNombresAstraux().map(na => this.getDetailNombreAstral(na))
|
||||
nombresAstraux: game.system.rdd.calendrier.getNombresAstraux()
|
||||
.map(na => this.getDetailNombreAstral(na))
|
||||
}
|
||||
}
|
||||
return {}
|
||||
@@ -104,15 +104,18 @@ export class AppAstrologie extends Application {
|
||||
}
|
||||
|
||||
getDetailNombreAstral(nombreAstral) {
|
||||
const detail = duplicate(nombreAstral);
|
||||
const detail = foundry.utils.duplicate(nombreAstral);
|
||||
const timestamp = new RdDTimestamp({ indexDate: nombreAstral.index });
|
||||
detail.date = { mois: timestamp.mois, jour: timestamp.jour + 1 };
|
||||
detail.valeursFausses.forEach(fausse => fausse.actorName = game.actors.get(fausse.actorId).name ?? "Inconnu");
|
||||
detail.lectures.forEach(lecture => lecture.actorName = game.actors.get(lecture.actorId).name ?? "Inconnu");
|
||||
return detail;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
if (!this.hookReference){
|
||||
this.hookReference = Hooks.on(APP_ASTROLOGIE_REFRESH, () => this.refreshAstrologie());
|
||||
}
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.html.find('select[name="signe-astral"]').change(event => {
|
||||
@@ -145,8 +148,7 @@ export class AppAstrologie extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async onRebuild() {
|
||||
game.system.rdd.calendrier.resetNombresAstraux();
|
||||
|
||||
await game.system.rdd.calendrier.resetNombresAstraux();
|
||||
await game.system.rdd.calendrier.rebuildNombresAstraux();
|
||||
}
|
||||
|
||||
@@ -184,7 +186,7 @@ export class AppAstrologie extends Application {
|
||||
date: this.html.find('[name="joursAstrologie"]').val(),
|
||||
userId: game.user.id
|
||||
}
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
game.system.rdd.calendrier.requestNombreAstral(socketData);
|
||||
} else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
@@ -195,6 +197,8 @@ export class AppAstrologie extends Application {
|
||||
}
|
||||
|
||||
refreshAstrologie() {
|
||||
this.count = (this.count ?? 0)+1
|
||||
console.log(`Refreshing ${this.count}`);
|
||||
this.render(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@ export class DialogChateauDormant extends Dialog {
|
||||
|
||||
static async create() {
|
||||
const date = game.system.rdd.calendrier.dateCourante();
|
||||
const actors = game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage());
|
||||
|
||||
const dialogData = {
|
||||
actors: actors,
|
||||
actors: game.actors.filter(actor => actor.isPersonnageJoueur()),
|
||||
date: date,
|
||||
motifStress: `Nuit du ${date}`,
|
||||
finChateauDormant: game.system.rdd.calendrier.getTimestampFinChateauDormant()
|
||||
|
||||
@@ -6,7 +6,7 @@ export class DialogStress extends Dialog {
|
||||
motif: "Motif",
|
||||
stress: 10,
|
||||
immediat: false,
|
||||
actors: game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage())
|
||||
actors: game.actors.filter(actor => actor.isPersonnageJoueur())
|
||||
.map(actor => ({
|
||||
id: actor.id,
|
||||
name: actor.name,
|
||||
|
||||
@@ -13,18 +13,21 @@ export class Targets {
|
||||
static extractTokenData(target) {
|
||||
return { id: target?.id, name: target?.document.name, img: target?.document.texture.src ?? target?.actor.img ?? 'icons/svg/mystery-man.svg' };
|
||||
}
|
||||
|
||||
static buildActorTokenData(tokenId, actor) {
|
||||
return { id: tokenId, name: actor.name, img: actor.img ?? 'icons/svg/mystery-man.svg' };
|
||||
}
|
||||
static isTargetEntite(target) {
|
||||
return target?.actor.type == 'entite' && target?.actor.system.definition.typeentite == ENTITE_NONINCARNE;
|
||||
}
|
||||
|
||||
static async selectOneToken(onSelectTarget = target => { }) {
|
||||
const targets = Targets.listTargets();
|
||||
static async selectOneTargetToken(onSelectTarget = target => { }) {
|
||||
const targets = Targets.listTargets()
|
||||
switch (targets.length) {
|
||||
case 0: return;
|
||||
case 0:
|
||||
return
|
||||
case 1:
|
||||
onSelectTarget(targets[0]);
|
||||
return;
|
||||
onSelectTarget(targets[0])
|
||||
return
|
||||
default:
|
||||
{
|
||||
const selectData = {
|
||||
@@ -32,7 +35,7 @@ export class Targets {
|
||||
label: "Choisir une seule des cibles",
|
||||
list: targets.map(it => Targets.extractTokenData(it))
|
||||
};
|
||||
DialogSelect.select(selectData, onSelectTarget);
|
||||
DialogSelect.select(selectData, onSelectTarget)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ export const AUTO_ADJUST_DARKNESS = "auto-adjust-darkness";
|
||||
|
||||
export class AutoAdjustDarkness {
|
||||
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, AUTO_ADJUST_DARKNESS, {
|
||||
name: AUTO_ADJUST_DARKNESS,
|
||||
scope: "world",
|
||||
@@ -15,9 +15,9 @@ export class AutoAdjustDarkness {
|
||||
}
|
||||
|
||||
static async adjust(darkness) {
|
||||
if (AutoAdjustDarkness.isAuto()) {
|
||||
if (game.user.isGM && AutoAdjustDarkness.isAuto()) {
|
||||
const scene = game.scenes.viewed;
|
||||
if (scene?.globalLight && scene?.tokenVision) {
|
||||
if (scene?.environment?.globalLight?.enabled && scene?.tokenVision) {
|
||||
await scene.update({ darkness });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export class RdDCalendrierEditor extends Dialog {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
updateData(calendrierData) {
|
||||
this.calendrierData = duplicate(calendrierData);
|
||||
this.calendrierData = foundry.utils.duplicate(calendrierData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { MAX_NOMBRE_ASTRAL, RdDTimestamp, WORLD_TIMESTAMP_SETTING } from "./rdd-timestamp.js";
|
||||
import { RdDCalendrierEditor } from "./rdd-calendrier-editor.js";
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js";
|
||||
import { RdDUtility } from "../rdd-utility.js";
|
||||
import { RdDDice } from "../rdd-dice.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { DialogChronologie } from "../dialog-chronologie.js";
|
||||
@@ -16,7 +15,7 @@ const TEMPLATE_CALENDRIER = "systems/foundryvtt-reve-de-dragon/templates/time/ca
|
||||
const INITIAL_CALENDAR_POS = { top: 200, left: 200, horlogeAnalogique: true };
|
||||
/* -------------------------------------------- */
|
||||
export class RdDCalendrier extends Application {
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, "liste-nombre-astral", {
|
||||
name: "liste-nombre-astral",
|
||||
scope: "world",
|
||||
@@ -35,7 +34,7 @@ export class RdDCalendrier extends Application {
|
||||
}
|
||||
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
title: "Calendrier",
|
||||
template: TEMPLATE_CALENDRIER,
|
||||
classes: ["calendar"],
|
||||
@@ -43,15 +42,14 @@ export class RdDCalendrier extends Application {
|
||||
resizable: false,
|
||||
width: 'fit-content',
|
||||
height: 'fit-content',
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.timestamp = RdDTimestamp.getWorldTime();
|
||||
if (Misc.isUniqueConnectedGM()) { // Uniquement si GM
|
||||
if (Misc.isFirstConnectedGM()) { // Uniquement si GM
|
||||
RdDTimestamp.setWorldTime(this.timestamp);
|
||||
this.nombresAstraux = this.getNombresAstraux();
|
||||
this.rebuildNombresAstraux(); // Ensure always up-to-date
|
||||
}
|
||||
Hooks.on('updateSetting', async (setting, update, options, id) => this.onUpdateSetting(setting, update, options, id));
|
||||
@@ -108,7 +106,10 @@ export class RdDCalendrier extends Application {
|
||||
this.timestamp = RdDTimestamp.getWorldTime();
|
||||
this.positionAiguilles()
|
||||
this.render(false);
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
||||
}
|
||||
if (setting.key == SYSTEM_RDD + '.' + "liste-nombre-astral") {
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +121,10 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
fillCalendrierData(formData = {}) {
|
||||
mergeObject(formData, this.timestamp.toCalendrier());
|
||||
formData.isGM = game.user.isGM;
|
||||
foundry.utils.mergeObject(formData, this.timestamp.toCalendrier());
|
||||
formData.isGM = game.user.isGM
|
||||
formData.heures = RdDTimestamp.definitions()
|
||||
formData.horlogeAnalogique = this.horlogeAnalogique;
|
||||
formData.horlogeAnalogique = this.horlogeAnalogique
|
||||
formData.autoDarkness = AutoAdjustDarkness.isAuto()
|
||||
return formData;
|
||||
}
|
||||
@@ -167,7 +168,11 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
getNombresAstraux() {
|
||||
return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? [];
|
||||
return game.settings.get(SYSTEM_RDD, "liste-nombre-astral") ?? []
|
||||
}
|
||||
|
||||
async setNombresAstraux(nombresAstraux) {
|
||||
await game.settings.set(SYSTEM_RDD, "liste-nombre-astral", nombresAstraux)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -222,23 +227,18 @@ export class RdDCalendrier extends Application {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ajouterNombreAstral(indexDate) {
|
||||
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: HIDE_DICE, rollMode: "selfroll" });
|
||||
const nombreAstral = await RdDDice.rollHeure( { showDice: HIDE_DICE, rollMode: "selfroll" });
|
||||
return {
|
||||
nombreAstral: nombreAstral,
|
||||
valeursFausses: [],
|
||||
lectures: [],
|
||||
index: indexDate
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
resetNombresAstraux() {
|
||||
this.nombresAstraux = [];
|
||||
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", []);
|
||||
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_reset_nombre_astral",
|
||||
data: {}
|
||||
});
|
||||
async resetNombresAstraux() {
|
||||
await Promise.all(game.actors.filter(it => it.type == "personnage").map(async it => await it.deleteNombresAstraux()))
|
||||
await this.setNombresAstraux([])
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,39 +251,30 @@ export class RdDCalendrier extends Application {
|
||||
if (indexDate == undefined) {
|
||||
indexDate = this.timestamp.indexDate;
|
||||
}
|
||||
this.nombresAstraux = this.getNombresAstraux();
|
||||
let astralData = this.nombresAstraux.find((nombreAstral, i) => nombreAstral.index == indexDate);
|
||||
const nombresAstraux = this.getNombresAstraux()
|
||||
let astralData = nombresAstraux.find(it => it.index == indexDate);
|
||||
return astralData?.nombreAstral ?? 0;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rebuildNombresAstraux() {
|
||||
if (Misc.isUniqueConnectedGM()) {
|
||||
let newList = [];
|
||||
if (Misc.isFirstConnectedGM()) {
|
||||
const nombresAstraux = this.getNombresAstraux()
|
||||
let newNombresAstraux = [];
|
||||
for (let i = 0; i < MAX_NOMBRE_ASTRAL; i++) {
|
||||
let dayIndex = this.timestamp.indexDate + i;
|
||||
let na = this.nombresAstraux.find(n => n.index == dayIndex);
|
||||
let na = nombresAstraux.find(it => it.index == dayIndex);
|
||||
if (na) {
|
||||
newList[i] = na;
|
||||
newNombresAstraux[i] = na;
|
||||
} else {
|
||||
newList[i] = await this.ajouterNombreAstral(dayIndex);
|
||||
newNombresAstraux[i] = await this.ajouterNombreAstral(dayIndex);
|
||||
}
|
||||
}
|
||||
this.nombresAstraux = newList;
|
||||
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", newList);
|
||||
game.actors.filter(it => it.isPersonnage()).forEach(actor => actor.supprimerAnciensNombresAstraux());
|
||||
this.notifyChangeNombresAstraux();
|
||||
await this.setNombresAstraux(newNombresAstraux);
|
||||
}
|
||||
}
|
||||
|
||||
notifyChangeNombresAstraux() {
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH);
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_refresh_nombre_astral",
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async setNewTimestamp(newTimestamp) {
|
||||
const oldTimestamp = this.timestamp;
|
||||
@@ -346,7 +337,7 @@ export class RdDCalendrier extends Application {
|
||||
/* -------------------------------------------- */
|
||||
async requestNombreAstral(request) {
|
||||
const actor = game.actors.get(request.id);
|
||||
if (Misc.isUniqueConnectedGM()) { // Only once
|
||||
if (Misc.isFirstConnectedGM()) { // Only once
|
||||
console.log(request);
|
||||
let jourDiff = this.getLectureAstrologieDifficulte(request.date);
|
||||
let niveau = Number(request.astrologie.system.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
|
||||
@@ -373,25 +364,22 @@ export class RdDCalendrier extends Application {
|
||||
request.nbAstral = await RdDDice.rollTotal("1dhr" + request.nbAstral, {
|
||||
rollMode: "selfroll", showDice: HIDE_DICE
|
||||
});
|
||||
// Mise à jour des nombres astraux du joueur
|
||||
this.addNbAstralIncorect(request.id, request.date, request.nbAstral);
|
||||
}
|
||||
|
||||
if (Misc.getActiveUser(request.userId)?.isGM) {
|
||||
RdDUtility.responseNombreAstral(request);
|
||||
} else {
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, {
|
||||
msg: "msg_response_nombre_astral",
|
||||
data: request
|
||||
});
|
||||
}
|
||||
// Mise à jour des nombres astraux du joueur
|
||||
await this.addNbAstralJoueur(actor, request.date, request.nbAstral, request.isValid)
|
||||
Hooks.callAll(APP_ASTROLOGIE_REFRESH)
|
||||
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_app_astrologie_refresh", data: {} })
|
||||
}
|
||||
}
|
||||
|
||||
addNbAstralIncorect(actorId, date, nbAstral) {
|
||||
const astralData = this.nombresAstraux.find((nombreAstral, i) => nombreAstral.index == date);
|
||||
astralData.valeursFausses.push({ actorId: actorId, nombreAstral: nbAstral });
|
||||
game.settings.set(SYSTEM_RDD, "liste-nombre-astral", this.nombresAstraux);
|
||||
async addNbAstralJoueur(actor, date, nbAstral, isValid) {
|
||||
const nombresAstraux = this.getNombresAstraux()
|
||||
const astralData = nombresAstraux.find(it => it.index == date)
|
||||
if (astralData) {
|
||||
astralData.lectures.push({ actorId: actor.id, nombreAstral: nbAstral });
|
||||
await this.setNombresAstraux(nombresAstraux);
|
||||
await actor.ajouteNombreAstral(date, nbAstral, isValid);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
@@ -15,18 +15,18 @@ export const RDD_MINUTES_PAR_JOUR = 1440; //RDD_HEURES_PAR_JOUR * RDD_MINUTES_PA
|
||||
const ROUNDS_PAR_MINUTE = 10;
|
||||
|
||||
const DEFINITION_HEURES = [
|
||||
{ key: "vaisseau", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 },
|
||||
{ key: "sirene", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 },
|
||||
{ key: "faucon", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 },
|
||||
{ key: "couronne", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 },
|
||||
{ key: "dragon", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 },
|
||||
{ key: "epees", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 },
|
||||
{ key: "lyre", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 },
|
||||
{ key: "serpent", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 },
|
||||
{ key: "poissonacrobate", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 },
|
||||
{ key: "araignee", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 },
|
||||
{ key: "roseau", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 },
|
||||
{ key: "chateaudormant", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 },
|
||||
{ key: "vaisseau", article: "du ", label: "Vaisseau", lettreFont: 'v', saison: "Printemps", darkness: 0.9 },
|
||||
{ key: "sirene", article: "de la ", label: "Sirène", lettreFont: 'i', saison: "Printemps", darkness: 0.1 },
|
||||
{ key: "faucon", article: "du ", label: "Faucon", lettreFont: 'f', saison: "Printemps", darkness: 0 },
|
||||
{ key: "couronne", article: "de la ", label: "Couronne", lettreFont: '', saison: "Eté", darkness: 0 },
|
||||
{ key: "dragon", article: "du ", label: "Dragon", lettreFont: 'd', saison: "Eté", darkness: 0 },
|
||||
{ key: "epees", article: "des ", label: "Epées", lettreFont: 'e', saison: "Eté", darkness: 0 },
|
||||
{ key: "lyre", article: "de la ", label: "Lyre", lettreFont: 'l', saison: "Automne", darkness: 0.1 },
|
||||
{ key: "serpent", article: "du ", label: "Serpent", lettreFont: 's', saison: "Automne", darkness: 0.9 },
|
||||
{ key: "poissonacrobate", article: "du ", label: "Poisson Acrobate", lettreFont: 'p', saison: "Automne", darkness: 1 },
|
||||
{ key: "araignee", article: "de l'", label: "Araignée", lettreFont: 'a', saison: "Hiver", darkness: 1 },
|
||||
{ key: "roseau", article: "du ", label: "Roseau", lettreFont: 'r', saison: "Hiver", darkness: 1 },
|
||||
{ key: "chateaudormant", article: "du ", label: "Château Dormant", lettreFont: 'c', saison: "Hiver", darkness: 1 },
|
||||
]
|
||||
|
||||
const FORMULES_DUREE = [
|
||||
@@ -49,7 +49,7 @@ const FORMULES_PERIODE = [
|
||||
|
||||
export class RdDTimestamp {
|
||||
|
||||
static init() {
|
||||
static initSettings() {
|
||||
game.settings.register(SYSTEM_RDD, WORLD_TIMESTAMP_SETTING, {
|
||||
name: WORLD_TIMESTAMP_SETTING,
|
||||
scope: "world",
|
||||
@@ -64,6 +64,7 @@ export class RdDTimestamp {
|
||||
DEFINITION_HEURES[i].hh = RdDTimestamp.hh(i);
|
||||
DEFINITION_HEURES[i].icon = RdDTimestamp.iconeHeure(i);
|
||||
DEFINITION_HEURES[i].webp = DEFINITION_HEURES[i].icon.replace(".svg", ".webp");
|
||||
DEFINITION_HEURES[i].avecArticle = DEFINITION_HEURES[i].article + DEFINITION_HEURES[i].label
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,15 +160,21 @@ export class RdDTimestamp {
|
||||
}
|
||||
|
||||
static findHeure(heure) {
|
||||
heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
|
||||
let parHeureOuLabel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR));
|
||||
if (parHeureOuLabel.length == 1) {
|
||||
return parHeureOuLabel[0];
|
||||
let filtered
|
||||
if (Number.isInteger(Number(heure))) {
|
||||
filtered = DEFINITION_HEURES.filter(it => it.heure == Misc.modulo(Number(heure) - 1, RDD_HEURES_PAR_JOUR))
|
||||
}
|
||||
let parLabelPartiel = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
|
||||
if (parLabelPartiel.length > 0) {
|
||||
parLabelPartiel.sort(Misc.ascending(h => h.label.length));
|
||||
return parLabelPartiel[0];
|
||||
else {
|
||||
heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
|
||||
filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure || it.heure == Misc.modulo(parseInt(heure), RDD_HEURES_PAR_JOUR));
|
||||
}
|
||||
if (filtered.length == 1) {
|
||||
return filtered[0]
|
||||
}
|
||||
filtered = DEFINITION_HEURES.filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
|
||||
if (filtered.length > 0) {
|
||||
filtered.sort(Misc.ascending(h => h.label.length));
|
||||
return filtered[0]
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -202,7 +209,7 @@ export class RdDTimestamp {
|
||||
}
|
||||
|
||||
static setWorldTime(timestamp) {
|
||||
game.settings.set(SYSTEM_RDD, WORLD_TIMESTAMP_SETTING, duplicate(timestamp));
|
||||
game.settings.set(SYSTEM_RDD, WORLD_TIMESTAMP_SETTING, foundry.utils.duplicate(timestamp));
|
||||
}
|
||||
|
||||
/** construit un RdDTimestamp à partir de l'année/mois/jour/heure?/minute? */
|
||||
@@ -231,6 +238,7 @@ export class RdDTimestamp {
|
||||
|
||||
get annee() { return Math.floor(this.indexDate / RDD_JOURS_PAR_AN) }
|
||||
get mois() { return Math.floor(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN) / RDD_JOURS_PAR_MOIS) }
|
||||
get nomMois() { return Math.floor(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN) / RDD_JOURS_PAR_MOIS) }
|
||||
get jour() { return Misc.modulo(Misc.modulo(this.indexDate, RDD_JOURS_PAR_AN), RDD_JOURS_PAR_MOIS) }
|
||||
get heure() { return Math.floor(this.indexMinute / RDD_MINUTES_PAR_HEURES) }
|
||||
get minute() { return Misc.modulo(this.indexMinute, RDD_MINUTES_PAR_HEURES) }
|
||||
@@ -240,7 +248,7 @@ export class RdDTimestamp {
|
||||
|
||||
get darkness() {
|
||||
const darknessDebut = 100 * RdDTimestamp.definition(this.heure).darkness
|
||||
const darknessFin = 100 * RdDTimestamp.definition(this.heure + 1).darkness
|
||||
const darknessFin = 100 * RdDTimestamp.definition(this.heure + 1).darkness
|
||||
const darknessMinute = Math.round((darknessFin - darknessDebut) * this.minute / RDD_MINUTES_PAR_HEURES);
|
||||
return (darknessDebut + darknessMinute) / 100
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ function $loadFilters(parameters) {
|
||||
|
||||
export class FenetreRechercheTirage extends Application {
|
||||
static get defaultOptions() {
|
||||
return mergeObject(super.defaultOptions, {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
template: "systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-tirage.hbs",
|
||||
title: `Recherches et tirages`,
|
||||
width: 600,
|
||||
@@ -125,7 +125,7 @@ export class FenetreRechercheTirage extends Application {
|
||||
popOut: true,
|
||||
dragDrop: [{ dragSelector: "a.content-link" }],
|
||||
resizable: true
|
||||
});
|
||||
}, { inplace: false })
|
||||
}
|
||||
|
||||
static async create() {
|
||||
@@ -133,7 +133,7 @@ export class FenetreRechercheTirage extends Application {
|
||||
const parameters = {
|
||||
milieux: milieux,
|
||||
filterMilieux: $filterMilieux(milieux),
|
||||
filterGroups: duplicate(FILTER_GROUPS).filter(it => it.group),
|
||||
filterGroups: foundry.utils.duplicate(FILTER_GROUPS).filter(it => it.group),
|
||||
}
|
||||
const options = {}
|
||||
$loadFilters(parameters);
|
||||
@@ -147,7 +147,7 @@ export class FenetreRechercheTirage extends Application {
|
||||
}
|
||||
|
||||
async getData() {
|
||||
return mergeObject(await super.getData(), this.parameters)
|
||||
return foundry.utils.mergeObject(await super.getData(), this.parameters)
|
||||
}
|
||||
|
||||
_canDragStart() { return true; }
|
||||
@@ -294,7 +294,7 @@ class FenetreRechercheConfiguration extends Dialog {
|
||||
static async create() {
|
||||
const configuration = {
|
||||
compendiums: game.packs.filter(it => it.metadata.type == 'Item').map(it => it.metadata)
|
||||
.map(it => mergeObject({ selected: game.system.rdd.environnement.compendiums.includes(it.id) }, it))
|
||||
.map(it => foundry.utils.mergeObject({ selected: game.system.rdd.environnement.compendiums.includes(it.id) }, it))
|
||||
}
|
||||
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/tirage/fenetre-recherche-configuration.hbs", configuration);
|
||||
new FenetreRechercheConfiguration(html).render(true);
|
||||
|
||||
@@ -39,6 +39,8 @@ export class TMRRencontres {
|
||||
const frequence = it => it.system.frequence[codeTerrain];
|
||||
const row = await this.table.getRandom(frequence, filtreMauvaise, forcedRoll);
|
||||
if (row) {
|
||||
console.log("DORM", row);
|
||||
//row.document.system.computedForce = new Roll(row.document.system.formula).roll({async: false}).total;
|
||||
await CompendiumTableHelpers.tableRowToChatMessage(row);
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ export class TMRRencontres {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async $chatRolledRencontre(row, rencontre, tmr) {
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.html',
|
||||
const flavorContent = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-compendium-table-roll-rencontre.hbs',
|
||||
{
|
||||
roll: row.roll,
|
||||
rencontre,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { TMRUtility } from "../tmr-utility.js";
|
||||
import { PixiTMR } from "./pixi-tmr.js";
|
||||
|
||||
@@ -12,10 +12,10 @@ export class Draconique {
|
||||
static init() {
|
||||
}
|
||||
|
||||
static isCaseTMR(item) { return item.type == TYPES.casetmr; }
|
||||
static isCaseTMR(item) { return item.type == ITEM_TYPES.casetmr; }
|
||||
static isQueueDragon(item) { return item.isQueueDragon(); }
|
||||
static isSouffleDragon(item) { return item.type == TYPES.souffle; }
|
||||
static isTeteDragon(item) { return item.type == TYPES.tete; }
|
||||
static isSouffleDragon(item) { return item.type == ITEM_TYPES.souffle; }
|
||||
static isTeteDragon(item) { return item.type == ITEM_TYPES.tete; }
|
||||
static isQueueSouffle(item) { return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item); }
|
||||
|
||||
static register(draconique, code = undefined) {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { Periple } from "./periple.js";
|
||||
import { UrgenceDraconique } from "./urgence-draconique.js";
|
||||
import { Grammar } from "../grammar.js";
|
||||
import { AugmentationSeuil } from "./augmentation-seuil.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
|
||||
export class EffetsDraconiques {
|
||||
static carteTmr = new CarteTmr();
|
||||
@@ -122,11 +122,11 @@ export class EffetsDraconiques {
|
||||
}
|
||||
|
||||
static tetesDragon(actor, name) {
|
||||
return actor.itemTypes[TYPES.tete].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
return actor.itemTypes[ITEM_TYPES.tete].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static soufflesDragon(actor, name) {
|
||||
return actor.itemTypes[TYPES.souffle].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
return actor.itemTypes[ITEM_TYPES.souffle].filter(it => Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static queuesDragon(actor, name) {
|
||||
@@ -134,7 +134,7 @@ export class EffetsDraconiques {
|
||||
}
|
||||
|
||||
static queuesSoufflesDragon(actor, name) {
|
||||
return actor.filterItems(it => [TYPES.queue, TYPES.ombre, TYPES.souffle].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
return actor.filterItems(it => [ITEM_TYPES.queue, ITEM_TYPES.ombre, ITEM_TYPES.souffle].includes(it.type) && Grammar.includesLowerCaseNoAccent(it.name, name));
|
||||
}
|
||||
|
||||
static countAugmentationSeuil(actor) {
|
||||
|
||||
@@ -30,7 +30,7 @@ export class EffetsRencontre {
|
||||
static $reve_plus = async (actor, reve) => {
|
||||
if (!ReglesOptionnelles.isUsing("recuperation-reve") && reve < 0) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(actor.name),
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
content: `Pas de récupération de rêve (${reve} points ignorés)`
|
||||
});
|
||||
return
|
||||
@@ -107,18 +107,18 @@ export class EffetsRencontre {
|
||||
}
|
||||
|
||||
static rdd_part_tete = async (dialog, context) => {
|
||||
mergeObject(context, {
|
||||
foundry.utils.mergeObject(context, {
|
||||
tete: context.rolled.isPart,
|
||||
poesie: await Poetique.getExtrait()
|
||||
})
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(context.actor.name),
|
||||
whisper: ChatUtility.getOwners(context.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
|
||||
});
|
||||
}
|
||||
|
||||
static rdd_echec_queue = async (dialog, context) => {
|
||||
mergeObject(context, {
|
||||
foundry.utils.mergeObject(context, {
|
||||
queues: [await context.actor.ajouterQueue()],
|
||||
poesie: await Poetique.getExtrait()
|
||||
})
|
||||
@@ -127,7 +127,7 @@ export class EffetsRencontre {
|
||||
}
|
||||
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.name),
|
||||
whisper: ChatUtility.getOwners(context.actor),
|
||||
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-reve-de-dragon.html`, context)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { SYSTEM_RDD } from "../constants.js";
|
||||
import { Misc } from "../misc.js";
|
||||
import { TMRConstants, tmrTokenZIndex } from "../tmr-constants.js";
|
||||
import { TMRUtility } from "../tmr-utility.js";
|
||||
@@ -14,12 +13,12 @@ export class PixiTMR {
|
||||
static register(name, img) {
|
||||
PixiTMR.textures[name] = img;
|
||||
}
|
||||
|
||||
static async init() {
|
||||
await Promise.all(
|
||||
Object.values(PixiTMR.textures)
|
||||
.filter(img => img != undefined)
|
||||
.map(async img => PIXI.Sprite.from(await PIXI.Assets.load(img)))
|
||||
)
|
||||
.filter(img => img != undefined && !PIXI.utils.TextureCache[img])
|
||||
.map(async img => PIXI.Sprite.from(await PIXI.Assets.load(img))))
|
||||
}
|
||||
|
||||
constructor(tmrDialog, displaySize) {
|
||||
@@ -106,8 +105,9 @@ export class PixiTMR {
|
||||
|
||||
sprite(code, options = {}) {
|
||||
let img = PixiTMR.getImgFromCode(code)
|
||||
const texture = PIXI.utils.TextureCache[img]
|
||||
let texture = PIXI.utils.TextureCache[img]
|
||||
if (!texture) {
|
||||
// TODO: charger la texture
|
||||
console.error("Texture manquante", code, PIXI.utils.TextureCache)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ export class PresentCites extends Draconique {
|
||||
let existants = actor.items.filter(it => this.isCase(it)).map(it => it.system.coord);
|
||||
if (existants.length > 0) {
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
content: "Vous avez encore des présents dans des cités, vous devrez tirer une autre tête pour remplacer celle ci!"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ export class Rencontre extends Draconique {
|
||||
return pixiTMR.sprite(this.code(), {
|
||||
zIndex: tmrTokenZIndex.rencontre,
|
||||
decallage: pixiTMR.sizes.decallage(0, 0),
|
||||
taille: () => pixiTMR.sizes.twoThird,
|
||||
taille: () => pixiTMR.sizes.full,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { RdDRollTables } from "../rdd-rolltables.js";
|
||||
import { TMRUtility } from "../tmr-utility.js";
|
||||
import { tmrTokenZIndex } from "../tmr-constants.js";
|
||||
import { Draconique } from "./draconique.js";
|
||||
import { TYPES } from "../item.js";
|
||||
import { ITEM_TYPES } from "../item.js";
|
||||
import { TMRAnimations } from "./animation.js";
|
||||
|
||||
export class UrgenceDraconique extends Draconique {
|
||||
@@ -14,12 +14,12 @@ export class UrgenceDraconique extends Draconique {
|
||||
match(item) { return Draconique.isQueueDragon(item) && Grammar.toLowerCaseNoAccent(item.name).includes('urgence draconique'); }
|
||||
manualMessage() { return false }
|
||||
async onActorCreateOwned(actor, queue) {
|
||||
const coordSortsReserve = actor.itemTypes[TYPES.sortreserve].map(it => it.system.coord) ?? [];
|
||||
const coordSortsReserve = actor.itemTypes[ITEM_TYPES.sortreserve].map(it => it.system.coord) ?? [];
|
||||
if (coordSortsReserve.length == 0) {
|
||||
// La queue se transforme en idée fixe
|
||||
const ideeFixe = await RdDRollTables.getIdeeFixe();
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
|
||||
whisper: ChatUtility.getOwners(actor),
|
||||
content: `En l'absence de sorts en réserve, l'urgence draconique de ${actor.name} se transforme en ${ideeFixe.name}`
|
||||
});
|
||||
await actor.createEmbeddedDocuments('Item', [ideeFixe]);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { TYPES } from "../item.js"
|
||||
import { ITEM_TYPES } from "../item.js"
|
||||
import { RdDItemCompetence } from "../item-competence.js"
|
||||
import { ChatUtility } from "../chat-utility.js"
|
||||
import { Misc } from "../misc.js"
|
||||
|
||||
const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation']
|
||||
const TABLEAU_FATIGUE_MARCHE = [
|
||||
@@ -33,11 +34,10 @@ export class DialogFatigueVoyage extends Dialog {
|
||||
return
|
||||
}
|
||||
if (!DialogFatigueVoyage.dialog) {
|
||||
const playerActors = game.actors.filter(actor => actor.hasPlayerOwner && actor.isPersonnage())
|
||||
.map(actor => DialogFatigueVoyage.prepareActor(actor))
|
||||
const parameters = {
|
||||
tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE,
|
||||
playerActors: playerActors,
|
||||
playerActors: game.actors.filter(actor => actor.isPersonnageJoueur())
|
||||
.map(actor => DialogFatigueVoyage.prepareActorParameters(actor)),
|
||||
nombreHeures: 1,
|
||||
}
|
||||
DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined)
|
||||
@@ -54,21 +54,37 @@ export class DialogFatigueVoyage extends Dialog {
|
||||
parameters.typeTerrain = ligneFatigueMarche
|
||||
parameters.vitesseDeplacement = rythme.vitesse
|
||||
parameters.fatigueHoraire = rythme.fatigue
|
||||
parameters.playerActors.forEach(voyageur =>
|
||||
DialogFatigueVoyage.selectSurvie(voyageur, parameters.typeTerrain.code)
|
||||
)
|
||||
}
|
||||
|
||||
static prepareActor(actor) {
|
||||
const competencesVoyage = {}
|
||||
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie =>
|
||||
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[TYPES.competence], codeSurvie, { onMessage: () => { } })
|
||||
)
|
||||
return {
|
||||
static prepareActorParameters(actor) {
|
||||
const actorParameters = {
|
||||
id: actor.id,
|
||||
actor: actor,
|
||||
selected: true,
|
||||
ajustementFatigue: 0,
|
||||
competencesVoyage: competencesVoyage
|
||||
survies: {}
|
||||
}
|
||||
const competencesVoyage = {}
|
||||
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => {
|
||||
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[ITEM_TYPES.competence], codeSurvie, { onMessage: () => { } })
|
||||
})
|
||||
TABLEAU_FATIGUE_MARCHE.forEach(terrain => {
|
||||
actorParameters.survies[terrain.code] = Misc.join(
|
||||
terrain.survies.map(survie => {
|
||||
const niveau = competencesVoyage[survie]?.system.niveau
|
||||
return `${survie}: ${niveau}`
|
||||
}),
|
||||
', ')
|
||||
})
|
||||
return actorParameters
|
||||
}
|
||||
|
||||
static selectSurvie(actorParameters, code) {
|
||||
actorParameters.survieCourante = actorParameters.survies[code]
|
||||
}
|
||||
|
||||
constructor(html, parameters) {
|
||||
const options = {
|
||||
@@ -98,6 +114,7 @@ export class DialogFatigueVoyage extends Dialog {
|
||||
this.html.find('select[name="code-terrain"]').change(event => this.changeParameters())
|
||||
this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters())
|
||||
this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters())
|
||||
this.html.find('.list-item input[name="ajustement-fatigue"]').change(event => this.changeParameters())
|
||||
this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue())
|
||||
}
|
||||
|
||||
@@ -119,6 +136,10 @@ export class DialogFatigueVoyage extends Dialog {
|
||||
selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme))
|
||||
})
|
||||
selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change()
|
||||
|
||||
Promise.all(this.getActorRows()
|
||||
.map(async row => row.find('label.voyage-liste-survies').text(this.$extractActorParameters(row).survieCourante)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,44 +154,61 @@ export class DialogFatigueVoyage extends Dialog {
|
||||
}
|
||||
|
||||
async setFatigue() {
|
||||
this.html.find('input[name="base-fatigue"]').val(this.parameters.nombreHeures * this.parameters.fatigueHoraire)
|
||||
const baseFatigue = this.parameters.nombreHeures * this.parameters.fatigueHoraire
|
||||
this.html.find('input[name="base-fatigue"]').val(baseFatigue)
|
||||
this.updateActorTotalFatigue(baseFatigue)
|
||||
}
|
||||
|
||||
async updateActorTotalFatigue(baseFatigue) {
|
||||
Promise.all(this.getActorRows()
|
||||
.map(async row => {
|
||||
const actor = this.$extractActorParameters(row)
|
||||
row.find('input[name="total-fatigue"]').val(actor.ajustement + baseFatigue)
|
||||
}))
|
||||
}
|
||||
|
||||
async appliquerFatigue() {
|
||||
const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0)
|
||||
const actors = jQuery.map(
|
||||
this.html.find('div.fatigue-actors-list li.list-item'),
|
||||
it => this.$extractActor(this.html.find(it))
|
||||
)
|
||||
actors.filter(it => it.selected)
|
||||
.forEach(async it => {
|
||||
this.getActorRows()
|
||||
.map(row => this.$extractActorParameters(row))
|
||||
.filter(it => it.selected)
|
||||
.forEach(async it => {
|
||||
const perteFatigue = fatigueBase + it.ajustement
|
||||
ChatMessage.create({
|
||||
whisper: ChatUtility.getWhisperRecipientsAndGMs(it.actor.name),
|
||||
whisper: ChatUtility.getOwners(it.actor),
|
||||
content: await renderTemplate(
|
||||
'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs', mergeObject(it,
|
||||
'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs',
|
||||
foundry.utils.mergeObject(it,
|
||||
{
|
||||
parameters: this.parameters,
|
||||
fatigueBase: fatigueBase,
|
||||
perteFatigue: perteFatigue,
|
||||
isVoyage: fatigueBase == this.parameters.nombreHeures * this.parameters.fatigueHoraire
|
||||
})
|
||||
}, { inplace: false })
|
||||
),
|
||||
})
|
||||
await it.actor.santeIncDec("fatigue", perteFatigue)
|
||||
})
|
||||
}
|
||||
|
||||
$extractActor(actorRow) {
|
||||
const actor = game.actors.get(actorRow.data('actor-id'))
|
||||
getActorRows() {
|
||||
return jQuery.map(
|
||||
this.html.find('div.fatigue-actors-list li.list-item'),
|
||||
it => this.html.find(it))
|
||||
}
|
||||
|
||||
|
||||
$extractActorParameters(actorRow) {
|
||||
const actorId = actorRow.data('actor-id')
|
||||
const actorParameters = this.parameters.playerActors.find(it => it.id == actorId)
|
||||
const actor = game.actors.get(actorId)
|
||||
if (!actor) {
|
||||
ui.notifications.warn(`Acteur ${it.actorId} introuvable`)
|
||||
return {}
|
||||
}
|
||||
return {
|
||||
actor: actor,
|
||||
ajustement: parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0),
|
||||
selected: actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
|
||||
}
|
||||
actorParameters.ajustement = parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0)
|
||||
actorParameters.selected = actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
|
||||
return actorParameters
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
{"_id":"MGvyXFQJpv6nNynl","name":"Masse lourde","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/masse_lourde.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.MGvyXFQJpv6nNynl"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":3,"quantite":1,"qualite":0,"cout":4,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":10,"categorie_parade":"","dommages":"3/4","penetration":0,"force":"12/11","competence":"Masse à 1 main","lancer":"","tir":"","portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"magique":false,"ecaille_efficacite":0,"resistance_magique":0,"rapide":false,"deuxmains":true,"unemain":true,"initpremierround":"masse"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"MQxgfYTEQEUhG116","name":"Épée bâtarde","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_batarde.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.MQxgfYTEQEUhG116"}},"system":{"description":"<p>Comme son nom l’indique, c’est une <em>bâtarde </em>de l'épée longue et de l'épée sorde, à la fois longue et large, pouvant s’utiliser à une ou deux mains.</p>","descriptionmj":"","equipe":false,"encombrement":3,"quantite":1,"qualite":0,"cout":30,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"resistance":14,"categorie_parade":"epees-lourdes","dommages":"4/5","penetration":0,"force":"13/12","competence":"Epée à 1 main","lancer":"","tir":"","portee_courte":0,"portee_moyenne":0,"portee_extreme":0,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":false,"deuxmains":true,"unemain":true,"initpremierround":"epeebatarde"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"Mbh2M8JS1Rf0vxEX","name":"Harpe","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/harpe.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.Mbh2M8JS1Rf0vxEX"}},"system":{"description":"","descriptionmj":"","encombrement":1,"quantite":1,"qualite":0,"cout":5,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rarissime","frequence":2},{"milieu":"Villes","rarete":"Rare","frequence":6}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"NCp2kdTKmJVdFuit","name":"Dague mêlée","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/dague.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sheetClass":"","sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NCp2kdTKmQGyAh1U"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":0.5,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Frequente","frequence":18},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":8,"categorie_parade":"dagues","dommages":"1","penetration":0,"force":"7","competence":"Dague","lancer":"Dague de jet","tir":"","portee_courte":3,"portee_moyenne":8,"portee_extreme":15,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":true,"deuxmains":false,"unemain":true,"initpremierround":"dague"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"NCp2kdTKmQGyAh1U","name":"Dague","type":"arme","img":"systems/foundryvtt-reve-de-dragon/icons/armes_armures/dague.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sheetClass":"","sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NCp2kdTKmQGyAh1U"}},"system":{"description":"","descriptionmj":"","equipe":false,"encombrement":0.5,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Frequente","frequence":18},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"resistance":8,"categorie_parade":"dagues","dommages":"1","penetration":0,"force":"7","competence":"Dague","lancer":"Dague de jet","tir":"","portee_courte":3,"portee_moyenne":8,"portee_extreme":15,"magique":false,"ecaille_efficacite":null,"resistance_magique":null,"rapide":true,"deuxmains":false,"unemain":true,"initpremierround":"dague"},"ownership":{"default":0,"Q4cUvqxCxMoTJXDL":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"NNLhxjFsoJVdFuit","name":"Bouteille de verre (1 litre)","type":"conteneur","img":"systems/foundryvtt-reve-de-dragon/icons/objets/bouteille_verre.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.NNLhxjFsoJVdFuit"}},"system":{"description":"","descriptionmj":"","encombrement":0.2,"quantite":1,"qualite":0,"cout":0.7,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"contenu":[],"capacite":0.5,"equipe":false},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
{"_id":"OXFFRZOqlhZDJas3","name":"Béret de velours","type":"objet","img":"systems/foundryvtt-reve-de-dragon/icons/objets/beret_velours.webp","effects":[],"folder":null,"sort":0,"flags":{"core":{"sourceId":"Compendium.foundryvtt-reve-de-dragon.equipement.OXFFRZOqlhZDJas3"}},"system":{"description":"","descriptionmj":"","encombrement":0.05,"quantite":1,"qualite":0,"cout":3,"milieu":"","environnement":[{"milieu":"Villages","rarete":"Rare","frequence":6},{"milieu":"Villes","rarete":"Frequente","frequence":18}],"equipe":false,"resistance":1},"ownership":{"default":0,"rYShh2P1DNavdoBD":3},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.15","coreVersion":"10.291","createdTime":1668808206023,"modifiedTime":1676074487966,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"}}
|
||||
|
||||
@@ -11,4 +11,3 @@
|
||||
{"name":"Thème astral","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/magic/nature/symbol-moon-stars-white.webp","command":"game.system.rdd.AppAstrologie.create()","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.oA0HPFeFK6YMspAX"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"10.6.19","coreVersion":"10.291","createdTime":1678127868791,"modifiedTime":1678237392810,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"koqhiDJSGP4gQ4vf"}
|
||||
{"name":"Jet d'éthylisme","type":"script","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"icons/consumables/drinks/alcohol-beer-stein-wooden-metal-brown.webp","command":"const selected = game.system.rdd.RdDUtility.getSelectedActor();\nif (selected) {\n selected.jetEthylisme();\n}\nelse {\n ui.notifications.info('Pas de personnage sélectionné');\n}","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.XHNbjnGKXaCiCadq"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1671220038331,"modifiedTime":1671233646086,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"mvub1dRHNFmWjRr7"}
|
||||
{"name":"Tirer le tarot","type":"chat","scope":"global","author":"Hp9ImM4o9YRTSdfu","img":"systems/foundryvtt-reve-de-dragon/icons/tarots/dos-tarot.webp","command":"/tirer tarot","ownership":{"default":0,"Hp9ImM4o9YRTSdfu":3},"flags":{"core":{"sourceId":"Macro.HBZSKR9OHCQbLcTC"}},"_stats":{"systemId":"foundryvtt-reve-de-dragon","systemVersion":"11.1.0","coreVersion":"10.291","createdTime":1669469547231,"modifiedTime":1671237401618,"lastModifiedBy":"Hp9ImM4o9YRTSdfu"},"folder":null,"sort":0,"_id":"vTfJTFYYiRu8X5LM"}
|
||||
{"name": "Mon personnage","type": "script","author": "Hp9ImM4o9YRTSdfu","img": "systems/foundryvtt-reve-de-dragon/icons/voyageurs/token_hr_dilettante.webp","scope": "global","command": "if (game.user.isGM) {\n ui.notifications.warn(\"En tant que gardien, vous n'avez pas de personnage attitré\")\n return\n}\nconst actor = game.users.get(game.userId)?.character\nif (!actor) {\n ui.notifications.warn(\"Vous n'avez pas de personnage attitré\")\n return\n}\nactor.sheet.render(true)","folder": null,"flags": {"core": {},"exportSource": {"world": "graine","system": "foundryvtt-reve-de-dragon","coreVersion": "11.313","systemVersion": "11.1.1"}},"_stats": {"systemId": "foundryvtt-reve-de-dragon","systemVersion": "11.1.1","coreVersion": "11.313","createdTime": 1699477824379,"modifiedTime": 1699485023429,"lastModifiedBy": "Hp9ImM4o9YRTSdfu"}}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user