Compare commits

...

57 Commits

Author SHA1 Message Date
3aa8c0f0af Fix weapon in the HUD 2024-09-01 20:39:25 +02:00
8d9f09c18c Fix warnings 2024-09-01 20:22:52 +02:00
9d654246c2 Merge pull request '12.0.7 - La propriété d'Astrobazzarh' (#709) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#709
2024-09-01 20:21:04 +02:00
111fac2b2d Amélioration dialogue voyage
- le changement de terrain change l'affichage de compétences
- le total de fatigue est affiché (ajustement + base)
2024-09-01 20:13:09 +02:00
3e99265125 Version 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
2024-08-31 00:59:26 +02:00
28878b74fc Fix: demandes au défenseur
Les demandes de résistance pour les possessions sont envoyées au
défenseur

Les demlandes de défense contre une empoignade dont envoyées au
 défenseur
2024-08-31 00:58:58 +02:00
ba8276ef37 Possibilité d'accorder un personnage
Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
d'une entité incarnée permet d'accorder le personnage
2024-08-31 00:21:24 +02:00
b9e8c24461 Pas d'expérience si le MJ n'est pas connecté
Pour éviter les jets de dés abusifs quand le MJ n'est pas là,
les réussites particulières ne rapportent plus d'expérience
lorsque le MJ n'est pas connecté
2024-08-30 23:56:20 +02:00
8754ea9f5f Fix hook sur creation
Correction des Hooks qui font des calculs à la création d'un item.

- document instanceof Document est false pour un Actor
- le tri des users ne marche pas sur foundry 12
- mise à jour des blessures lors des soins

Correction de la détermination du MJ connecté permettant de nouveau:
- jets de dés quand aucun MJ n'est connecté
- affichage de l'horloge
2024-08-30 23:54:06 +02:00
f56ddb4a1b Merge pull request 'Version 12.0.6 - Le bazar d'Astrobazzarh' (#708) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#708
2024-08-01 07:19:12 +02:00
e80dbc7332 Version 12.0.6 2024-08-01 01:19:54 +02:00
4c82d85e6a Fix: visibilité des tirages dans les compendium
Les macros /tirer affichaient le résultat pour tous les joueurs
2024-08-01 01:19:07 +02:00
538058ecc6 Fix: cas d'un objet est un conteneur fantôme
Lors d'une partie, la feuille d'un personnage a été bloquée.
Après debug, il semble que l'objet a eu le flag estContenu=true
sans être contenu.

En regardant le json, il semble que des Item "objet" se sont retrouvés
avec un champ "contenu", et que l'arbre des contenant a été cassé.

Du coup: l'ajout dans un conteneur est maintenant "sécurisé" pour
éviter l'accident. si on essaie d'ajouter dans un Item non conteneur,
on positionne estContenu à false, et on corrige si possible le "contenu"
de la cible, qui ne devrait pas être là.
2024-08-01 01:17:36 +02:00
70e42ea631 Merge pull request 'Restaurer la compatibilité v11' (#707) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#707
2024-07-15 17:17:29 +02:00
15525ef8cc Restaurer la compatibilité v11 2024-07-10 23:17:27 +02:00
5a4ef6da7e Merge pull request '12.0.5 - Les mauvais jours d'Astrobazzarh' (#706) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#706
2024-07-08 22:14:15 +02:00
ab698b2124 Version 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'
2024-07-04 21:30:19 +02:00
4cc6e86d79 Fix: Failed to execute 'getComputedStyle'
Dans certains cas (ouverture de fenêtre de lancer de sort),
le bringToTop était appelé alors que la fenêtre n'était pas prête
2024-07-04 21:23:29 +02:00
8f3d56a830 Une seule fenêtres de lancer de sort à la fois
On ne peut plus ouvrir de fenêtre de lancer de sort quand une
fenêtre est déjà ouverte
2024-07-04 21:23:29 +02:00
8561e3f8bc Securité: limiter les cleanupConteneurs
Dans certains cas mal identifiés, on pouvait avoir un problème de droits
sur l'acteur, quand plusieurs joueurs accédaient en même temps à
l'équipement porté par une mule, par exemple
2024-07-04 21:23:29 +02:00
f207cb7325 Fix: Fenêtre d'édition du calendrier
Ajout d'un helper Handlebars pour accéder à l'objet RDD_CONFIG
sans avoir besoin de l'ajouter dans les données pour rendu du template
2024-07-04 21:23:28 +02:00
b9e911a588 Merge pull request '## 12.0.4 - La plaie d'Astrobazzarh' (#705) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#705
2024-07-03 21:47:11 +02:00
92e9be8b02 Version 12.0.4 2024-07-03 02:35:23 +02:00
50a86e751d Fix: warnings deprecated v12 2024-07-02 23:37:50 +02:00
1725d4c17b Fix: impossible de faire l'encaissement
Echec lors des test de permission d'utilisateur
2024-07-02 23:36:52 +02:00
3e33053ed4 Merge pull request '12.0.3 - L'hémorragie d'Astrobazzarh' (#704) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#704
2024-07-01 22:21:26 +02:00
baa3729568 Version 12.0.3 2024-06-29 00:26:12 +02:00
99f29cb95b Fix confirmation de suppression
Lors de la suppression, la demande de confirmation était toujours
faite, même si on indiquait de ne plus demander
2024-06-29 00:12:31 +02:00
7d19860f5f Fix ouverture des Items avec rareté
La sélection des raretés ne fonctionnait plus, la liste des
raretés n'étant pas disponible configuration n'étant
pas disponible dans les données des Items.
2024-06-29 00:12:31 +02:00
40987149cc Fix Ouvertures impossibles
Le contexte des constructeurs est partagé entre Actor et Items,
il faut donc enlever l'indicateur qui sert au choix de la bonne
classe dérivée, sans quoi certains objets/acteurs peuvent être
créés en utilisant le type de base, ce qui empêche d'ouvrir
certains items d'acteurs après avoir redémarré le monde

Par exemple, après ajout d'une blessure et redémarrage, il était
impossible de réouvrir la feuille du personnage blessé.
2024-06-29 00:12:30 +02:00
49d7c4f71d Merge pull request '12.0.2 - Les pluies d'Astrobazzarh' (#703) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#703
2024-06-14 08:04:23 +02:00
23582984cf Version 12.0.2 - Les pluies d'Astrobazzarh 2024-06-14 00:25:10 +02:00
638459049d Fix: dé draconique et rencontre
Le dé draconique donnait toujours un total de 0
2024-06-14 00:03:06 +02:00
366ca981ca Fix message de log de journaux 2024-06-13 22:46:35 +02:00
c0e54c2369 Fix warning sur test de version 2024-06-13 22:06:23 +02:00
f95f5b2b81 Fix calendrier in v12 2024-06-13 22:00:09 +02:00
d30226cb33 Fix game.users for v12 2024-06-13 21:52:48 +02:00
5cf7dda76c Fix game.users for v12 2024-06-13 21:51:31 +02:00
9bc2593b8c Sync version to v12 2024-06-12 08:21:03 +02:00
efd02b40a9 Merge pull request 'Version 11.2.22 - Le futur d'Akarlikarlikar' (#702) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#702
2024-06-12 08:16:17 +02:00
feb3116c47 Version 11.2.22 2024-06-12 01:02:03 +02:00
91a870ad91 Merge pull request 'Fix User ... lacks permission to update' (#701) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#701
2024-06-11 07:52:59 +02:00
2bbf606f30 Fix User ... lacks permission to update
Correction de l'erreur qui était affichée chez les joueurs lors de
hooks utilisés pour effectuer des modifications sur des
documents:

- ChatMessage, ajout de flags pour l'heure
- Item au sein d'un Actor pour mettre à jour certains éléments
2024-06-11 02:49:18 +02:00
a385b98126 Various fixes for v12 2024-06-07 11:12:00 +02:00
8775df5285 Merge pull request 'Corrections v12' (#700) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#700
2024-06-01 09:11:18 +02:00
a103239288 Passe de vérification mergeObject
Quand mergeObject est utilisé pour retourner une valeur, faire très
attention à ne pas passer un Item/Actor, ou une de ses sous parties
en premier paramètre sans préciser l'option { inplace: false }

Sinon, le premier paramètre subit une mutation!
2024-06-01 01:53:14 +02:00
0b1c5d0a3d Fix again achatVente
- remplacement des données/JSON dans le html par des Flags sur
  le ChatMessage
- extraction de la gestion des infos de ventes pour rassembler la
  génération du ChatMessage
- on ne perd plus la quantité ou le vendeur
- attention au mergeObject: il modifie le premier parametre, ce
  qui modifiait parfois l'acteur (!!!) et toujours la quantité de
  l'objet du vendeur lors de la création de l'objet de l'acheteur!
2024-06-01 01:50:48 +02:00
e19577eab2 Fix for v12 2024-05-31 21:48:19 +02:00
c3b502ff6c Fix V12 Fenêtre de recherche 2024-05-31 21:42:09 +02:00
db2ca2453e Foundry v11/v12 support 2024-05-27 08:53:57 +02:00
915283a674 Merge pull request '11.2.21 - Le questionnement d'Akarlikarlikar' (#699) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: public/foundryvtt-reve-de-dragon#699
2024-05-27 07:17:09 +02:00
621bb4ebc3 Version 11.2.21 2024-05-27 00:57:12 +02:00
26e805cf46 Ajout de la date/heure aux messages 2024-05-27 00:55:18 +02:00
657566fb11 Les effets s'appliquent aux créatures 2024-05-26 22:43:07 +02:00
26e8853a94 Passage v12 2024-05-26 22:16:42 +02:00
4f69d3cf78 Expérience sur rêve et chance actuels
L'expérience en caractéristique sur les jets de
2024-05-26 22:15:10 +02:00
dfe4b47452 Message de confirmation rencontre TMR
Quand un haut-rêvant monte dans les TMR avec une rencontre en attente,
un message est affiché pour demander confirmation
2024-05-26 22:13:47 +02:00
70 changed files with 704 additions and 485 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@@ -1,11 +1,75 @@
# 11.2
## 11.2.20 - Le soulagement d'Akarlikarlikar
# 12.0
## 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
- L'option 'ajout de la difficulté d'attaque à l'encaissement est affichée comme un modificateur d'encaissement
- Les options d'encaissement alternative fonctionnent avec la validation du gardien
## 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 maintenant lisibles
- 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

4
icons/heures/.directory Normal file
View 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

View 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
})
}
}

View File

@@ -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);

View File

@@ -1,29 +1,30 @@
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,
vendeurId: item.actor?.id,
vendeurId: item.actor.id,
prixOrigine: item.calculerPrixCommercant(),
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,7 +52,15 @@ 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) {
@@ -61,7 +69,7 @@ export class DialogItemVente extends Dialog {
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)
}
}

View File

@@ -16,7 +16,6 @@ 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";
/* -------------------------------------------- */
@@ -33,22 +32,20 @@ export class RdDActorSheet extends RdDBaseActorSangSheet {
width: 550,
showCompNiveauBase: false,
vueArchetype: false,
});
}, { inplace: false });
}
/* -------------------------------------------- */
async getData() {
let formData = await super.getData();
foundry.utils.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 }),
});
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,
@@ -213,7 +210,7 @@ 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())
}

View File

@@ -902,7 +902,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;
@@ -991,25 +991,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 == TYPES.casetmr).filter(it => EffetsDraconiques.isInnaccessible(it)).map(it => it.system.coord)
}
/* -------------------------------------------- */
getTMRRencontres() {
return this.itemTypes['rencontre'];
getRencontresTMR() {
return this.itemTypes[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[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[TYPES.rencontre].find(this.filterRencontreTMRDemiReve())
}
filterRencontreTMRDemiReve() {
const position = this.getDemiReve()
return it => it.system.coord == position
}
/* -------------------------------------------- */
async addTMRRencontre(currentRencontre) {
const toCreate = currentRencontre.toObject();
@@ -1140,7 +1146,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);
@@ -1542,6 +1548,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
if (!Misc.firstConnectedGM()){
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) {
@@ -2337,7 +2346,7 @@ export class RdDActor extends RdDBaseActorSang {
async _xpCaracDerivee(xpData) {
const caracs = RdDActor._getComposantsCaracDerivee(xpData.caracName)
.map(c => foundry.utils.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;
@@ -2353,6 +2362,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']
@@ -2423,22 +2434,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) {
@@ -2610,13 +2628,13 @@ 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 = foundry.utils.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);
@@ -2967,9 +2985,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) {

View File

@@ -180,7 +180,7 @@ export class RdDBaseActorReve extends RdDBaseActor {
}
/* -------------------------------------------- */
isEffectAllowed(effectId) { return true }
isEffectAllowed(effectId) { return false }
getEffects(filter = e => true) {
return this.getEmbeddedCollection("ActiveEffect").filter(filter);
@@ -286,12 +286,12 @@ export class RdDBaseActorReve extends RdDBaseActor {
getCarac() {
// TODO: le niveau d'une entité de cauchemar devrait être exclu...
const carac = foundry.utils.mergeObject(foundry.utils.duplicate(this.system.carac),
return foundry.utils.mergeObject(this.system.carac,
{
'reve-actuel': this.getCaracReveActuel(),
'chance-actuelle': this.getCaracChanceActuelle()
});
return carac;
},
{ inplace: false })
}
/* -------------------------------------------- */
@@ -508,8 +508,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");
}
}

View File

@@ -269,6 +269,8 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
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 }

View File

@@ -20,7 +20,7 @@ export class RdDBaseActorSheet extends ActorSheet {
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);

View File

@@ -1,3 +1,4 @@
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";
@@ -8,7 +9,6 @@ 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,10 +32,10 @@ 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) {
@@ -82,10 +82,6 @@ export class RdDBaseActor extends Actor {
static extractActorMin = (actor) => { return { id: actor?.id, type: actor?.type, name: actor?.name, img: actor?.img }; };
static getParentActor(document) {
return document?.parent instanceof Actor ? document.parent : undefined
}
/**
* Cette methode surcharge Actor.create() pour ajouter si besoin des Items par défaut:
* compétences et monnaies.
@@ -125,6 +121,7 @@ export class RdDBaseActor extends Actor {
return new ActorConstructor(docData, context);
}
}
context.rdd = undefined
super(docData, context);
}
@@ -235,11 +232,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)
}
}
}
@@ -361,12 +360,9 @@ 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");
}
@@ -380,24 +376,26 @@ export class RdDBaseActor extends Actor {
});
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);
}
}
@@ -410,31 +408,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 }]);
}
}
@@ -446,7 +441,7 @@ export class RdDBaseActor extends Actor {
type: item.type,
img: item.img,
name: item.name,
system: foundry.utils.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);
@@ -562,15 +557,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 })
}
}
@@ -588,8 +583,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) {
@@ -624,15 +624,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;
}
/* -------------------------------------------- */

View File

@@ -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";
@@ -15,7 +15,7 @@ export class RdDCommerceSheet extends RdDBaseActorSheet {
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) {

View File

@@ -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
}

View File

@@ -12,7 +12,7 @@ export class RdDCreatureSheet extends RdDBaseActorSangSheet {
return foundry.utils.mergeObject(RdDBaseActorSangSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-creature-sheet.html",
width: 640, height: 720
});
}, { inplace: false })
}
/* -------------------------------------------- */

View File

@@ -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 = foundry.utils.duplicate(this.system.sante.resonnance);
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé
return;
}
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
}

View File

@@ -9,7 +9,7 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
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 });

View File

@@ -67,7 +67,7 @@ export class RdDEntite extends RdDBaseActorReve {
if (this.isNonIncarnee()) {
return
}
await RdDEncaisser.encaisser(this)
await RdDEncaisser.encaisser(this)
}
isEffectAllowed(effectId) {
@@ -91,20 +91,16 @@ export class RdDEntite extends RdDBaseActorReve {
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attacker) {
async setEntiteReveAccordee(actor) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = foundry.utils.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)
}
}
}

View File

@@ -9,7 +9,7 @@ export class RdDActorVehiculeSheet extends RdDBaseActorSheet {
return foundry.utils.mergeObject(RdDBaseActorSheet.defaultOptions, {
template: "systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html",
width: 640, height: 720,
});
}, { inplace: false })
}
/* -------------------------------------------- */

View File

@@ -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";
/**
@@ -148,14 +149,13 @@ export class ChatUtility {
}
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 +163,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());
}
}
}

View File

@@ -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);

View File

@@ -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"}
]
}

View File

@@ -199,7 +199,7 @@ export class RdDItemCompetence extends Item {
if (idOrName == undefined || idOrName == "") {
return RdDItemCompetence.sansCompetence();
}
options = foundry.utils.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);
}

View File

@@ -33,8 +33,7 @@ export class RdDItemCompetenceCreature extends Item {
if (categorieAttaque != undefined) {
// si c'est un Item compétence: cloner pour ne pas modifier la compétence
let arme = item.clone();
foundry.utils.mergeObject(arme,
{
return foundry.utils.mergeObject(arme, {
action: item.isCompetencePossession() ? 'possession' : 'attaque',
system: {
competence: arme.name,
@@ -48,8 +47,7 @@ export class RdDItemCompetenceCreature extends Item {
force: 0,
rapide: true,
}
});
return arme;
}, { inplace: false });
}
return undefined;
}

View File

@@ -44,7 +44,7 @@ export class RdDItemSheet extends ItemSheet {
template: RdDItemSheet.defaultTemplate(RdDItemSheet.ITEM_TYPE),
width: 550,
height: 550
});
}, { inplace: false });
}
/* -------------------------------------------- */
@@ -98,7 +98,7 @@ 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) {
formData.isparade = RdDItemCompetenceCreature.isParade(this.item)
@@ -108,8 +108,8 @@ export class RdDItemSheet extends ItemSheet {
const competences = await SystemCompendiums.getCompetences('personnage');
formData.categories = this.item.getCategories()
if (this.item.type == 'tache' || this.item.type == 'livre' || this.item.type == 'meditation' || this.item.type == 'oeuvre') {
formData.caracList = foundry.utils.duplicate(game.system.model.Actor.personnage.carac)
formData.caracList["reve-actuel"] = foundry.utils.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') {

View File

@@ -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";
@@ -177,7 +177,7 @@ export class RdDItem extends Item {
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,6 +189,7 @@ export class RdDItem extends Item {
if (!docData.img) {
docData.img = RdDItem.getDefaultImg(docData.type);
}
context.rdd = undefined
super(docData, context);
}
@@ -233,7 +234,7 @@ 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" }
@@ -538,7 +539,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 +622,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 })
}
/* -------------------------------------------- */

View File

@@ -39,7 +39,7 @@ export class RdDItemBlessure extends RdDItem {
ui.notifications.warn(`Pas de tâche de soins pour une blessure ${gravite}`)
return undefined;
}
return foundry.utils.mergeObject(foundry.utils.duplicate(BASE_TACHE_SOIN_BLESSURE), tache)
return foundry.utils.mergeObject(BASE_TACHE_SOIN_BLESSURE, tache, { inplace: false })
}
static async applyFullBlessure(actor, gravite) {
@@ -48,7 +48,7 @@ export class RdDItemBlessure extends RdDItem {
let lostEndurance = 0
let lostVie = 0
if (definition.endurance) {
lostEndurance = new Roll(definition.endurance).roll({async: false}).total;
lostEndurance = await new Roll(definition.endurance).roll().total;
actor.santeIncDec("endurance", -Number(lostEndurance));
}
if (definition.vie) {
@@ -106,12 +106,12 @@ export class RdDItemBlessure extends RdDItem {
}
async setSoinsBlessure(systemUpdate = {}) {
systemUpdate = foundry.utils.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 }) {

View File

@@ -10,7 +10,7 @@ export class RdDItemInventaireSheet extends RdDItemSheet {
static get 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 foundry.utils.mergeObject(formData, {
foundry.utils.mergeObject(formData, {
milieux: await game.system.rdd.environnement.autresMilieux(this.item)
});
})
return formData
}
activateListeners(html) {

View File

@@ -8,7 +8,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "carac" }]
});
}, { inplace: false })
}
/* -------------------------------------------- */
@@ -35,7 +35,7 @@ export class RdDRencontreItemSheet extends RdDItemSheet {
select: RdDRencontre.mapEffets(this.item.system.echec.effets)
}
}
});
})
return formData;
}

View File

@@ -567,9 +567,9 @@ export class Migrations {
if (currentVersion.startsWith("v")) {
currentVersion = currentVersion.substring(1)
}
if (isNewerVersion(game.system.version, currentVersion)) {
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) => {

View File

@@ -166,15 +166,47 @@ 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.isUniqueConnectedGM() || (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.isUniqueConnectedGM();
}
/**

View File

@@ -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);
}
}
}

View File

@@ -110,6 +110,7 @@ export class RdDCombatManager extends Combat {
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;
//console.log("RollInitiative", competence, carac, niveau, bonusEcaille);
rollFormula = RdDCombatManager.formuleInitiative(2, carac, niveau, bonusEcaille);
} else {
ui.notifications.warn(`Votre arme ${armeCombat.name} n'a pas de compétence renseignée`);
@@ -119,7 +120,7 @@ export class RdDCombatManager extends Combat {
//console.log("Combatat", c);
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);
@@ -128,21 +129,17 @@ export class RdDCombatManager extends Combat {
// Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
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,
},
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.initInfo})<br>`,
},
messageOptions);
roll.toMessage(messageData, { rollMode, create: true });
RdDCombatManager.processPremierRoundInit();
@@ -791,7 +788,7 @@ export class RdDCombat {
/* -------------------------------------------- */
_prepareAttaque(competence, arme) {
let rollData = {
passeArme: randomID(16),
passeArme: foundry.utils.randomID(16),
mortalite: arme?.system.mortalite,
competence: competence,
surprise: this.attacker.getSurprise(true),

View File

@@ -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 = foundry.utils.mergeObject(RdDConfirm._createButtonActionSave(options), buttons);
}
if (autresActions) {
buttons = foundry.utils.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() {

View File

@@ -36,8 +36,8 @@ export class DeTMR extends Die {
super(termData);
}
async evaluate() {
super.evaluate();
async evaluate(options) {
await super.evaluate(options);
this.explode("x=8");
return this;
}
@@ -73,8 +73,8 @@ export class DeDraconique extends Die {
super(termData);
}
async evaluate() {
super.evaluate();
async evaluate(options) {
await super.evaluate(options);
this.explode("x=7");
return this;
}
@@ -138,7 +138,7 @@ export class RdDDice {
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;
}
@@ -216,7 +216,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;
}

View File

@@ -248,7 +248,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);
}
@@ -427,7 +427,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

View File

@@ -1,4 +1,4 @@
import { SYSTEM_RDD, SYSTEM_SOCKET_ID } from "./constants.js";
import { SYSTEM_RDD, SYSTEM_SOCKET_ID, RDD_CONFIG } from "./constants.js";
import { Migrations } from './migrations.js';
import { RdDUtility } from "./rdd-utility.js";
@@ -71,15 +71,16 @@ import { RdDTMRDialog } from "./rdd-tmr-dialog.js";
* Software License: GNU GPLv3
*/
export class SystemReveDeDragon {
static start() {
const system = new SystemReveDeDragon()
Hooks.once('init', async () => await system.onInit())
Hooks.once('diceSoNiceReady', (dice3d) => RdDDice.diceSoNiceReady(dice3d))
Hooks.once('ready', () => system.onReady())
}
constructor() {
this.config = RDD_CONFIG;
this.RdDUtility = RdDUtility;
this.RdDHotbar = RdDHotbar;
this.itemClasses = {
@@ -108,7 +109,7 @@ export class SystemReveDeDragon {
/* -------------------------------------------- */
async onInit() {
game.system.rdd = this;
this.AppAstrologie = AppAstrologie;
this.AppAstrologie = AppAstrologie;
console.log(`Initializing Reve de Dragon System`);

View File

@@ -56,7 +56,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 +67,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';

View File

@@ -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

View File

@@ -97,7 +97,7 @@ export class RdDResolutionTable {
}
static actorChatName(actor) {
return actor?.userName ?? game.user.name;
return actor?.name ?? game.user.name;
}
/* -------------------------------------------- */

View File

@@ -129,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')));
@@ -142,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()));
}
@@ -164,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;
}
@@ -212,7 +221,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
loadRencontres() {
this.rencontresExistantes = this.actor.getTMRRencontres();
this.rencontresExistantes = this.actor.getRencontresTMR();
}
/* -------------------------------------------- */
@@ -302,7 +311,7 @@ export class RdDTMRDialog extends Dialog {
}
const coord = this._getCoordActor();
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
let ptsreve = document.getElementById("tmr-pointsreve-value");
ptsreve.innerHTML = this.actor.system.reve.reve.value;
@@ -382,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();
@@ -392,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();
@@ -446,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 = {

View File

@@ -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";
@@ -19,6 +19,7 @@ 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
@@ -99,8 +100,9 @@ export class RdDUtility {
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));
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))
Hooks.on('renderChatLog', (log, html, chatLog) => RdDUtility.chatListeners(html))
}
/* -------------------------------------------- */
@@ -206,6 +208,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',
@@ -260,8 +263,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() ?? '');
@@ -270,6 +271,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)); });
@@ -298,6 +303,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);
}
@@ -345,13 +358,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);
}
}
}
}
@@ -622,7 +637,7 @@ export class RdDUtility {
/* -------------------------------------------- */
static async _evaluatePerte(formula, over20) {
let perte = new Roll(formula, { over20: over20 });
await perte.evaluate({ async: true });
await perte.evaluate();
return perte.total;
}
@@ -754,7 +769,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,
@@ -890,10 +905,4 @@ export class RdDUtility {
}
}
/*-------------------------------------------- */
static async onRenderChatMessage(app, html, msg) {
// TODO
//console.log(app, html, msg);
}
}

View File

@@ -26,6 +26,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"},
@@ -70,8 +71,7 @@ export class ReglesOptionnelles extends FormApplication {
}
static get defaultOptions() {
const options = super.defaultOptions;
foundry.utils.mergeObject(options, {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "regles-optionnelles",
template: "systems/foundryvtt-reve-de-dragon/templates/settings/regles-optionnelles.html",
height: 650,
@@ -79,8 +79,7 @@ export class ReglesOptionnelles extends FormApplication {
minimizable: false,
closeOnSubmit: true,
title: "Règles optionnelles"
});
return options;
}, { inplace: false })
}
getData() {

View File

@@ -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
@@ -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,

View File

@@ -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";
@@ -152,7 +153,7 @@ export class SystemCompendiums extends FormApplication {
getData() {
const systemCompendiums = Object.values(CONFIGURABLE_COMPENDIUMS)
.map(it => foundry.utils.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,
@@ -163,7 +164,7 @@ export class SystemCompendiums extends FormApplication {
return foundry.utils.mergeObject(super.getData(), {
systemCompendiums: systemCompendiums,
availableCompendiums: availableCompendiums
});
}, { inplace: false })
}
activateListeners(html) {
@@ -290,7 +291,7 @@ export class CompendiumTableHelpers {
sound: CONFIG.sounds.dice,
content: flavorContent
};
ChatMessage.create(messageData, { rollMode: "gmroll" });
await ChatUtility.createChatWithRollMode(game.user.id, messageData)
}
/* -------------------------------------------- */
@@ -306,7 +307,7 @@ export class CompendiumTableHelpers {
whisper: game.user.id,
content: flavorContent
};
ChatMessage.create(messageData, { rollMode: "gmroll" });
await ChatUtility.createChatWithRollMode(game.user.id, messageData)
}
}

View File

@@ -25,7 +25,7 @@ export class AppAstrologie extends Application {
classes: ['calendar-astrologie'],
popOut: true,
resizable: false
});
}, { inplace: false })
}
constructor(actor, options = {}) {
@@ -49,7 +49,7 @@ export class AppAstrologie extends Application {
signeNaissance: RdDTimestamp.definition(0)
}
})
return this.appData;
return this.appData
}
getActorAstrologie() {

View File

@@ -17,7 +17,7 @@ export class AutoAdjustDarkness {
static async adjust(darkness) {
if (AutoAdjustDarkness.isAuto()) {
const scene = game.scenes.viewed;
if (scene?.globalLight && scene?.tokenVision) {
if (scene?.environment?.globalLight?.enabled && scene?.tokenVision) {
await scene.update({ darkness });
}
}

View File

@@ -43,7 +43,7 @@ export class RdDCalendrier extends Application {
resizable: false,
width: 'fit-content',
height: 'fit-content',
});
}, { inplace: false })
}
constructor() {
@@ -123,9 +123,9 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
fillCalendrierData(formData = {}) {
foundry.utils.mergeObject(formData, this.timestamp.toCalendrier());
formData.isGM = game.user.isGM;
formData.isGM = game.user.isGM
formData.heures = RdDTimestamp.definitions()
formData.horlogeAnalogique = this.horlogeAnalogique;
formData.horlogeAnalogique = this.horlogeAnalogique
formData.autoDarkness = AutoAdjustDarkness.isAuto()
return formData;
}
@@ -372,7 +372,7 @@ export class RdDCalendrier extends Application {
game.socket.emit(SYSTEM_SOCKET_ID, { msg: "msg_app_astrologie_refresh", data: {} })
}
}
async addNbAstralJoueur(actor, date, nbAstral, isValid) {
const nombresAstraux = this.getNombresAstraux()
const astralData = nombresAstraux.find(it => it.index == date)

View File

@@ -231,6 +231,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) }

View File

@@ -125,7 +125,7 @@ export class FenetreRechercheTirage extends Application {
popOut: true,
dragDrop: [{ dragSelector: "a.content-link" }],
resizable: true
});
}, { inplace: false })
}
static async create() {

View File

@@ -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,
})
}
}

View File

@@ -1,6 +1,7 @@
import { 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 = [
@@ -36,7 +37,7 @@ export class DialogFatigueVoyage extends Dialog {
const parameters = {
tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE,
playerActors: game.actors.filter(actor => actor.isPersonnageJoueur())
.map(actor => DialogFatigueVoyage.prepareActor(actor)),
.map(actor => DialogFatigueVoyage.prepareActorParameters(actor)),
nombreHeures: 1,
}
DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined)
@@ -53,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[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 = {
@@ -97,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())
}
@@ -118,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)
))
}
}
@@ -132,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),
content: await renderTemplate(
'systems/foundryvtt-reve-de-dragon/templates/voyage/chat-fatigue_voyage.hbs', foundry.utils.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() {

View File

@@ -1374,7 +1374,7 @@ table.table-nombres-astraux tr:hover {
flex-direction: column;
position: absolute;
top: 4.6rem;
right: 3.5rem;
left: -19rem;
}
.token-hud-ext.soins {
flex-direction: column;
@@ -1527,6 +1527,11 @@ div.control-icon.token-hud-icon {
font-size: 1rem;
}
.chat-message header.message-header .heure-rdd {
font-size: 0.7rem;
flex-grow: 3;
}
.chat-message.whisper {
background: rgba(220,220,210,0.75);
border: 2px solid #545469;

View File

@@ -1,13 +1,13 @@
{
"id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon",
"version": "11.2.20",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-11.2.20.zip",
"version": "12.0.7",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.7.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": {
"minimum": "11",
"verified": "11"
"verified": "12"
},
"description": "Rêve de Dragon RPG for FoundryVTT",
"authors": [

View File

@@ -55,9 +55,7 @@
<li class="caracteristique flexrow list-item" data-tooltip="Niveau d'éthylisme">
<label class="derivee-label" for="system.compteurs.ethylisme.value">{{system.compteurs.ethylisme.label}}</label>
<select class="derivee-value" name="system.compteurs.ethylisme.value" data-dtype="Number">
{{#select system.compteurs.ethylisme.value}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-niveau-ethylisme.html"}}
{{/select}}
{{selectOptions (RDD_CONFIG 'niveauEthylisme') selected=system.compteurs.ethylisme.value valueAttr="value" nameAttr="value" labelAttr="label"}}
</select>
</li>

View File

@@ -2,20 +2,13 @@
<li class="caracteristique flexrow list-item">
<span class="carac-label" name="catEntite">Catégorie : </span>
<select name="system.definition.categorieentite" value="{{system.definition.categorieentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}>
{{#select system.definition.categorieentite}}
<option value="cauchemar">Cauchemar</option>
<option value="reve">Rêve</option>
{{/select}}
{{selectOptions (RDD_CONFIG 'categorieEntite') selected=system.definition.categorieentite}}
</select>
</li>
<li class="caracteristique flexrow list-item">
<span class="carac-label" name="typeEntite">Type d'entité : </span>
<select name="system.definition.typeentite" value="{{system.definition.typeentite}}" data-dtype="String" {{#unless @root.options.vueDetaillee}}disabled{{/unless}}>
{{#select system.definition.typeentite}}
<option value="incarne">Incarnée</option>
<option value="nonincarne">Non Incarnée</option>
<option value="blurette">Blurette</option>
{{/select}}
{{selectOptions (RDD_CONFIG 'typeEntite') selected=system.definition.typeentite}}
</select>
</li>
{{#each system.attributs as |attr key|}}

View File

@@ -2,7 +2,7 @@
{{#if effects}}
{{#each effects as |effect key|}}
<span class="active-effect" data-effect="{{effect.id}}">
<img class="button-effect-img {{#if @root.options.isGM}}delete-active-effect{{/if}}" src="{{effect.icon}}" data-tooltip="{{localize effect.name}}" width="24" height="24" />
<img class="button-effect-img {{#if @root.options.isGM}}delete-active-effect{{/if}}" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" width="24" height="24" />
</span>
{{/each}}
{{#if calc.surprise}}<span>{{calc.surprise}}!</span>{{/if}}

View File

@@ -1,3 +1,4 @@
{{log 'chat-vente-item' this}}
<div class="post-item" data-transfer="{{transfer}}">
<h3>{{#if alias}}{{alias}} propose: {{else}}Acheter {{/if}}{{item.name}}</h3>
{{#if item.img}}
@@ -12,7 +13,7 @@
<hr>
<p>
{{#unless quantiteIllimite}}
<span>Lots disponibles: <span class="quantiteNbLots">{{quantiteNbLots}}</span></span><br>
<span>Lots disponibles: {{nbLots}}</span><br>
{{/unless}}
{{#if (gt tailleLot 1)}}
<span>Lots de: <span class="tailleLot">{{tailleLot}}</span></span><br>
@@ -22,15 +23,9 @@
<span class="prixLot">{{numberFormat prixLot decimals=2 sign=false}}</span> Sols</strong></span><br>
{{/if}}
</p>
{{#if (or (gt quantiteNbLots 0) quantiteIllimite)}}
{{#if (or (gt nbLots 0) quantiteIllimite)}}
<span class="chat-card-button-area">
<a class="button-acheter chat-card-button"
data-jsondata='{{jsondata}}'
{{#if vendeurId}}data-vendeurId='{{vendeurId}}'{{/if}}
data-tailleLot="{{tailleLot}}"
data-quantiteNbLots="{{quantiteNbLots}}"
data-quantiteIllimite="{{#if quantiteIllimite}}true{{else}}false{{/if}}"
data-prixLot="{{prixLot}}">
<a class="button-acheter chat-card-button">
{{#if (eq prixLot 0)}}Prendre{{else}}Acheter{{/if}}</a>
</span>
{{/if}}

View File

@@ -1,22 +1,20 @@
<span draggable="true">
{{#if pack}}
{{!-- draggable="true" --}}
<a class="content-link"
<span draggable="true">
<a class="{{#if pack}}content-link{{else}}rdd-world-content-link{{/if}}"
data-id="{{id}}"
data-link=""
{{#if doctype}}
data-doctype="{{doctype}}"
data-type="{{doctype}}"
{{/if}}
{{#if pack}}
data-pack="{{pack}}"
data-uuid="Compendium.{{pack}}.{{id}}"
data-pack="{{pack}}"
{{#if doctype}}data-doctype="{{doctype}}"{{/if}}
data-id="{{id}}"
>
{{else}}
<a class="rdd-world-content-link"
{{#if doctype}}data-doctype="{{doctype}}"{{/if}}
data-id="{{id}}"
>
{{/if}}
{{#if img}}
<img class="in-text-img" src="{{img}}" data-tooltip="{{name}}" />
{{else}}
<i class="fas fa-suitcase"></i>
{{/if}}
{{name}}</a>
{{/if}} >
{{#if img}}
<img class="in-text-img" src="{{img}}" data-tooltip="{{name}}" />
{{else}}
<i class="fas fa-suitcase"></i>
{{/if}}
{{name}}
</a>
</span>

View File

@@ -0,0 +1,3 @@
<span class="message-metadata heure-rdd">
{{this.jourDuMois}} {{this.mois.label}} - {{timestamp-imgSigne this.heure}}
</span>

View File

@@ -2,8 +2,6 @@
<div class="flexrow">
<input type="number" name="{{path}}.nombre" value="{{nombre}}" data-dtype="Number"/>
<select name="{{path}}.unite" data-dtype="String" >
{{#select unite}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-periode.html"}}
{{/select}}
{{selectOptions (timestamp-formulesPeriode) selected=unite labelAttr="label" nameAttr="code" valueAttr="code"}}
</select>
</div>

View File

@@ -6,9 +6,7 @@
type="number" data-dtype="Number" min="1" max="28"
name="{{path}}.jourDuMois" value="{{jourDuMois}}" />
<select {{#if disabled}}{{disabled}}{{/if}} name="{{path}}.mois" class="calendar-signe-heure" data-dtype="String">
{{#select mois.key}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
{{selectOptions (RDD_CONFIG 'heuresRdD') selected=mois.key labelAttr="label" nameAttr="value" valueAttr="value"}}
</select>
{{timestamp-imgSigne mois}}
<input {{#if disabled}}{{disabled}}{{/if}} type="number" class="number-x2" name="{{path}}.annee" value="{{annee}}" data-dtype="Number"/>
@@ -17,9 +15,7 @@
<label></label>
<label>heure</label>
<select {{#if disabled}}{{disabled}}{{/if}} name="{{path}}.heure" class="calendar-signe-heure" data-dtype="String">
{{#select heure.key}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-heures.html"}}
{{/select}}
{{selectOptions (RDD_CONFIG 'heuresRdD') selected=heure.key labelAttr="label" nameAttr="value" valueAttr="value"}}
</select>
{{timestamp-imgSigne heure}}
<input {{#if disabled}}{{disabled}}{{/if}} type="number" class="number-x2" name="{{path}}.minute" value="{{minute}}" data-dtype="Number"/>

View File

@@ -31,7 +31,7 @@
<label>{{#if quantiteIllimite}}
pas de limite
{{else}}
{{quantiteNbLots}}
{{nbLots}}
{{/if}}</label>
</div>
<div class="flexrow flex-group-left">
@@ -41,7 +41,7 @@
</label>
<div class="flexrow">
<input name="nombreLots" class="nombreLots flex-shrink number-x2" type="number" min="1"
{{#unless quantiteIllimite}} max="{{quantiteNbLots}}" {{/unless}}
{{#unless quantiteIllimite}} max="{{nbLots}}" {{/unless}}
value="{{choix.nombreLots}}"
data-dtype="Number" />
</div>

View File

@@ -18,8 +18,8 @@
quantiteIllimite}}checked{{/if}} />
<label class="label-quantiteIllimite flex-shrink">disponibles</label>
{{/unless}}
<input name="quantiteNbLots" class="quantiteNbLots flex-shrink number-x2" type="number" min="1"
max="{{quantiteMaxLots}}" value="{{quantiteNbLots}}" data-dtype="Number" />
<input name="nbLots" class="nbLots flex-shrink number-x2" type="number" min="1"
max="{{maxLots}}" value="{{nbLots}}" data-dtype="Number" />
</div>
</div>
<div class="flexrow flex-group-left">

View File

@@ -18,6 +18,7 @@
<a class="milieu-add"><i class="fas fa-plus-circle"></i></a>
</span>
</div>
{{#each system.environnement as |env key|}}
<div class="form-group environnement-milieu" data-milieu="{{env.milieu}}">
<label>
@@ -26,9 +27,7 @@
</label>
<span class="flexrow">
<select name="milieu-{{key}}-rarete" class="environnement-rarete flex-shrink" data-dtype="String">
{{#select env.rarete}}
{{>"systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html"}}
{{/select}}
{{selectOptions (RDD_CONFIG 'raretes') selected=env.rarete labelAttr="label" valueAttr="value" nameAttr="value"}}
</select>
{{rangePicker name="milieu-{{key}}-frequence" value=env.frequence min=(rarete-getChamp env.rarete 'min') max=(rarete-getChamp env.rarete 'max') step=1}}
<label>[{{rarete-getChamp env.rarete 'min'}}-{{rarete-getChamp env.rarete 'max'}}]</label>

View File

@@ -7,7 +7,7 @@
{{else}}
<input class="resource-content select-effect" type="checkbox" name="{{effect.id}}" {{#if effect.active}}checked{{/if}}/>
{{/if}}
<img class="button-effect-img" height="16" width="16" src="{{effect.icon}}" data-tooltip="{{localize effect.name}}" />
<img class="button-effect-img" height="16" width="16" src="{{effect.img}}" data-tooltip="{{localize effect.name}}" />
<label>{{localize effect.name}}</label>
</li>
{{/each}}

View File

@@ -3,7 +3,7 @@
{{#each systemCompendiums as |definition key|}}
<li class="flexrow">
<label>{{definition.label}}</label>
<select data-dtype="String" class="system-compendium-setting flex-grow-2" data-compendium="{{definition.compendium}}" >
<select data-dtype="String" class="system-compendium-setting flex-grow-2" data-compendium="{{definition.compendium}}" >
{{#select definition.value}}
{{#each @root.availableCompendiums as |available key|}}
{{#if (eq available.type definition.type)}}

View File

@@ -1,19 +1,11 @@
<div>
<label>Conditions</label>
<select name="diffConditions" data-dtype="Number">
{{#select '0'}}
{{#each actorAstrologie.ajustements as |ajustement|}}
<option value={{ajustement}}>{{ajustement}}</option>
{{/each}}
{{/select}}
{{selectOptions actorAstrologie.ajustements selected='0'}}
</select>
<label>&nbsp;&nbsp;Jours</label>
<select name="joursAstrologie" data-dtype="Number">
{{#select ''}}
{{#each dates as |date|}}
<option value={{date.index}}>{{date.label}}</option>
{{/each}}
{{/select}}
{{selectOptions dates selected='' labelAttr='label' valueAttr='index' nameAttr='index'}}
</select>
<label>
&nbsp;&nbsp;Etat Général: {{actorAstrologie.etat}}

View File

@@ -42,7 +42,8 @@
<li class="competence-header flexrow">
<span class="flex-grow-2">Personnage</span>
<span class="flex-grow-2">Survies</span>
<span class="flex-grow-1" data-tooltip="Ajustements à appliquer pour les personnages se reposant (par exemple, à cheval)">Ajustements</span>
<span class="flex-grow-1" data-tooltip="Ajustements à appliquer (par exemple, repos à cheval)">Ajustements</span>
<span class="flex-grow-1" data-tooltip="Total de fatigue pour le voyageur">Total</span>
</li>
{{#each playerActors as |selected|}}
{{>'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs' voyageur=selected survies=@root.typeTerrain.survies}}

View File

@@ -8,16 +8,13 @@
</span>
<span class="flex-grow-2">
<div class="flexcol ">
<label class="voyage-liste-survies">
{{#each voyageur.competencesVoyage as |comp key|}}
{{#if (array-includes ../survies key)}}
{{key}} {{comp.system.niveau}},
{{/if}}
{{/each}}
</label>
<label class="voyage-liste-survies">{{voyageur.survieCourante}}</label>
</div>
</span>
<span class="flex-grow-1">
<input type="number" name="ajustement-fatigue" class="number-x2 ajustement-fatigue" data-dtype="Number" value="{{voyageur.ajustementFatigue}}" min="-6" max="6"/>
</span>
<span class="flex-grow-1">
<input type="number" name="total-fatigue" class="number-x2 total-fatigue" data-dtype="Number" value="1" min="0" max="24" disabled/>
</span>
</li>