Compare commits

..

116 Commits
v1.4 ... master

Author SHA1 Message Date
c515e9bc66 Merge branch 'tyrcho-master-patch-22717' into 'master'
typos

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!269
2021-06-07 22:01:32 +00:00
b2e7a8a6e1 typos 2021-06-07 21:41:04 +00:00
09045c0d53 Blocage astro #198, Synchro horloge #197, gérer pièces #196 2021-06-01 21:05:45 +02:00
4c4e1e8419 Fix combat et messages 2021-06-01 07:52:47 +02:00
66bcc51102 Merge branch 'master-fix-combat' into 'master'
Fix: regression combat

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!262
2021-06-01 04:34:22 +00:00
32844bbf3c increment version 1.3.62 2021-06-01 00:20:24 +02:00
21d6f14b68 Fix: regression combat
Notifier tous les postes clients des données de passe d'arme
2021-06-01 00:18:41 +02:00
87a0bece5e Cosmetic changes 2021-05-26 17:45:52 +02:00
e0f83e9be2 Fix TMR 2021-05-26 16:41:18 +02:00
01c1978ccd Fix pour montée TMR en double 2021-05-24 09:36:09 +02:00
47ae157781 Fix pour montée TMR en double 2021-05-24 09:35:49 +02:00
0c092b9099 Fix for Misc.js 2021-05-22 17:51:30 +02:00
a6d1a84b13 Fix combat avec MJ 2021-05-22 08:40:00 +02:00
82e8954d5c Merge branch 'master-fix-defense-193' into 'master'
#193: utiliser isElectedUser pour les défenses

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!249
2021-05-22 06:39:14 +00:00
249850558b #193: utiliser isElectedUser pour les défenses
Misc.isElectedUser renvoit true pour un seul MJ connecté,
ou le joueur connecté s'il n'y a pas de MJ.

Ca veut dire que sans MJ, les messages de combat ne marcheront
peut-être pas, mais pour tous les autres cas, ça marchera correctement,
vu que ce sera toujours un MJ qui postera le message de défense au
joueur (connecté ou pas) et au MJ
2021-05-22 02:04:25 +02:00
45b10f2c6b Fix sur defense 2021-05-18 10:14:57 +02:00
d39dac3bf9 Merge branch 'master-fix' into 'master'
Fix: pas de messages de défense

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!240
2021-05-18 08:14:18 +00:00
1f5e8c084b Fix +dom Bandersnatch 2021-05-18 00:36:07 +02:00
0864721bc5 Fix: pas de messages de défense
Dans certains cas, il n'y avait plus de message pour que le personnage
attaqué se défense
2021-05-17 23:18:03 +02:00
4c5685c20b Update release 2021-05-14 08:46:38 +02:00
a618200417 Merge branch 'master-fix' into 'master'
Fix rencontre Rêve de Dragon

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!237
2021-05-12 04:45:17 +00:00
62eb6482d0 Fix rencontre Rêve de Dragon
Le minimum était devenu 14
2021-05-12 00:06:53 +02:00
9b8ea03067 Merge branch 'master-fix' into 'master'
Fix jet récupération

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!229
2021-05-08 05:41:14 +00:00
8090d0280d Fix jet récupération
le +7 n'est pas justifié, sinon on ne fait que des rêves
de dragon
2021-05-08 00:27:50 +02:00
c31202fbd3 Merge branch 'master-misc' into 'master'
Utiliser des polices pour les dés

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!223
2021-05-01 21:50:58 +00:00
146c8d184c Utiliser des polices pour les dés
Afin de ne pas avoir de soucis de couleurs
2021-05-01 15:53:26 +02:00
c251727dea Aide tchat dans un dialogue 2021-05-01 13:00:49 +02:00
19f5e2af59 Fix jet éthylisme sur vie 2021-05-01 13:00:42 +02:00
8b2f02d4b0 Sync versions 2021-04-30 23:11:06 +02:00
03b88a269a Merge branch 'master-des' into 'master'
Un dé pour les heures draconiques

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!219
2021-04-30 06:13:46 +00:00
32d016b9ad Dé des heures
inutile, donc indispensable

 /roll 1dh
2021-04-30 00:51:38 +02:00
a0c1d063f1 Fix dé dragon sans bords pour tous
Pas uniquement pour le système rdd
2021-04-30 00:51:38 +02:00
1e5446fcde Merge branch 'master-des' into 'master'
Jolis dés draconiques

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!218
2021-04-29 06:25:38 +00:00
f76e0db046 Jolis dés draconiques 2021-04-29 03:59:16 +02:00
b7c816129b Merge branch 'master-blessures' into 'master'
Amélioration des blessures #173

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!216
2021-04-28 07:42:18 +00:00
c786757db0 Fix: oubli correction tmr multiples 2021-04-28 00:43:06 +02:00
78d4b48aae Amélioration des blessures #173
# Conflicts:
#	templates/chat-resultat-encaissement.html
2021-04-28 00:33:44 +02:00
0a9e8e0ac6 Amélioration présentation blessures #173 2021-04-28 00:33:44 +02:00
5443cb52bb Merge branch 'master-rappel-regles' into 'master'
Amélioration, rappel-des-regles

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!215
2021-04-27 07:34:02 +00:00
b232a8fa0c typofix 2021-04-27 00:36:01 +02:00
a68aa29b53 Extraction calcul chances 2021-04-26 23:45:43 +02:00
ccb9cd73f4 Amélioration, rappel-des-regles 2021-04-26 23:44:39 +02:00
723d1e6b99 Fix #187 2021-04-26 00:07:36 +02:00
40f99da8ac Merge branch 'master-fix-187' into 'master'
Fix: recul sur encaissement créature #187

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!213
2021-04-25 22:06:21 +00:00
76865d24d2 Fix: recul sur encaissement créature #187 2021-04-25 14:50:44 +02:00
020824af7e Reset des nombre astraux 2021-04-25 09:43:26 +02:00
cc8f432746 Merge branch 'master' of gitlab.com:LeRatierBretonnien/foundryvtt-reve-de-dragon 2021-04-24 09:31:41 +02:00
6435ce70da Fix sauvegarde TMR 2021-04-24 09:31:29 +02:00
db9cbc693a Merge branch 'master-fix' into 'master'
Fix: après dérobade, impossible ouvrir fiche

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!208
2021-04-18 06:39:12 +00:00
b202352979 Fix: après dérobade, impossible ouvrir fiche 2021-04-17 21:03:59 +02:00
7ddedea204 Updat release 2021-04-17 09:19:15 +02:00
2bca036d53 Merge branch 'master-fix' into 'master'
Empêcher doublons sur tête/souffle #175

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!206
2021-04-17 07:18:31 +00:00
8f08f95dbf Updat release 2021-04-17 09:08:09 +02:00
b5581ff9fb Ajout de tokens de créatures 2021-04-17 00:04:25 +02:00
e06ae1937a Empêcher doublons sur tête/souffle #175
Lors de l'ajout de la tête présents des cités, le présent de chaque
cité était ajouté par tous les joueurs connectés qui traitaient le hook
2021-04-16 23:33:09 +02:00
0f7e1ef553 Merge branch 'master-fix-compendium' into 'master'
Fix compendium voyageurs

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!201
2021-04-16 07:14:57 +00:00
51afd9020c Fix compendium voyageurs
- nom de token Coureur des Rues
- don de haut rêve pour le Cuisinier Haut-Rêvant
- tokens maintenant neutres
2021-04-15 20:00:14 +02:00
1bc5e06147 Merge branch 'master-fix-comp-base' into 'master'
Fix categorieCompetences.base

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!196
2021-04-09 08:29:51 +00:00
7f3a575349 Fix categorieCompetences.base
au lieu de niveau/level
2021-04-09 09:41:57 +02:00
c26ba66722 #182 - Décompte XP 2021-04-09 08:46:46 +02:00
cb105dd311 Merge branch 'master' of gitlab.com:LeRatierBretonnien/foundryvtt-reve-de-dragon 2021-04-09 08:09:20 +02:00
76c88e530e #182 - Décompte XP 2021-04-09 08:09:04 +02:00
03839397ce Merge branch 'master-fix-182' into 'master'
Fix xp des compétences tronc #182

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!195
2021-04-09 06:05:05 +00:00
74ddc8893a Fix xp des compétences tronc #182
La méthode splice retourne les éléments supprimées, et non pas
le tableau après suppression

# Conflicts:
#	module/item-competence.js
#	module/misc.js
2021-04-09 01:12:02 +02:00
790aa950c3 Message explicite HR 2021-04-04 09:03:28 +02:00
4672a3a7d6 Message explicite HR 2021-04-04 08:58:23 +02:00
2a8ab5e1ce Merge branch 'master-demi-surprise' into 'master'
Demi-surprise: Réussite normale => échec #181

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!190
2021-04-04 06:50:37 +00:00
4aaa72ed1a Erreur si draconic sans être haut-rêvant 2021-04-04 00:16:49 +02:00
f087b61c27 Demi-surprise: Réussite normale => échec #181
En demi-surprise, les résultats "réussite normaux" sont
maintenant présenté comme des réussite insuffisantes
2021-04-03 23:59:47 +02:00
96c6936c3e Fix: message pour non haut-rêvant 2021-04-03 23:59:47 +02:00
7d27d7d9f9 Fix sur commande astro 2021-04-03 23:01:04 +02:00
0d7ba3be69 Merge branch 'master' of gitlab.com:LeRatierBretonnien/foundryvtt-reve-de-dragon 2021-04-03 18:53:21 +02:00
8670456d9a Increment version 2021-04-03 18:53:09 +02:00
b2c7ff4927 Merge branch 'master-177' into 'master'
Fix: #177 arme creature incorrecte

Closes #177

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!189
2021-04-03 16:52:42 +00:00
680fbee090 Fix: #177 arme creature incorrecte 2021-04-03 13:05:10 +02:00
5c6a01b9f4 Push pour mini-fixes 2021-04-03 08:39:31 +02:00
d45f5d625a #179 - Fix reve-actuel 2021-04-03 08:32:27 +02:00
2b1a9151d7 Gestion état sonné correct 2021-04-03 08:18:08 +02:00
3335c41c27 Merge branch 'master-improve' into 'master'
Draconic pour les haut-rêvants - HUD

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!188
2021-04-03 06:16:18 +00:00
329ae475d9 Correction message échec total 2021-04-03 03:05:44 +02:00
72f8c83caf Draconic que pour les Haut rêvant #174 2021-04-03 03:04:48 +02:00
d353b6ccaf Fix regression liste tâches 2021-04-02 22:06:58 +02:00
a122a2e421 Merge branch 'master-hautrevant' into 'master'
Limiter le draconic aux Haut rêvant - #174

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!185
2021-04-02 06:45:10 +00:00
2465af4413 réparation icones 2021-04-01 23:02:03 +02:00
817c5d30ad Les haut-rêvants ont le don de haut rêve 2021-04-01 23:02:02 +02:00
87440cf7f9 Limiter le draconic aux Haut rêvant - #174 2021-04-01 23:02:02 +02:00
965e45cead Merge branch 'master-fixes' into 'master'
Fix détermination nombre astral

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!184
2021-04-01 05:41:36 +00:00
ac8610cd6c Fix détermination nombre astral
fixé, déplacé dans les savoirs

# Conflicts:
#	module/rdd-calendrier.js
#	templates/actor-sheet.html
2021-04-01 01:12:16 +02:00
08cf1f49e1 Fix Chanter la chanson 2021-04-01 01:12:15 +02:00
4925cee756 Fix changement jour 2021-04-01 01:12:15 +02:00
43acbfb443 Simplification calcul de difficulté alchimie 2021-04-01 01:12:15 +02:00
9a6fb1a850 Fix reférence de recette de cuisine 2021-04-01 01:12:15 +02:00
42fb0c0b5e Merge branch 'master-fixes' into 'master'
Création d'oeuvres

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!182
2021-03-31 06:40:56 +00:00
fa2b125459 Création d'oeuvres
# Conflicts:
#	module/actor-sheet.js
2021-03-31 01:34:52 +02:00
e8d0748688 Fix tooltip périple 2021-03-29 23:57:37 +02:00
2972504640 Fix caracXP, chance, /payer 2021-03-27 14:55:32 +01:00
3582fa9c8a Merge branch 'master-fixes' into 'master'
Fix expérience carac

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!179
2021-03-27 13:54:53 +00:00
d5277137dd Fix dépense chance sur appel à la chance 2021-03-27 14:41:12 +01:00
dae852a1e0 Fix expérience carac
=> await manquant
=> plusieurs whisper recipients: pas supporté
=> manque lowercase sur recherche de carac par nom
2021-03-27 14:41:12 +01:00
1ea6b66483 Fix chance 2021-03-26 07:42:58 +01:00
d35f3ce5a2 Merge branch 'master-improve' into 'master'
Fix jet de moral/chance

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!178
2021-03-26 06:42:14 +00:00
bf9e74ef7c Ne pas afficher la description d'un sort manqué
Pas d'affichage pour un sort mis en réserve non plus
2021-03-26 01:16:53 +01:00
fd73b2c7af Fix récupération chance 2021-03-26 01:16:52 +01:00
3aa13511cd Fix jet de moral
L'affichage du message ne fonctionnait plus
2021-03-26 01:16:52 +01:00
94cebbb9e5 Ajout edition nombre astral 2021-03-25 18:05:42 +01:00
2a1495927f Merge branch 'master' of gitlab.com:LeRatierBretonnien/foundryvtt-reve-de-dragon 2021-03-25 17:53:30 +01:00
8d42871988 Fix competence base 2021-03-25 17:52:02 +01:00
868ed01723 Merge branch 'master-improve' into 'master'
Fix /rdd [carac]

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!177
2021-03-25 16:36:49 +00:00
65c90c5bd4 Fix /rdd [carac]
- en cas de carac exact (reve), choisir cette caractéristique
(pas de message par rapport à reve-actuel)
- support /rdd odorat-gout
2021-03-25 10:27:33 +01:00
c16101428a Add 2021-03-25 07:45:32 +01:00
77d5646497 Permet les macros spéciales (SF) 2021-03-25 07:34:19 +01:00
1c0c775de3 Merge branch 'master-improve' into 'master'
Jets de masse

See merge request LeRatierBretonnien/foundryvtt-reve-de-dragon!174
2021-03-25 06:32:16 +00:00
e8a59b56a4 Fix: privilégier le nom exact 2021-03-25 01:58:41 +01:00
39f6307058 Version 1.3.38 2021-03-25 00:16:53 +01:00
a532a989d6 Jets de masse
Quelques exemples:

- `/rdd dexterite bricolage -2`
- `/rdd vue survie en sous-sol -2`
- `/rdd vue désert 0`
- `/rdd vue vigi -3`
- `/rdd vol vigi 0` : Volonté Vigilance
- `/rdd chance-actuelle 0`
- `/rdd reve-actuel -8`

Attention:
- `/rdd vue vig 0`

 => Navigation et Vigilance correspondent, c'est Navigation qui est
pris (premier dans l'ordre alphabétique), avec un message.
2021-03-25 00:15:08 +01:00
a802307dac Update release 2021-03-24 11:10:17 +01:00
260 changed files with 26208 additions and 7735 deletions

2
.gitignore vendored
View File

@ -1,5 +1,3 @@
.vscode/settings.json
.idea
todo.txt
todo.md
/.vscode

43
RdD.geany Normal file
View File

@ -0,0 +1,43 @@
[editor]
line_wrapping=false
line_break_column=72
auto_continue_multiline=true
[file_prefs]
final_new_line=true
ensure_convert_new_lines=false
strip_trailing_spaces=false
replace_tabs=false
[indentation]
indent_width=2
indent_type=0
indent_hard_tab_width=8
detect_indent=false
detect_indent_width=false
indent_mode=2
[project]
name=RdD
base_path=/home/morr/work/foundryvtt/foundryvtt-reve-de-dragon
description=
file_patterns=
[long line marker]
long_line_behaviour=1
long_line_column=72
[files]
current_page=8
FILE_NAME_0=9759;JSON;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Ftemplate.json;0;2
FILE_NAME_1=8120;CSS;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fstyles%2Fsimple.css;0;2
FILE_NAME_2=19778;Javascript;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fmodule%2Ftmr-utility.js;0;2
FILE_NAME_3=21106;Javascript;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fmodule%2Factor.js;0;2
FILE_NAME_4=6228;Javascript;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fmodule%2Factor-sheet.js;0;2
FILE_NAME_5=20083;HTML;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Ftemplates%2Factor-sheet.html;0;2
FILE_NAME_6=1312;Javascript;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fmodule%2Frdd-tmr-dialog.js;0;2
FILE_NAME_7=1767;Javascript;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fmodule%2Frdd-roll-dialog.js;0;2
FILE_NAME_8=266;None;0;EUTF-8;0;1;0;%2Fhome%2Fmorr%2Fwork%2Ffoundryvtt%2Ffoundryvtt-reve-de-dragon%2Fpacks%2Fqueues-de-dragon.db;0;2
[VTE]
last_dir=/home/sigmar

View File

@ -1,61 +0,0 @@
# Actor notes
> The Actor#getData default implementation gives you the following for use in sheet rendering:
```
actor -> the Actor instance
data -> a cloned copy of Actor#data
items -> a cloned copy of Actor#data#items
effects -> a cloned copy of Actor#data#effects
```
> if all you need is a safe copy of `Actor#data`, you'll be much better off by simply defining your own function and avoiding all the wasted work that the parent class does which will slow down your sheet
```js
getData(options) {
return {
data: foundry.utils.deepClone(this.object.data)
}
}
```
who knows, maybe you don't even need to copy your actor data, skip the copy and it's even faster:
```js
getData(options) {
return {
data: this.object.data
}
}
```
Atropos19/02/2021
There are two recommended ways to create owned items in 0.8.0:
```js
await Item.create(itemData, {parent: actor});
await actor.createEmbeddedDocuments("Item", itemDataArray);
```
You can update an embedded item in one of two ways:
```js
//Method 1:
const item = actor.items.get(itemId);
item.update(data);
//Method 2:
actor.updateEmbeddedDocuments("Item", [{_id: itemId, ...}]);
```
I noticed adding an ActiveEffect to an actor in code using
```js
this.createEmbeddedDocuments('ActiveEffect', [effet], options);
this.applyActiveEffects();
```
Atropos — Aujourdhui à 14:42
Two notes on this:
1. You don't actually need to call this.applyActiveEffects() because this will happen automatically whenever an effect is created/updated/deleted
2. If you want to suppress the automatic display of the sheet for the newly created document, you can pass options.renderSheet = false as part of your options object

BIN
fonts/goudyacc.woff Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.2 KiB

59
icons/humanoides/cyan.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

59
icons/humanoides/ogre.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 387 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 382 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 372 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 368 KiB

130
icons/tmr/gift.svg Normal file
View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="512"
height="512"
viewBox="0 0 512 512"
xml:space="preserve"
sodipodi:docname="gift.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
id="metadata51"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
id="defs49" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2066"
id="namedview47"
showgrid="false"
inkscape:zoom="2.415894"
inkscape:cx="64"
inkscape:cy="163.34211"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
inkscape:current-layer="g14"
inkscape:document-rotation="0" />
<g
id="g14"
transform="matrix(5.7,0,0,5.7,1.6591,1.6521435)">
<g
id="g24-9"
transform="matrix(0.1754386,0,0,0.1754386,3.2674006,3.2686582)"
style="fill:#ffffff;stroke:none"><path
d="m 81.245,212.419 c -9.902,13.127 -19.256,25.526 -8.273,47.079 4.957,9.729 18.132,11.771 28.311,11.771 20.904,0 45.125,-8.057 63.033,-19.182 -2.994,-3.719 -6.111,-8.237 -6.111,-13.949 0,-6.576 4.131,-11.571 7.451,-15.585 1.601,-1.936 3.415,-4.129 3.882,-5.569 0.523,-1.607 0.357,-4.439 0.197,-7.178 -0.299,-5.108 -0.67,-11.466 3.069,-16.605 2.653,-3.644 6.503,-5.517 10.286,-6.759 -3.608,-8.125 -8.398,-16.488 -14.204,-24.48 -14.902,-20.512 -32.983,-33.767 -46.06,-33.767 -2.845,0 -5.39,0.592 -7.78,1.81 -21.868,11.143 -21.404,26.636 -20.912,43.039 0.22,7.359 0.429,14.31 -1.603,20.561 -2.198,6.767 -6.612,12.619 -11.286,18.814 z"
id="path2"
style="fill:#ffffff;stroke:none" /><path
d="m 464.076,203.816 c -7.567,-14.789 -26.952,-17.893 -41.88,-17.893 -9.41,0 -19.295,1.161 -29.221,3.252 1.645,2.602 3.775,5.369 5.992,8.235 10.528,13.614 24.948,32.259 9.778,62.032 -5.735,11.255 -17.472,17.797 -34.132,19.144 4.004,3.046 7.514,6.264 10.369,9.608 7.716,9.035 10.98,18.948 9.44,28.668 -5.153,32.537 -27.667,39.408 -44.107,44.425 -2.622,0.8 -5.172,1.586 -7.547,2.43 17.125,17.508 34.971,27.756 49.438,27.756 4.384,0 8.483,-0.96 12.185,-2.855 32.102,-16.428 31.354,-39.981 30.631,-62.76 -0.318,-10.034 -0.619,-19.512 2.054,-27.791 2.912,-9.018 8.93,-17.024 15.301,-25.501 14.344,-19.083 27.892,-37.108 11.699,-68.75 z"
id="path4"
style="fill:#ffffff;stroke:none" /><path
d="m 270.444,394.702 c 2.878,0.456 5.642,0.687 8.214,0.687 18.176,0 25.863,-11.274 34.001,-23.211 4.148,-6.084 8.066,-11.83 13.384,-15.693 5.755,-4.182 12.766,-6.321 20.188,-8.587 15.727,-4.8 30.581,-9.333 34.364,-33.225 0.893,-5.63 -1.213,-11.479 -6.258,-17.386 -8.141,-9.532 -23.127,-18.049 -39.956,-23.652 -1.862,-0.538 -3.721,-1.116 -5.575,-1.729 -9.632,-2.772 -19.668,-4.561 -29.237,-5.027 0.292,5.036 0.549,11.19 -3.092,16.193 -3.771,5.18 -9.963,6.789 -14.938,8.081 -2.629,0.683 -5.348,1.389 -6.67,2.351 -1.28,0.933 -2.769,3.273 -4.207,5.537 -2.776,4.368 -6.232,9.804 -12.397,11.806 -1.511,0.491 -3.127,0.739 -4.804,0.739 -1.835,0 -3.626,-0.305 -5.359,-0.754 -3.383,17.09 -3.525,36.966 0.635,54.293 2.436,10.148 8.497,27.485 21.707,29.577 z"
id="path6"
style="fill:#ffffff;stroke:none" /><path
d="m 126.439,366.003 c -16.52,-4.826 -39.144,-11.435 -44.37,-44.438 -1.539,-9.719 1.725,-19.632 9.44,-28.667 2.257,-2.643 4.924,-5.206 7.915,-7.669 -19.207,-0.406 -32.657,-7.071 -38.927,-19.376 -14.955,-29.353 -0.779,-48.145 9.572,-61.866 1.457,-1.931 2.882,-3.822 4.177,-5.669 -8.438,-1.537 -16.798,-2.384 -24.81,-2.384 -15.076,0 -34.636,3.13 -42.2,18.042 -16.315,32.161 -1.866,50.776 12.108,68.778 6.156,7.931 11.971,15.422 14.674,23.692 2.944,9.006 2.782,19.021 2.61,29.623 -0.386,23.87 -0.751,46.416 30.949,62.497 3.678,1.866 7.743,2.811 12.085,2.811 15.828,0 35.7,-12.34 54.219,-33.068 -2.312,-0.8 -4.839,-1.546 -7.442,-2.306 z"
id="path8"
style="fill:#ffffff;stroke:none" /><path
d="m 276.172,62.189 c 12.786,0 24.223,5.22 34.962,15.96 9.115,9.115 11.603,22.92 7.36,39.616 9.602,-6.462 19.178,-9.98 27.922,-9.98 5.036,0 9.792,1.123 14.137,3.337 29.352,14.955 28.93,38.491 28.62,55.676 -0.036,2.032 -0.067,4.02 -0.056,5.943 13.727,-6.889 25.322,-15.114 32.853,-23.947 7.611,-8.928 10.762,-17.875 9.364,-26.592 C 425.63,86.594 402.997,80.027 381.11,73.676 371.468,70.879 362.361,68.236 355.314,63.135 347.636,57.578 341.881,49.38 335.789,40.701 324.269,24.291 312.358,7.323 285.965,7.323 c -3.748,0 -7.768,0.339 -11.947,1.009 -20.054,3.212 -28.987,28.625 -32.527,43.488 -1.487,6.242 -2.569,12.945 -3.271,19.898 3.292,-0.724 7.018,-2.048 10.899,-3.439 7.965,-2.855 16.995,-6.09 27.053,-6.09 z"
id="path10"
style="fill:#ffffff;stroke:none" /><path
d="m 80.254,180.726 c 0.028,-2.296 -0.039,-4.745 -0.114,-7.261 -0.516,-17.203 -1.222,-40.762 28.551,-55.932 4.345,-2.214 9.101,-3.336 14.136,-3.336 8.349,0 17.457,3.203 26.621,9.117 -6.331,-19.186 -4.373,-35.058 5.734,-45.165 10.691,-10.692 22.104,-15.89 34.887,-15.89 9.877,0 18.926,3.121 26.909,5.875 1.419,0.49 2.817,0.97 4.191,1.424 -0.685,-4.98 -1.561,-9.809 -2.666,-14.377 -3.594,-14.851 -12.618,-40.235 -32.683,-43.376 -4.124,-0.646 -8.094,-0.973 -11.801,-0.973 -26.95,0 -38.601,17.153 -49.868,33.742 -5.641,8.306 -10.969,16.151 -17.999,21.277 -7.655,5.583 -17.23,8.524 -27.367,11.638 -22.821,7.009 -44.376,13.629 -49.874,48.746 -1.361,8.696 1.798,17.605 9.392,26.48 9.129,10.667 24.272,20.436 41.951,28.011 z"
id="path12"
style="fill:#ffffff;stroke:none" /><path
d="m 328.161,374.443 c -1.295,1.753 -2.6,3.664 -3.935,5.621 -8.438,12.375 -19.993,29.324 -45.568,29.324 -3.304,0 -6.804,-0.289 -10.403,-0.859 -12.671,-2.006 -22.761,-11.63 -29.146,-27.494 -6.21,18.666 -16.992,30 -30.871,32.198 -3.581,0.567 -7.063,0.854 -10.349,0.854 -25.198,0 -36.474,-16.121 -45.533,-29.075 -1.561,-2.232 -3.085,-4.399 -4.611,-6.387 -2.519,4.654 -4.752,9.299 -6.633,13.862 -5.821,14.126 -13.439,39.965 0.946,54.3 11.86,11.818 23.598,17.323 36.938,17.323 11.172,0 21.87,-3.855 32.217,-7.584 9.445,-3.404 18.367,-6.619 27.066,-6.634 9.527,0 18.977,3.24 28.98,6.671 10.371,3.556 21.096,7.234 32.052,7.234 h 0.005 c 13.408,-0.002 25.147,-5.516 36.943,-17.354 14.313,-14.363 6.645,-40.121 0.8,-54.197 -2.432,-5.852 -5.439,-11.836 -8.898,-17.803 z"
id="path14"
style="fill:#ffffff;stroke:none" /><path
d="m 190.069,76.259 c -9.005,0 -16.944,3.746 -24.987,11.789 -9.459,9.458 -4.171,27.047 -0.177,36.69 7.686,18.555 21.693,36.525 36.309,48.605 2.38,-3.296 5.398,-6.483 9.806,-7.914 1.511,-0.491 3.127,-0.739 4.805,-0.739 4.22,0 8.227,1.567 11.763,2.949 2.6,1.016 5.287,2.067 7.057,2.067 1.77,0 4.457,-1.051 7.057,-2.067 3.535,-1.382 7.543,-2.948 11.762,-2.948 1.678,0 3.294,0.249 4.805,0.739 3.715,1.206 6.442,3.662 8.633,6.377 13.957,-12.04 27.143,-29.278 34.512,-47.07 3.994,-9.643 9.282,-27.231 -0.176,-36.69 -8.092,-8.091 -16.055,-11.859 -25.063,-11.859 -7.626,0 -15.102,2.679 -22.331,5.27 -6.931,2.484 -13.477,4.83 -20.049,4.83 -7.115,0 -14.044,-2.39 -21.379,-4.92 -7.286,-2.512 -14.816,-5.109 -22.347,-5.109 z"
id="path16"
style="fill:#ffffff;stroke:none" /><path
d="m 396.271,253.086 c 11.144,-21.87 1.661,-34.13 -8.379,-47.111 -4.504,-5.824 -8.758,-11.324 -10.789,-17.574 -2.199,-6.768 -2.067,-14.096 -1.928,-21.855 0.296,-16.44 0.575,-31.969 -20.978,-42.951 -2.392,-1.218 -4.936,-1.811 -7.781,-1.811 -13.076,0 -31.153,13.253 -46.055,33.763 -7.177,9.878 -12.801,20.322 -16.549,30.183 4.48,1.242 9.45,3.059 12.663,7.474 3.74,5.139 3.368,11.496 3.069,16.604 -0.16,2.739 -0.326,5.571 0.196,7.178 0.467,1.44 2.281,3.633 3.882,5.568 3.319,4.014 7.45,9.008 7.45,15.583 0,3.601 -1.241,6.724 -2.907,9.475 6.998,4.038 14.811,7.587 22.921,10.41 3.011,0.836 5.989,1.759 8.917,2.766 9.424,2.568 18.994,4.068 27.956,4.068 10.181,0.001 23.356,-2.041 28.312,-11.77 z"
id="path18"
style="fill:#ffffff;stroke:none" /><path
d="m 95.897,319.376 c 3.839,24.242 18.717,28.588 34.468,33.189 7.066,2.064 13.742,4.015 19.059,7.877 5.757,4.182 9.957,10.189 14.404,16.547 8.308,11.878 16.155,23.098 34.061,23.098 2.555,0 5.299,-0.229 8.159,-0.683 13.211,-2.092 19.271,-19.429 21.708,-29.577 4.71,-19.62 3.901,-42.504 -0.881,-60.914 -3.359,1.307 -7.109,2.672 -11.051,2.672 -1.678,0 -3.294,-0.249 -4.805,-0.739 -6.165,-2.001 -9.621,-7.438 -12.398,-11.805 -1.439,-2.264 -2.928,-4.605 -4.208,-5.538 -1.322,-0.962 -4.041,-1.668 -6.67,-2.351 -4.976,-1.292 -11.168,-2.9 -14.938,-8.08 -2.434,-3.342 -3.123,-7.199 -3.229,-10.893 -26.569,3.035 -54.982,15.244 -67.422,29.811 -5.043,5.908 -7.149,11.757 -6.257,17.386 z"
id="path20"
style="fill:#ffffff;stroke:none" /><path
d="m 246.796,295.599 c 2.499,0.978 5.084,1.988 6.664,1.988 0.204,0 0.37,-0.019 0.48,-0.055 1.376,-0.447 3.416,-3.657 4.906,-6.001 2.04,-3.21 4.354,-6.849 7.784,-9.346 3.469,-2.525 7.677,-3.618 11.388,-4.583 2.666,-0.692 6.317,-1.641 7.139,-2.768 0.79,-1.086 0.571,-4.821 0.411,-7.548 -0.225,-3.845 -0.48,-8.204 0.856,-12.32 1.292,-3.98 4.011,-7.267 6.41,-10.168 1.889,-2.283 4.238,-5.124 4.238,-6.661 0,-1.536 -2.351,-4.378 -4.238,-6.661 -2.399,-2.9 -5.118,-6.188 -6.41,-10.168 -1.336,-4.115 -1.081,-8.474 -0.856,-12.319 0.16,-2.728 0.379,-6.462 -0.412,-7.549 -0.82,-1.127 -4.471,-2.075 -7.137,-2.768 -3.712,-0.964 -7.918,-2.057 -11.388,-4.583 -3.432,-2.497 -5.745,-6.136 -7.786,-9.347 -1.489,-2.344 -3.529,-5.553 -4.904,-5.999 -0.11,-0.036 -0.276,-0.055 -0.48,-0.055 -1.58,0 -4.165,1.01 -6.665,1.988 -3.63,1.419 -7.745,3.027 -12.153,3.027 -4.408,0 -8.523,-1.609 -12.154,-3.028 -2.5,-0.978 -5.085,-1.988 -6.665,-1.988 -0.204,0 -0.371,0.019 -0.482,0.055 -1.375,0.446 -3.415,3.656 -4.904,5.999 -2.041,3.211 -4.355,6.85 -7.787,9.348 -3.47,2.525 -7.677,3.617 -11.389,4.581 -2.666,0.692 -6.317,1.64 -7.139,2.768 -0.79,1.086 -0.572,4.822 -0.413,7.549 0.225,3.845 0.48,8.203 -0.856,12.319 -1.293,3.98 -4.012,7.267 -6.41,10.167 -1.889,2.284 -4.239,5.126 -4.239,6.662 0,1.537 2.351,4.378 4.239,6.662 2.398,2.9 5.117,6.187 6.41,10.167 1.336,4.115 1.081,8.473 0.856,12.318 -0.159,2.728 -0.377,6.463 0.414,7.55 0.821,1.128 4.472,2.076 7.138,2.768 3.712,0.964 7.918,2.056 11.389,4.581 3.432,2.497 5.745,6.136 7.786,9.347 1.489,2.344 3.53,5.554 4.905,6.001 0.111,0.036 0.277,0.055 0.482,0.055 1.58,0 4.165,-1.011 6.666,-1.988 3.63,-1.419 7.745,-3.028 12.153,-3.028 4.408,0 8.523,1.612 12.153,3.031 z"
id="path22"
style="fill:#ffffff;stroke:none" /></g></g>
<g
id="g16">
</g>
<g
id="g18">
</g>
<g
id="g20">
</g>
<g
id="g22">
</g>
<g
id="g24">
</g>
<g
id="g26">
</g>
<g
id="g28">
</g>
<g
id="g30">
</g>
<g
id="g32">
</g>
<g
id="g34">
</g>
<g
id="g36">
</g>
<g
id="g38">
</g>
<g
id="g40">
</g>
<g
id="g42">
</g>
<g
id="g44">
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 528 B

197
icons/tmr/pelerin.svg Normal file
View File

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg878"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
sodipodi:docname="pelerin.svg">
<defs
id="defs872">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1730">
<g
inkscape:label="Clip"
id="use1732"
style="fill:#d38d5f;stroke:#502d16">
<g
id="g1541"
transform="matrix(0.28980934,0,0,0.21909426,120.56466,-12.741092)"
style="display:inline;fill:#d38d5f;stroke:#502d16;stroke-width:2.16856">
<path
sodipodi:nodetypes="cccccc"
id="path1535"
d="m -174.5565,130.97253 h 15.40856 v 508.4827 l -7.70428,24 -7.70428,-24 z"
style="fill:#d38d5f;stroke:#502d16;stroke-width:2.16856" />
<path
transform="matrix(1.001146,0,0,0.893038,2.193524,15.82179)"
style="fill:#d38d5f;stroke:#502d16;stroke-width:2.29344"
d="m -145.09735,123.91028 c 0,13.11269 -10.64218,17.6523 -23.75487,17.6523 -13.11269,0 -23.75487,-4.53961 -23.75487,-17.6523 0,-13.11269 10.64218,-23.75487 23.75487,-23.75487 13.11269,0 23.75487,10.64218 23.75487,23.75487 z"
id="path1537"
sodipodi:nodetypes="csssc" />
<path
style="fill:#d38d5f;stroke:#502d16;stroke-width:2.16856"
d="m -146.94948,221.199 c 0,8.50553 -8.91642,12.68366 -19.90273,12.68366 -10.98631,0 -19.90273,-4.17813 -19.90273,-12.68366 0,-8.50553 8.91642,-9.95873 19.90273,-9.95873 10.98631,0 19.90273,1.4532 19.90273,9.95873 z"
id="path1539"
sodipodi:nodetypes="csssc" />
</g>
<g
style="display:inline;fill:#d38d5f;stroke:#502d16"
id="g1559"
transform="matrix(0.20847315,-0.03662954,0.03662954,0.20847315,-0.34176516,-0.20270665)">
<g
inkscape:label="Fond écu"
id="g1543"
style="fill:#d38d5f;stroke:#502d16" />
<g
style="opacity:1;fill:#d38d5f;stroke:#502d16"
inkscape:label="Meubles"
id="g1553">
<g
id="g1551"
transform="matrix(0.714908,0,0,0.756557,137.7704,128.4719)"
style="display:inline;fill:#d38d5f;fill-opacity:1;stroke:#502d16;stroke-width:2.71947;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<path
sodipodi:nodetypes="ccccc"
id="path1545"
d="m 160.08787,143.23938 39.92645,57.31251 39.53535,-57.31251 h -40.3837 z"
style="fill:#d38d5f;fill-opacity:1;fill-rule:evenodd;stroke:#502d16;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccccccccccccccccccc"
id="path1547"
d="m 193.20453,145.31745 c -24.41443,20.15923 -49.98749,37.33861 -73.2768,58.5917 -6.37089,11.43876 -4.50952,20.09512 9.2768,25.68955 14.75917,-16.92275 18.76874,-17.90421 41.38418,-46.03566 -22.42258,29.55858 -41.45116,42.84434 -41.29043,46.09816 5.38114,19.66042 0.98803,22.70493 25.28125,31.0625 2.90109,-14.41044 25.62687,-63.19056 32.51802,-70.81345 -6.73696,8.18151 -29.75646,56.59527 -32.58052,71.37595 18.94602,17.92 18.75832,19.45149 44.6875,14.03125 l 0.375,-80.91001 0.375,80.91001 c 21.42445,5.42024 29.31401,4.7897 44.65625,-14.03125 -3.59166,-13.24549 -25.62533,-59.96461 -31.64832,-69.57405 4.75359,7.7904 26.43091,52.99484 31.61707,69.01155 18.88754,-8.35757 21.70202,-8.69924 25.28125,-31.0625 -1.0235,-6.998 -18.88266,-18.38043 -42.22262,-45.81545 23.11839,25.66768 42.65103,40.10972 42.31637,45.75295 15.18653,-6.16263 15.88219,-19.26899 8.92398,-28.52504 -25.17844,-18.14393 -47.18822,-37.47898 -72.36824,-56.58981 0,0 -4.64225,-4.09784 -6.93074,-3.0414 z"
style="fill:#d38d5f;fill-opacity:1;fill-rule:evenodd;stroke:#502d16;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path1549"
d="m 168.24779,168.92114 c 23.13397,11.51861 44.28729,9.17267 64.46537,0"
style="fill:#d38d5f;fill-opacity:1;fill-rule:evenodd;stroke:#502d16;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<g
inkscape:label="Reflet final"
id="g1555"
style="fill:#d38d5f;stroke:#502d16" />
<g
inkscape:label="Contour final"
id="g1557"
style="fill:#d38d5f;stroke:#502d16" />
</g>
</g>
</clipPath>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="400"
inkscape:cy="560"
inkscape:document-units="mm"
inkscape:current-layer="svg878"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="2073"
inkscape:window-height="997"
inkscape:window-x="114"
inkscape:window-y="114"
inkscape:window-maximized="0" />
<metadata
id="metadata875">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="g1510"
style="fill:#784421;stroke:#ffffff;image-rendering:auto"
transform="translate(-1.0583648,-3.7366014)">
<g
inkscape:label="Clip"
id="g1726"
style="fill:#784421;stroke:#ffffff">
<g
id="g3257"
transform="matrix(0.28980934,0,0,0.21909426,120.56466,-12.741092)"
style="display:inline;fill:#784421;stroke:#ffffff;stroke-width:2.16856">
<path
sodipodi:nodetypes="cccccc"
id="rect3250"
d="m -174.5565,130.97253 h 15.40856 v 508.4827 l -7.70428,24 -7.70428,-24 z"
style="fill:#784421;stroke:#ffffff;stroke-width:2.16856" />
<path
transform="matrix(1.001146,0,0,0.893038,2.193524,15.82179)"
style="fill:#784421;stroke:#ffffff;stroke-width:2.29344"
d="m -145.09735,123.91028 c 0,13.11269 -10.64218,17.6523 -23.75487,17.6523 -13.11269,0 -23.75487,-4.53961 -23.75487,-17.6523 0,-13.11269 10.64218,-23.75487 23.75487,-23.75487 13.11269,0 23.75487,10.64218 23.75487,23.75487 z"
id="path3252"
sodipodi:nodetypes="csssc" />
<path
style="fill:#784421;stroke:#ffffff;stroke-width:2.16856"
d="m -146.94948,221.199 c 0,8.50553 -8.91642,12.68366 -19.90273,12.68366 -10.98631,0 -19.90273,-4.17813 -19.90273,-12.68366 0,-8.50553 8.91642,-9.95873 19.90273,-9.95873 10.98631,0 19.90273,1.4532 19.90273,9.95873 z"
id="path3254"
sodipodi:nodetypes="csssc" />
</g>
<g
style="display:inline;fill:#784421;stroke:#ffffff"
id="g2066"
transform="matrix(0.20847315,-0.03662954,0.03662954,0.20847315,-0.34176516,-0.20270665)">
<g
inkscape:label="Fond écu"
id="g2068"
style="fill:#784421;stroke:#ffffff" />
<g
style="opacity:1;fill:#784421;stroke:#ffffff"
inkscape:label="Meubles"
id="g2070">
<g
id="g4219"
transform="matrix(0.714908,0,0,0.756557,137.7704,128.4719)"
style="display:inline;fill:#784421;fill-opacity:1;stroke:#ffffff;stroke-width:2.71947;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<path
sodipodi:nodetypes="ccccc"
id="path4221"
d="m 160.08787,143.23938 39.92645,57.31251 39.53535,-57.31251 h -40.3837 z"
style="fill:#784421;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="ccccccccccccccccccccc"
id="path4223"
d="m 193.20453,145.31745 c -24.41443,20.15923 -49.98749,37.33861 -73.2768,58.5917 -6.37089,11.43876 -4.50952,20.09512 9.2768,25.68955 14.75917,-16.92275 18.76874,-17.90421 41.38418,-46.03566 -22.42258,29.55858 -41.45116,42.84434 -41.29043,46.09816 5.38114,19.66042 0.98803,22.70493 25.28125,31.0625 2.90109,-14.41044 25.62687,-63.19056 32.51802,-70.81345 -6.73696,8.18151 -29.75646,56.59527 -32.58052,71.37595 18.94602,17.92 18.75832,19.45149 44.6875,14.03125 l 0.375,-80.91001 0.375,80.91001 c 21.42445,5.42024 29.31401,4.7897 44.65625,-14.03125 -3.59166,-13.24549 -25.62533,-59.96461 -31.64832,-69.57405 4.75359,7.7904 26.43091,52.99484 31.61707,69.01155 18.88754,-8.35757 21.70202,-8.69924 25.28125,-31.0625 -1.0235,-6.998 -18.88266,-18.38043 -42.22262,-45.81545 23.11839,25.66768 42.65103,40.10972 42.31637,45.75295 15.18653,-6.16263 15.88219,-19.26899 8.92398,-28.52504 -25.17844,-18.14393 -47.18822,-37.47898 -72.36824,-56.58981 0,0 -4.64225,-4.09784 -6.93074,-3.0414 z"
style="fill:#784421;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
id="path4225"
d="m 168.24779,168.92114 c 23.13397,11.51861 44.28729,9.17267 64.46537,0"
style="fill:#784421;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2.71947;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
<g
inkscape:label="Reflet final"
id="g2076"
style="fill:#784421;stroke:#ffffff" />
<g
inkscape:label="Contour final"
id="g2078"
style="fill:#784421;stroke:#ffffff" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

58
icons/tmr/scroll.svg Normal file
View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 511.999 511.999" style="enable-background:new 0 0 511.999 511.999;" xml:space="preserve">
<path style="fill:#CCAC68;" d="M145.179,371.239H95.282c-35.205,0-63.745,28.539-63.745,63.745l0,0
c0,35.205,28.539,63.745,63.745,63.745H266.31v-93.993L145.179,371.239z"/>
<path style="fill:#E6C275;" d="M356.848,140.762L154.642,13.272H90.44l0,0c-60.783,0-99.78,64.617-71.453,118.395l138.469,262.878
h-0.022c25.403,47.058-8.675,104.182-62.152,104.182h336.415c53.477,0,87.555-57.123,62.152-104.182L356.848,140.762z"/>
<path style="fill:#FFD782;" d="M90.44,13.272c35.205,0,63.745,28.54,63.745,63.745l0,0c0,35.205-28.54,63.745-63.745,63.745h266.408
c35.205,0,63.745-28.54,63.745-63.745l0,0c0-35.205-28.54-63.745-63.745-63.745C356.848,13.272,90.44,13.272,90.44,13.272z"/>
<path d="M342.963,489.153c0,0-195.544,0-195.559,0c1.764,0,6.043-5.742,7.172-6.989c17.747-19.618,25.167-48.132,18.443-73.982
c-2.737-10.522-8.091-19.987-13.121-29.534L27.455,127.206C15.728,104.945,16.489,78.792,29.49,57.25
c13.001-21.543,35.785-34.403,60.947-34.403c29.869,0,54.17,24.3,54.17,54.17s-24.3,54.17-54.17,54.17
c-5.289,0-9.575,4.286-9.575,9.576c0,5.289,4.286,9.575,9.575,9.575h260.695l31.745,58.803c2.512,4.655,8.318,6.387,12.973,3.877
c4.655-2.512,6.389-8.321,3.877-12.973l-27.694-51.301c33.163-7.016,58.129-36.507,58.129-71.729c0-40.429-32.892-73.32-73.32-73.32
H240.78c-5.289,0-9.575,4.286-9.575,9.575s4.286,9.575,9.575,9.575h116.063c29.869,0,54.17,24.3,54.17,54.17
c0,29.866-24.293,54.164-54.17,54.17H139.796c0.919-0.839,1.818-1.7,2.694-2.584c13.491-13.615,21.266-32.414,21.266-51.587
c0-20.045-8.544-39.648-23.128-53.374c-0.28-0.263-0.546-0.537-0.83-0.797h56.304c5.289,0,9.575-4.286,9.575-9.575
s-4.286-9.575-9.575-9.575c0,0-105.664,0-105.665,0c-31.931,0-60.842,16.32-77.341,43.658
c-16.498,27.337-17.463,60.524-2.581,88.774l118.798,225.535H95.277c-40.428,0-73.32,32.891-73.32,73.32s32.892,73.32,73.32,73.32
c0.027,0,0.052-0.001,0.078-0.001h247.609c5.289,0,9.575-4.286,9.575-9.575S348.252,489.153,342.963,489.153z M41.107,434.984
c0-29.869,24.3-54.17,54.17-54.17h44.118c3.82,7.251,8.046,14.427,11.417,21.9c3.922,8.533,5.779,17.635,5.584,26.694
c-0.706,32.866-28.393,59.744-61.136,59.744C65.399,489.146,41.107,464.848,41.107,434.984z"/>
<path d="M502.27,389.999l-78.422-145.272c-2.514-4.655-8.322-6.389-12.973-3.877c-4.655,2.512-6.389,8.321-3.877,12.973
l78.423,145.272c10.312,19.103,9.829,41.639-1.293,60.283c-11.123,18.645-30.724,29.776-52.434,29.776h-44.048
c-5.289,0-9.575,4.286-9.575,9.575s4.286,9.575,9.575,9.575h44.048c28.52,0,54.269-14.622,68.88-39.114
C515.184,444.697,515.818,415.093,502.27,389.999z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 496 496" style="enable-background:new 0 0 496 496;" xml:space="preserve">
<path style="fill:#5B402E;" d="M0,232v167.2C0,460.8,52,456,113.6,456h268c61.6,0,113.6,4.8,113.6-56.8V232H0z"/>
<path style="fill:#493322;" d="M112,456h270.4c61.6,0,113.6,4.8,113.6-56.8V232"/>
<path style="fill:#5B402E;" d="M496,192v-40c0-61.6-52-112-113.6-112H113.6C52,40,0,90.4,0,152v40H496z"/>
<path style="fill:#493322;" d="M0,152v40h496v-40c0-61.6-52-112-113.6-112"/>
<rect y="232" style="fill:#F2B111;" width="496" height="64"/>
<polyline style="fill:#E88813;" points="0,296 496,296 496,232 "/>
<rect y="152" style="fill:#F2B111;" width="496" height="40"/>
<g>
<polyline style="fill:#E88813;" points="0,192 496,192 496,152 "/>
<rect x="104" y="32" style="fill:#E88813;" width="56" height="152"/>
<rect x="336" y="32" style="fill:#E88813;" width="56" height="152"/>
<rect x="104" y="288" style="fill:#E88813;" width="56" height="176"/>
<rect x="336" y="288" style="fill:#E88813;" width="56" height="176"/>
</g>
<g>
<circle style="fill:#493322;" cx="184" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="226.4" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="269.6" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="312" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="33.6" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="75.2" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="420" cy="264.8" r="8.8"/>
<circle style="fill:#493322;" cx="462.4" cy="264.8" r="8.8"/>
</g>
<path style="fill:#F2B111;" d="M276,346.4c0-15.2-12.8-28-28-28s-28,12.8-28,28c0,10.4,5.6,20,13.6,25.6l-8,52h44.8l-8-52
C270.4,367.2,276,356.8,276,346.4z"/>
<path style="fill:#E88813;" d="M270.4,424l-8-52c8-4.8,13.6-15.2,13.6-25.6c0-15.2-12.8-28-28-28s-28,12.8-28,28"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

94
icons/tmr/wave.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -1,44 +0,0 @@
{
"ACTOR": {
"TypePersonnage": "Personnage",
"TypeCreature": "Créature",
"TypeEntite": "Entité de cauchemar",
"TypeVehicule": "Véhicule"
},
"ITEM": {
"TypeObjet": "Objet",
"TypeCompetence": "Compétence",
"TypeCompetencecreature": "Compétence de créature",
"TypeMaladie": "Maladie",
"TypePoison": "Poison",
"TypeNombreastral": "Nombre astral",
"TypeTarot": "Carte de tarot",
"TypeCasetmr": "TMR spéciale",
"TypeRencontrestmr": "Rencontre TMR",
"TypeMunition": "Munition",
"TypeMonnaie": "Monnaie",
"TypeHerbe": "Herbe ou plante",
"TypeIngredient": "Ingrédient",
"TypeLivre": "Livre",
"TypePotion": "Potion",
"TypeArme": "Arme",
"TypeArmure": "Armure",
"TypeConteneur": "Conteneur",
"TypeNourritureboisson": "Nourriture & boisson",
"TypeChant": "Chant",
"TypeDanse": "Danse",
"TypeMusique": "Musique",
"TypeOeuvre": "Oeuvre",
"TypeTache": "Tâche",
"TypeJeu": "Jeu",
"TypeRecettealchimique": "Recette alchimique",
"TypeRecettecuisine": "Recette de cuisine",
"TypeSort": "Sort",
"TypeMeditation": "Méditation",
"TypeSignedraconique": "Signe draconique",
"TypeQueue": "Queue de Dragon",
"TypeOmbre": "Ombre de Thanatos",
"TypeSouffle": "Souffle de Dragon",
"TypeTete": "Tête de Dragon"
}
}

View File

@ -35,10 +35,12 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
}
formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : "";
formData.options.isGM = game.user.isGM;
formData.data.competencecreature = formData.itemsByType["competencecreature"];
RdDUtility.filterItemsPerTypeForSheet(formData);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
RdDUtility.buildArbreDeConteneur(this, formData);
console.log("Creature : ", this.objetVersConteneur, formData);
@ -70,6 +72,17 @@ export class RdDActorCreatureSheet extends RdDActorSheet {
});
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) {

View File

@ -5,7 +5,6 @@
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
export class RdDActorEntiteSheet extends ActorSheet {
@ -32,27 +31,14 @@ export class RdDActorEntiteSheet extends ActorSheet {
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
// actor: this.object,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
// items: items,
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
let formData = super.getData();
formData.itemsByType = Misc.classify(formData.items);
formData.options.isGM = game.user.isGM;
RdDUtility.filterItemsPerTypeForSheet(formData);
formData.data.carac.taille.isTaille = true; // To avoid button link;
formData.data.competencecreature = formData.itemsByType["competencecreature"];
return formData;
@ -71,14 +57,14 @@ export class RdDActorEntiteSheet extends ActorSheet {
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
const item = this.actor.getOwnedItem(li.data("itemId"));
item.sheet.render(true);
});
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.deleteEmbeddedDocuments('Item', [li.data("itemId")]);
this.actor.deleteOwnedItem(li.data("itemId"));
li.slideUp(200, () => this.render(false));
});
@ -117,7 +103,7 @@ export class RdDActorEntiteSheet extends ActorSheet {
this.render(true);
});
html.find('.encaisser-direct').click(ev => {
html.find('#encaisser-direct').click(ev => {
this.actor.encaisser();
});
@ -132,12 +118,10 @@ export class RdDActorEntiteSheet extends ActorSheet {
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
setPosition(options={}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}

View File

@ -11,9 +11,6 @@ import { RdDBonus } from "./rdd-bonus.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDItem } from "./item.js";
import { DialogSplitItem } from "./dialog-split-item.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/* -------------------------------------------- */
export class RdDActorSheet extends ActorSheet {
@ -30,55 +27,60 @@ export class RdDActorSheet extends ActorSheet {
dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
editCaracComp: false,
showCompNiveauBase: false,
montrerArchetype: false,
hideControls: true
montrerArchetype: false
});
}
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
//this.actor.checkMonnaiePresence(this.actor.data.items); // Always check
let formData = super.getData();
// -------------- version 0.7.9
// let formData = {
// cssClass: this.entity.owner ? "editable" : "locked",
// editable: this.isEditable,
// entity: duplicate(this.entity.data),
// limited: this.entity.limited,
// options: this.options,
// owner: this.entity.owner,
// title: this.title
// }
// // Entity data
// formData.actor = formData.entity;
// formData.data = formData.entity.data;
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
// // Owned items
// formData.items = formData.actor.items;
// formData.items.sort((a, b) => (a.sort || 0) - (b.sort || 0));
formData.itemsByType = Misc.classify(formData.items);
RdDUtility.filterItemsPerTypeForSheet(formData);
formData.options.isGM = game.user.isGM;
if (formData.type == 'creature') return formData; // Shortcut
// la taille est la taille: on ne peut pas l'utiliser pour un jet
formData.data.carac.taille.isTaille = true;
formData.competenceByCategory = Misc.classify(formData.competences, it => it.data.categorie);
if (this.actor.data.type == 'creature') return formData; // Shortcut
formData.competenceByCategory = Misc.classify(formData.data.competences, it => it.data.categorie);
formData.calc = {
comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.competences),
competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.competences),
comptageArchetype: RdDItemCompetence.computeResumeArchetype(formData.data.competences),
competenceXPTotal: RdDItemCompetence.computeTotalXP(formData.data.competences),
caracTotal: RdDCarac.computeTotal(formData.data.carac, formData.data.beaute),
// Mise à jour de l'encombrement total et du prix de l'équipement
encTotal: await this.actor.computeEncombrementTotalEtMalusArmure(),
prixTotalEquipement: this.actor.computePrixTotalEquipement(),
prixTotalEquipement: await this.actor.computePrixTotalEquipement(),
surprise: RdDBonus.find(this.actor.getSurprise(false)).descr,
fatigue: RdDUtility.calculFatigueHtml(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
fatigue: {
malus: RdDUtility.calculMalusFatigue(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(formData.data.sante.fatigue.value, formData.data.sante.endurance.max).html() + "</table>"
},
resumeBlessures: this.actor.computeResumeBlessure(formData.data.blessures),
};
formData.calc.surEncombrementMessage = (formData.data.compteurs.surenc.value < 0) ? "Sur-Encombrement!" : "";
formData.competences.forEach(item => {
formData.data.competences.forEach(item => {
item.visible = !this.options.showCompNiveauBase || !RdDItemCompetence.isNiveauBase(item);
RdDItemCompetence.levelUp(item);
});
@ -89,29 +91,36 @@ export class RdDActorSheet extends ActorSheet {
// toujours avoir une liste d'armes (pour mettre esquive et corps à corps)
formData.combat = duplicate(formData.armes ?? []);
RdDItemArme.computeNiveauArmes(formData.combat, formData.competences);
RdDItemArme.ajoutCorpsACorps(formData.combat, formData.competences, formData.data.carac);
formData.esquive = RdDItemCompetence.getEsquive(formData.competences);
formData.combat = RdDCombatManager.finalizeArmeList(formData.combat, formData.competences, formData.data.carac);
formData.data.combat = duplicate(formData.itemsByType.arme ?? []);
RdDItemArme.computeNiveauArmes(formData.data.combat, formData.data.competences);
RdDItemArme.ajoutCorpsACorps(formData.data.combat, formData.data.competences, formData.data.carac );
formData.esquive = RdDItemCompetence.getEsquive(formData.data.competences);
formData.data.combat = RdDCombatManager.finalizeArmeList(formData.data.combat, formData.itemsByType.competence, formData.data.carac);
this.armesList = formData.combat;
this.armesList = formData.data.combat;
// Mise à jour de l'encombrement total et du prix de l'équipement
// Common data
formData.data.competenceByCategory = formData.competenceByCategory;
formData.data.isGM = game.user.isGM;
formData.ajustementsConditions = CONFIG.RDD.ajustementsConditions;
formData.difficultesLibres = CONFIG.RDD.difficultesLibres;
formData.hautreve = {
isDemiReve: this.actor.listeEffets( it => it.label == "Demi-rêve").length > 0,
sortsReserve: formData.data.reve.reserve.list,
rencontres: duplicate(formData.data.reve.rencontre.list),
casesTmr: formData.itemsByType.casetmr,
cacheTMR: this.actor.isTMRCache()
// low is normal, this the base used to compute the grid.
formData.data.fatigue = {
malus: RdDUtility.calculMalusFatigue(formData.data.sante.fatigue.value, formData.data.sante.endurance.max),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(formData.data.sante.fatigue.value, formData.data.sante.endurance.max).html() + "</table>"
}
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
formData.hautreve = {
sortsReserve: formData.data.reve.reserve.list,
rencontres: duplicate(formData.data.reve.rencontre.list),
casesTmr: formData.itemsByType.casetmr
}
RdDUtility.buildArbreDeConteneur(this, formData);
formData.subacteurs = {
vehicules: this.actor.listeVehicules(),
montures: this.actor.listeMontures(),
@ -129,196 +138,221 @@ export class RdDActorSheet extends ActorSheet {
}
/* -------------------------------------------- */
async _onDropActor(event, dragData) {
console.log("DRAG", this.actor.id, dragData);
this.actor.addSubacteur(dragData.id || dragData.data._id);
super._onDropActor(event, dragData);
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const callSuper = await this.actor.processDropItem(event, dragData, this.objetVersConteneur);
if (callSuper) {
await super._onDropItem(event, dragData)
async _onDrop(event) {
let toSuper = await RdDUtility.processItemDropEvent(this, event);
if (toSuper) {
super._onDrop(event);
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
async createEmptyTache() {
await this.actor.createOwnedItem({ name: 'Nouvelle tache', type: 'tache' }, { renderSheet: true });
}
/* -------------------------------------------- */
async createEmptyTache() {
await this.createItem('Nouvelle tache', 'tache');
async creerObjet() {
let itemType = $(".item-type").val();
await this.actor.createOwnedItem({ name: 'Nouveau ' + itemType, type: itemType }, { renderSheet: true });
}
/* -------------------------------------------- */ /** @override */
/* -------------------------------------------- */
async selectObjetType() {
let typeObjets = ["objet", "arme", "armure", "conteneur", "herbe", "ingredient", "livre", "potion", "munition", "monnaie"];
let options = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of typeObjets) {
options += `<option value="${typeName}">${typeName}</option>`
}
options += '</select>';
let d = new Dialog({
title: "Créer un équipement",
content: options,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'objet",
callback: () => this.creerObjet()
}
}
});
d.render(true);
}
/* -------------------------------------------- */
async selectTypeOeuvre() {
let typeOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu" ];
let options = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of typeOeuvres) {
options += `<option value="${typeName}">${typeName}</option>`
}
options += '</select>';
let d = new Dialog({
title: "Créer une oeuvre",
content: options,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'oeuvre",
callback: () => this.creerObjet()
}
}
});
d.render(true);
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
html.find('#show-hide-competences').click((event) => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true);
});
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
html.find('.item-split').click(async event => {
const li = $(event.currentTarget).parents(".item");
const item = this.actor.items.get(li.data("item-id"));
this.splitItem(item);
});
html.find('.item-edit').click(async event => {
const li = $(event.currentTarget).parents(".item");
const item = this.actor.items.get(li.data("item-id"));
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getOwnedItem(li.data("item-id"));
item.sheet.render(true);
});
html.find('.display-label a').click(async event => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getEmbeddedDocument('Item', myID);
item.sheet.render(true);
});
html.find('.rencontre-delete').click(async event => {
const li = $(event.currentTarget).parents(".item");
// Update Inventory Item
html.find('.rencontre-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const rencontreKey = li.data("item-id");
this.actor.deleteTMRRencontre(rencontreKey);
});
html.find('.item-delete').click(async event => {
const li = $(event.currentTarget).parents(".item");
// Delete Inventory Item
html.find('.item-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
RdDUtility.confirmerSuppression(this, li);
});
html.find('.item-vendre').click(async event => {
const li = $(event.currentTarget).parents(".item");
const itemId = li.data("item-id");
const item = this.actor.getObjet(itemId);
item?.proposerVente();
});
html.find('.item-action').click(async event => {
const li = $(event.currentTarget).parents(".item");
const itemId = li.data("item-id");
const item = this.actor.getObjet(itemId);
this.actor.actionItem(item);
});
html.find('.subacteur-delete').click(async event => {
const li = $(event.currentTarget).parents(".item");
html.find('.subacteur-delete').click(ev => {
const li = $(ev.currentTarget).parents(".item");
RdDUtility.confirmerSuppressionSubacteur(this, li);
});
html.find('.encaisser-direct').click(async event => {
html.find('#encaisser-direct').click(ev => {
this.actor.encaisser();
});
html.find('.remise-a-neuf').click(async event => {
html.find('.remise-a-neuf').click(ev => {
if (game.user.isGM) {
this.actor.remiseANeuf();
ev.preventDefault();
}
});
html.find('.creer-tache').click(async event => {
html.find('.creer-tache').click(ev => {
this.createEmptyTache();
});
html.find('.creer-un-objet').click(async event => {
RdDUtility.selectObjetType( this );
html.find('.creer-un-objet').click(ev => {
this.selectObjetType();
});
html.find('.creer-une-oeuvre').click(async event => {
RdDUtility.selectTypeOeuvre(this);
html.find('.creer-une-oeuvre').click(ev => {
this.selectTypeOeuvre();
});
html.find('#nettoyer-conteneurs').click(async event => {
html.find('#nettoyer-conteneurs').click(ev => {
this.actor.nettoyerConteneurs();
});
// Blessure control
html.find('.blessure-control').click(async event => {
const tr = $(event.currentTarget).parents(".item");
let btype = tr.data("blessure-type");
let index = tr.data('blessure-index');
let active = $(event.currentTarget).data('blessure-active');
html.find('.blessure-control').click(ev => {
const li = $(ev.currentTarget).parents(".item");
let btype = li.data("blessure-type");
let index = li.data('blessure-index');
let active = $(ev.currentTarget).data('blessure-active');
//console.log(btype, index, active);
await this.actor.manageBlessureFromSheet(btype, index, active);
this.actor.manageBlessureFromSheet(btype, index, active).then(this.render(true));
});
// Blessure data
html.find('.blessures-soins').change(async event => {
const tr = $(event.currentTarget).parents(".item");
let btype = tr.data('blessure-type');
let index = tr.data('blessure-index');
let psoins = tr.find('.blessure-premiers_soins').val();
let pcomplets = tr.find('.blessure-soins_complets').val();
let jours = tr.find('.blessure-jours').val();
let loc = tr.find('.blessure-localisation').val();
html.find('.blessures-soins').change(ev => {
const li = $(ev.currentTarget).parents(".item");
let btype = li.data('blessure-type');
let index = li.data('blessure-index');
let psoins = li.find('input[name=premiers_soins]').val();
let pcomplets = li.find('input[name=soins_complets]').val();
let jours = li.find('input[name=jours]').val();
let loc = li.find('input[name=localisation]').val();
//console.log(btype, index, psoins, pcomplets, jours, loc);
await this.actor.setDataBlessureFromSheet(btype, index, psoins, pcomplets, jours, loc);
this.actor.setDataBlessureFromSheet(btype, index, psoins, pcomplets, jours, loc).then(this.render(true));
});
// Equip Inventory Item
html.find('.item-equip').click(async event => {
const li = $(event.currentTarget).parents(".item");
html.find('.item-equip').click(ev => {
const li = $(ev.currentTarget).parents(".item");
this.actor.equiperObjet(li.data("item-id"));
this.render(true);
});
// Roll Carac
html.find('.carac-label a').click(async event => {
html.find('.carac-label a').click((event) => {
let caracName = event.currentTarget.attributes.name.value;
this.actor.rollCarac(caracName.toLowerCase());
});
html.find('.chance-actuelle').click(async event => {
html.find('.chance-actuelle').click((event) => {
this.actor.rollCarac('chance-actuelle');
});
html.find('.chance-appel').click(async event => {
html.find('.chance-appel').click((event) => {
this.actor.rollAppelChance();
});
html.find('#jet-astrologie').click(async event => {
html.find('#jet-astrologie').click((event) => {
this.actor.astrologieNombresAstraux();
});
// Roll Skill
html.find('a.competence-label').click(async event => {
let compName = event.currentTarget.name;
html.find('.competence-label a').click((event) => {
let compName = event.currentTarget.text;
this.actor.rollCompetence(compName);
});
html.find('.tache-label a').click(async event => {
html.find('.tache-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let tacheId = li.data('item-id');
this.actor.rollTache(tacheId);
});
html.find('.meditation-label a').click(async event => {
html.find('.meditation-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let meditationId = li.data('item-id');
this.actor.rollMeditation(meditationId);
});
html.find('.chant-label a').click(async event => {
html.find('.chant-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let chantId = li.data('item-id');
this.actor.rollChant(chantId);
});
html.find('.danse-label a').click(async event => {
html.find('.danse-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let danseId = li.data('item-id');
this.actor.rollDanse(danseId);
});
html.find('.musique-label a').click(async event => {
html.find('.musique-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let musiqueId = li.data('item-id');
this.actor.rollMusique(musiqueId);
});
html.find('.oeuvre-label a').click(async event => {
html.find('.oeuvre-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let oeuvreId = li.data('item-id');
this.actor.rollOeuvre(oeuvreId);
});
html.find('.jeu-label a').click(async event => {
html.find('.jeu-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let jeuId = li.data('item-id');
this.actor.rollJeu(jeuId);
});
html.find('.recettecuisine-label a').click(async event => {
html.find('.recettecuisine-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let recetteId = li.data('item-id');
this.actor.rollRecetteCuisine(recetteId);
});
html.find('.subacteur-label a').click(async event => {
html.find('.subacteur-label a').click((event) => {
const li = $(event.currentTarget).parents(".item");
let actorId = li.data('actor-id');
let actor = game.actors.get(actorId);
@ -326,28 +360,20 @@ export class RdDActorSheet extends ActorSheet {
actor.sheet.render(true);
}
});
// Boutons spéciaux MJs
html.find('.forcer-tmr-aleatoire').click(async event => {
this.actor.cacheTMRetMessage();
});
html.find('.afficher-tmr').click(async event => {
this.actor.afficheTMRetMessage();
});
// Points de reve actuel
html.find('.ptreve-actuel a').click(async event => {
html.find('.ptreve-actuel a').click((event) => {
this.actor.rollCarac('reve-actuel');
});
// Roll Weapon1
html.find('.arme-label a').click(async event => {
html.find('.arme-label a').click((event) => {
let armeName = event.currentTarget.text;
let competenceName = event.currentTarget.attributes['data-competence-name'].value;
this.actor.rollArme(competenceName, armeName);
});
// Initiative pour l'arme
html.find('.arme-initiative a').click(async event => {
html.find('.arme-initiative a').click((event) => {
let combatant = game.combat.data.combatants.find(c => c.actor.data._id == this.actor.data._id);
if (combatant) {
let armeName = event.currentTarget.attributes['data-arme-name'].value;
@ -358,178 +384,201 @@ export class RdDActorSheet extends ActorSheet {
}
});
// Display TMR, visuualisation
html.find('.visu-tmr').click(async event => {
html.find('#visu-tmr').click((event) => {
this.actor.displayTMR("visu");
});
// Display TMR, normal
html.find('.monte-tmr').click(async event => {
html.find('#monte-tmr').click((event) => {
this.actor.displayTMR("normal");
});
// Display TMR, fast
html.find('.monte-tmr-rapide').click(async event => {
html.find('#monte-tmr-rapide').click((event) => {
this.actor.displayTMR("rapide");
});
html.find('.dormir-une-heure').click(async event => {
html.find('#dormir-une-heure').click((event) => {
this.actor.dormir(1);
});
html.find('.dormir-chateau-dormant').click(async event => {
html.find('#dormir-chateau-dormant').click((event) => {
this.actor.dormirChateauDormant();
});
html.find('.enlever-tous-effets').click(async event => {
html.find('#enlever-tous-effets').click((event) => {
this.actor.enleverTousLesEffets();
});
html.find('.conteneur-name a').click(async event => {
// Display info about queue
html.find('.queuesouffle-label a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Info sort
html.find('.sort-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Info sort
html.find('.case-label a').click((event) => {
let myID = event.currentTarget.attributes['data-id'].value;
const item = this.actor.getOwnedItem(myID);
item.sheet.render(true);
});
// Display info about queue
html.find('.conteneur-name a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
RdDUtility.toggleAfficheContenu(myID);
this.render(true);
});
html.find('.carac-xp-augmenter').click(async event => {
let caracName = event.currentTarget.name.replace("augmenter.", "");
this.actor.updateCaracXPAuto(caracName);
});
html.find('.competence-xp-augmenter').click(async event => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXPAuto(compName);
});
if (this.options.editCaracComp) {
// On carac change
html.find('.carac-value').change(async event => {
html.find('.carac-value').change((event) => {
let caracName = event.currentTarget.name.replace(".value", "").replace("data.carac.", "");
//console.log("Value changed :", event, caracName);
this.actor.updateCarac(caracName, parseInt(event.target.value));
});
html.find('.carac-xp').change(async event => {
html.find('.carac-xp').change((event) => {
let caracName = event.currentTarget.name.replace(".xp", "").replace("data.carac.", "");
//console.log("Value changed :", event, caracName);
this.actor.updateCaracXP(caracName, parseInt(event.target.value));
});
// On competence change
html.find('.competence-value').change(async event => {
html.find('.competence-value').change((event) => {
let compName = event.currentTarget.attributes.compname.value;
//console.log("Competence changed :", compName);
this.actor.updateCompetence(compName, parseInt(event.target.value));
});
// On competence xp change
html.find('.competence-xp').change(async event => {
html.find('.competence-xp').change((event) => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXP(compName, parseInt(event.target.value));
});
// On competence xp change
html.find('.competence-xp-sort').change(async event => {
html.find('.competence-xp-sort').change((event) => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceXPSort(compName, parseInt(event.target.value));
});
// On competence archetype change
html.find('.competence-archetype').change(async event => {
html.find('.competence-archetype').change((event) => {
let compName = event.currentTarget.attributes.compname.value;
this.actor.updateCompetenceArchetype(compName, parseInt(event.target.value));
});
}
html.find('#show-hide-competences').click(async event => {
this.options.showCompNiveauBase = !this.options.showCompNiveauBase;
this.render(true);
});
html.find('.lock-unlock-sheet').click(async event => {
// Gestion du bouton lock/unlock
html.find('.lock-unlock-sheet').click((event) => {
this.options.editCaracComp = !this.options.editCaracComp;
this.render(true);
});
html.find('#show-hide-archetype').click(async event => {
html.find('#show-hide-archetype').click((event) => {
this.options.montrerArchetype = !this.options.montrerArchetype;
this.render(true);
});
html.find('.lock-unlock-controls').click(async event => {
this.options.hideControls = !this.options.hideControls;
this.render(true);
});
// On pts de reve change
html.find('.pointsreve-value').change(async event => {
html.find('.pointsreve-value').change((event) => {
let reveValue = event.currentTarget.value;
this.actor.update({ "data.reve.reve.value": reveValue });
});
// On seuil de reve change
html.find('.seuil-reve-value').change(async event => {
html.find('.seuil-reve-value').change((event) => {
console.log("seuil-reve-value", event.currentTarget)
this.actor.setPointsDeSeuil(event.currentTarget.value);
});
html.find('#attribut-protection-edit').change(async event => {
html.find('#attribut-protection-edit').change((event) => {
this.actor.updateAttributeValue(event.currentTarget.attributes.name.value, parseInt(event.target.value));
});
// On stress change
html.find('.compteur-edit').change(async event => {
html.find('.compteur-edit').change((event) => {
let fieldName = event.currentTarget.attributes.name.value;
this.actor.updateCompteurValue(fieldName, parseInt(event.target.value));
});
html.find('#ethylisme').change(async event => {
html.find('#ethylisme').change((event) => {
this.actor.setEthylisme(parseInt(event.target.value));
});
html.find('.stress-test').click(async event => {
html.find('.stress-test').click((event) => {
this.actor.transformerStress();
this.render(true);
});
html.find('.moral-malheureux').click(async event => {
html.find('.moral-malheureux').click((event) => {
this.actor.jetDeMoral('malheureuse');
this.render(true);
});
html.find('.moral-neutre').click(async event => {
html.find('.moral-neutre').click((event) => {
this.actor.jetDeMoral('neutre');
this.render(true);
});
html.find('.moral-heureux').click(async event => {
html.find('.moral-heureux').click((event) => {
this.actor.jetDeMoral('heureuse');
this.render(true);
});
html.find('#ethylisme-test').click(async event => {
this.actor.jetEthylisme();
html.find('#ethylisme-test').click((event) => {
this.actor.ethylismeTest();
this.render(true);
});
html.find('#jet-vie').click(async event => {
html.find('#jet-vie').click((event) => {
this.actor.jetVie();
this.render(true);
});
html.find('#jet-endurance').click(async event => {
html.find('#jet-endurance').click((event) => {
this.actor.jetEndurance();
this.render(true);
});
html.find('.monnaie-plus').click(async event => {
html.find('.monnaie-plus').click((event) => {
const li = $(event.currentTarget).parents(".item");
this.actor.monnaieIncDec(li.data("item-id"), 1);
this.render(true);
});
html.find('.monnaie-moins').click(async event => {
html.find('.monnaie-moins').click((event) => {
const li = $(event.currentTarget).parents(".item");
this.actor.monnaieIncDec(li.data("item-id"), -1);
this.render(true);
});
html.find('#vie-plus').click(async event => {
html.find('#vie-plus').click((event) => {
this.actor.santeIncDec("vie", 1);
this.render(true);
});
html.find('#vie-moins').click(async event => {
html.find('#vie-moins').click((event) => {
this.actor.santeIncDec("vie", -1);
this.render(true);
});
html.find('#endurance-plus').click(async event => {
html.find('#endurance-plus').click((event) => {
this.actor.santeIncDec("endurance", 1);
this.render(true);
});
html.find('#endurance-moins').click(async event => {
html.find('#endurance-moins').click((event) => {
this.actor.santeIncDec("endurance", -1);
this.render(true);
});
html.find('.data-sante-sonne').click(async event => {
html.find('.data-sante-sonne').click((event) => {
this.actor.setSonne(event.currentTarget.checked);
this.render(true);
});
html.find('#ptreve-actuel-plus').click(async event => {
html.find('#ptreve-actuel-plus').click((event) => {
this.actor.reveActuelIncDec(1);
this.render(true);
});
html.find('#ptreve-actuel-moins').click(async event => {
html.find('#ptreve-actuel-moins').click((event) => {
this.actor.reveActuelIncDec(-1);
this.render(true);
});
html.find('#fatigue-plus').click(async event => {
html.find('#fatigue-plus').click((event) => {
this.actor.santeIncDec("fatigue", 1);
this.render(true);
});
html.find('#fatigue-moins').click(async event => {
html.find('#fatigue-moins').click((event) => {
this.actor.santeIncDec("fatigue", -1);
this.render(true);
});
}
@ -538,10 +587,8 @@ export class RdDActorSheet extends ActorSheet {
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
@ -553,19 +600,4 @@ export class RdDActorSheet extends ActorSheet {
// Update the Actor
return this.object.update(formData);
}
async splitItem(item) {
const dialog = await DialogSplitItem.create(item, (item, split) => this._onSplitItem(item, split));
dialog.render(true);
}
async _onSplitItem(item, split) {
if (split >= 1 && split < Misc.data(item).data.quantite) {
await item.diminuerQuantite(split);
const itemData = duplicate( Misc.data(item));
itemData.data.quantite = split;
await this.actor.createEmbeddedDocuments('Item', [itemData])
}
}
}

View File

@ -34,26 +34,12 @@ export class RdDActorVehiculeSheet extends ActorSheet {
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
let formData = {
title: this.title,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
data: foundry.utils.deepClone(Misc.templateData(this.object)),
effects: this.object.effects.map(e => foundry.utils.deepClone(e.data)),
limited: this.object.limited,
options: this.options,
owner: this.document.isOwner,
itemsByType: Misc.classify(this.object.items.map(i => foundry.utils.deepClone(i.data))),
};
let formData = super.getData();
formData.itemsByType = Misc.classify(formData.items);
RdDUtility.filterItemsPerTypeForSheet(formData);
this.objetVersConteneur = RdDUtility.buildArbreDeConteneurs(formData.conteneurs, formData.objets);
formData.conteneurs = RdDUtility.conteneursRacine(formData.conteneurs);
RdDUtility.buildArbreDeConteneur(this, formData);
formData.options.isGM = game.user.isGM;
@ -68,24 +54,10 @@ export class RdDActorVehiculeSheet extends ActorSheet {
}
/* -------------------------------------------- */
async _onDropItem(event, dragData) {
const callSuper = await this.actor.processDropItem(event, dragData, this.objetVersConteneur);
if (callSuper) {
await super._onDropItem(event, dragData)
}
}
/* -------------------------------------------- */
async createItem(name, type) {
await this.actor.createEmbeddedDocuments('Item', [{ name: name, type: type }], { renderSheet: true });
}
/* -------------------------------------------- */
async monnaieIncDec(id, value) {
let monnaie = this.getMonnaie(id);
if (monnaie) {
const quantite = Math.max(0, Misc.templateData(monnaie).quantite + value);
await this.updateEmbeddedDocuments('Item', [{ _id: monnaie.id, 'data.quantite': quantite }]);
async _onDrop(event) {
let toSuper = await RdDUtility.processItemDropEvent(this, event);
if ( toSuper) {
super._onDrop(event);
}
}
@ -102,7 +74,7 @@ export class RdDActorVehiculeSheet extends ActorSheet {
// Update Inventory Item
html.find('.item-edit').click(ev => {
const li = $(ev.currentTarget).parents(".item");
const item = this.actor.getEmbeddedDocument('Item', li.data("itemId"));
const item = this.actor.getOwnedItem(li.data("itemId"));
item.sheet.render(true);
});
// Delete Inventory Item
@ -111,22 +83,6 @@ export class RdDActorVehiculeSheet extends ActorSheet {
RdDUtility.confirmerSuppression(this, li);
});
html.find('.creer-un-objet').click(async event => {
RdDUtility.selectObjetType( this );
});
html.find('#nettoyer-conteneurs').click(async event => {
this.actor.nettoyerConteneurs();
});
html.find('.monnaie-plus').click(async event => {
const li = $(event.currentTarget).parents(".item");
this.actor.monnaieIncDec(li.data("item-id"), 1);
});
html.find('.monnaie-moins').click(async event => {
const li = $(event.currentTarget).parents(".item");
this.actor.monnaieIncDec(li.data("item-id"), -1);
});
// Display info about queue
html.find('.conteneur-name a').click((event) => {
let myID = event.currentTarget.attributes['data-item-id'].value;
@ -138,12 +94,10 @@ export class RdDActorVehiculeSheet extends ActorSheet {
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
setPosition(options={}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetTabs = this.element.find(".sheet-tabs");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight - sheetTabs[0].clientHeight;
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}

File diff suppressed because it is too large Load Diff

View File

@ -8,40 +8,27 @@ export class ChatUtility {
/* -------------------------------------------- */
static onSocketMessage(sockmsg) {
switch (sockmsg.msg) {
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.data);
case "msg_delete_chat_message": return ChatUtility.onRemoveMessages(sockmsg.part);
}
}
/* -------------------------------------------- */
static onRemoveMessages(data) {
static onRemoveMessages(part) {
if (Misc.isElectedUser()) {
if (data.part) {
const toDelete = game.messages.filter(it => it.data.content.includes(data.part));
toDelete.forEach(it => it.delete());
}
if (data.messageId) {
game.messages.get(data.messageId)?.delete();
}
}
}
static removeMessages(data) {
if (Misc.isElectedUser()){
ChatUtility.onRemoveMessages(data);
}
else {
game.socket.emit("system.foundryvtt-reve-de-dragon", { msg: "msg_delete_chat_message", data: data });
const toDelete = game.messages.filter(it => it.data.content.includes(part));
toDelete.forEach(it => it.delete());
}
}
/* -------------------------------------------- */
static removeChatMessageContaining(part) {
ChatUtility.removeMessages({ part: part });
}
static removeChatMessageId(messageId) {
if (messageId){
ChatUtility.removeMessages({ messageId: messageId });
if (Misc.isElectedUser()) {
ChatUtility.onRemoveMessages(part);
}
else {
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_delete_chat_message", data: { part: part }
});
}
}
@ -57,7 +44,7 @@ export class ChatUtility {
if (!game.user.isGM) {
ChatUtility.blindMessageToGM(chatOptions);
chatOptions.whisper = [game.user.id];
chatOptions.whisper = [game.user._id];
chatOptions.content = "Message envoyé en aveugle au Gardien";
}
else {
@ -75,7 +62,7 @@ export class ChatUtility {
/* -------------------------------------------- */
static prepareChatMessage(rollMode, name) {
return {
user: game.user.id,
user: game.user._id,
whisper: ChatUtility.getWhisperRecipients(rollMode, name)
}
}
@ -85,7 +72,7 @@ export class ChatUtility {
switch (rollMode) {
case "blindroll": return ChatUtility.getUsers(user => user.isGM);
case "gmroll": return ChatUtility.getWhisperRecipientsAndGMs(name);
case "selfroll": return [game.user.id];
case "selfroll": return [game.user._id];
}
return undefined;
}
@ -114,7 +101,7 @@ export class ChatUtility {
static handleGMChatMessage(data) {
console.log("blindMessageToGM", data);
if (game.user.isGM) { // message privé pour GM only
data.user = game.user.id;
data.user = game.user._id;
ChatMessage.create(data);
}
}

View File

@ -1,119 +0,0 @@
import { ChatUtility } from "./chat-utility.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
export class DialogCreateSigneDraconique extends Dialog {
static async createSigneForActors() {
const signe = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
let dialogData = {
signe: signe,
tmrs: TMRUtility.listSelectedTMR(signe.data.typesTMR ?? []),
actors: game.actors.filter(actor => actor.isHautRevant()).map(actor => {
let actorData = duplicate(Misc.data(actor));
actorData.selected = actor.hasPlayerOwner;
return actorData;
})
};
const html = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/dialog-create-signedraconique.html", dialogData);
new DialogCreateSigneDraconique(dialogData, html)
.render(true);
}
constructor(dialogData, html, callback) {
let options = { classes: ["DialogCreateSigneDraconiqueActorsActors"], width: 500, height: 650, 'z-index': 99999 };
let conf = {
title: "Créer un signe",
content: html,
default: "Ajouter aux haut-rêvants",
buttons: {
"Ajouter aux haut-rêvants": { label: "Ajouter aux haut-rêvants", callback: it => { this._onCreerSigneActeurs(); } }
}
};
super(conf, options);
this.dialogData = dialogData;
}
async _onCreerSigneActeurs() {
await $("[name='signe.data.ephemere']").change();
await $(".signe-xp-sort").change();
this.validerSigne();
this.dialogData.actors.filter(it => it.selected).map(it => game.actors.get(it._id))
.forEach(actor => this._createSigneForActor(actor, this.dialogData.signe));
}
async _createSigneForActor(actor, signe) {
actor.createEmbeddedDocuments("Item", [signe]);
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(Misc.data(actor).name),
content: await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html", {
signe: signe,
alias: Misc.data(actor).name
})
});
}
validerSigne() {
this.dialogData.signe.name = $("[name='signe.name']").val();
this.dialogData.signe.data.valeur.norm = $("[name='signe.data.valeur.norm']").val();
this.dialogData.signe.data.valeur.sign = $("[name='signe.data.valeur.sign']").val();
this.dialogData.signe.data.valeur.part = $("[name='signe.data.valeur.part']").val();
this.dialogData.signe.data.difficulte = $("[name='signe.data.difficulte']").val();
this.dialogData.signe.data.ephemere = $("[name='signe.data.ephemere']").prop("checked");
this.dialogData.signe.data.duree = $("[name='signe.data.duree']").val();
this.dialogData.signe.data.typesTMR = $(".select-tmr").val();
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.setEphemere(this.dialogData.signe.data.ephemere);
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find("[name='signe.data.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
html.find(".select-actor").change((event) => this.onSelectActor(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
}
async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique({ephemere: true});
$("[name='signe.name']").val(newSigne.name);
$("[name='signe.data.valeur.norm']").val(newSigne.data.valeur.norm);
$("[name='signe.data.valeur.sign']").val(newSigne.data.valeur.sign);
$("[name='signe.data.valeur.part']").val(newSigne.data.valeur.part);
$("[name='signe.data.difficulte']").val(newSigne.data.difficulte);
$("[name='signe.data.duree']").val(newSigne.data.duree);
$("[name='signe.data.ephemere']").prop("checked", newSigne.data.ephemere);
$(".select-tmr").val(newSigne.data.typesTMR);
this.setEphemere(newSigne.data.ephemere);
}
async setEphemere(ephemere) {
this.dialogData.signe.data.ephemere = ephemere;
HtmlUtility._showControlWhen($(".signe-data-duree"), ephemere);
}
async onSelectActor(event) {
event.preventDefault();
const options = event.currentTarget.options;
for (var i = 0; i < options.length; i++) { // looping over the options
const actorId = options[i].attributes["data-actor-id"].value;
const actor = this.dialogData.actors.find(it => it._id == actorId);
if (actor) {
actor.selected = options[i].selected;
}
};
}
onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value);
const oldValeur = this.dialogData.signe.data.valeur;
this.dialogData.signe.data.valeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
}
}

View File

@ -1,71 +0,0 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
export class DialogFabriquerPotion extends Dialog {
/* -------------------------------------------- */
static async create(actor, item, dialogConfig) {
let potionData = DialogFabriquerPotion.prepareData(actor, item);
let conf = {
title: `Fabriquer une potion de ${potionData.data.categorie}`,
content: await renderTemplate(dialogConfig.html, potionData),
default: potionData.buttonName,
};
let options = { classes: ["dialogfabriquerpotion"], width: 600, height: 160, 'z-index': 99999 };
mergeObject(options, dialogConfig.options ?? {}, { overwrite: true })
const dialog = new DialogFabriquerPotion(actor, potionData, conf, options);
dialog.render(true);
return dialog;
}
/* -------------------------------------------- */
static prepareData(actor, item) {
let potionData = duplicate(Misc.data(item));
potionData.nbBrinsSelect = RdDUtility.buildListOptions(1, potionData.data.quantite);
potionData.nbBrins = Math.min(potionData.data.quantite, DialogFabriquerPotion.getNombreBrinOptimal(potionData));
potionData.buttonName = "Fabriquer";
return potionData;
}
/* -------------------------------------------- */
constructor(actor, potionData, conf, options) {
conf.buttons = {
[potionData.buttonName]: {
label: potionData.buttonName, callback: it => this.onFabriquer(it)
}
};
super(conf, options);
this.actor = actor;
this.potionData = potionData;
}
static getNombreBrinOptimal(herbeData) {
switch (herbeData.data.categorie ?? '') {
case "Soin": return 12 - herbeData.data.niveau;
case "Repos": return 7 - herbeData.data.niveau;
}
return 1;
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find("#nbBrins").change(event => {
this.potionData.nbBrins = Misc.toInt(event.currentTarget.value);
});
}
/* -------------------------------------------- */
async onFabriquer(it) {
await $("#nbBrins").change();
this.actor.fabriquerPotion(this.potionData);
this.close();
}
}

View File

@ -1,95 +0,0 @@
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
export class DialogItemAchat extends Dialog {
static async onButtonAcheter(event) {
const buttonAcheter = event.currentTarget;
if (!buttonAcheter.attributes['data-jsondata']?.value) {
ui.notifications.warn("Impossible d'acheter: informations sur l'objet manquantes")
return;
}
const chatMessageIdVente = RdDUtility.findChatMessageId(buttonAcheter);
const vendeurId = buttonAcheter.attributes['data-vendeurId']?.value;
const vendeur = vendeurId ? game.actors.get(vendeurId) : undefined;
const acheteur = RdDUtility.getSelectedActor();
if (!acheteur && !vendeur) {
ui.notifications.info("Pas d'acheteur ni de vendeur, aucun changement");
return;
}
let venteData = DialogItemAchat.prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur);
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-achat.html`, venteData);
const dialog = new DialogItemAchat(html, vendeur, acheteur, venteData, chatMessageIdVente);
dialog.render(true);
}
constructor(html, vendeur, acheteur, venteData, chatMessageIdVente) {
let options = { classes: ["dialogachat"], width: 400, height: 300, 'z-index': 99999 };
const actionAchat = venteData.prixLot > 0 ? "Acheter" : "Prendre";
let conf = {
title: actionAchat,
content: html,
default: actionAchat,
buttons: {
[actionAchat]: { label: actionAchat, callback: it => { this.onAchat(); } },
"decliner": { label: "Décliner", callback: it => { } }
}
};
super(conf, options);
this.vendeur = vendeur;
this.acheteur = acheteur;
this.chatMessageIdVente = chatMessageIdVente;
this.venteData = venteData;
}
static prepareVenteData(buttonAcheter, vendeurId, vendeur, acheteur) {
const jsondata = buttonAcheter.attributes['data-jsondata']?.value;
const prixLot = buttonAcheter.attributes['data-prixLot']?.value ?? 0;
let venteData = {
item: JSON.parse(jsondata),
vendeurId: vendeurId,
vendeur: Misc.data(vendeur),
acheteur: Misc.data(acheteur),
tailleLot: parseInt(buttonAcheter.attributes['data-tailleLot']?.value ?? 1),
quantiteIllimite: buttonAcheter.attributes['data-quantiteIllimite']?.value == 'true',
quantiteNbLots: parseInt(buttonAcheter.attributes['data-quantiteNbLots']?.value),
nombreLots: 1,
prixLot: prixLot,
prixTotal: prixLot,
isVente: prixLot > 0
};
return venteData;
}
async onAchat() {
await $(".nombreLots").change();
(this.vendeur ?? this.acheteur).achatVente({
vendeurId: this.vendeur?.id,
acheteurId: this.acheteur?.id,
nombreLots: this.venteData.nombreLots,
prixTotal: this.venteData.prixTotal,
chatMessageIdVente: this.chatMessageIdVente
});
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".nombreLots").change(event => this.setNombreLots(Number(event.currentTarget.value)));
}
setNombreLots(nombreLots) {
this.venteData.nombreLots = nombreLots;
this.venteData.prixTotal = (nombreLots * this.venteData.prixLot).toFixed(2);
$(".prixTotal").text(this.venteData.prixTotal);
}
}

View File

@ -1,90 +0,0 @@
import { Misc } from "./misc.js";
export class DialogConsommer extends Dialog {
static async create(actor, item, template = undefined, options = {}) {
const consommerData = DialogConsommer.prepareData(actor, item, options);
const html = await renderTemplate(template ?? `systems/foundryvtt-reve-de-dragon/templates/dialog-item-consommer.html`, consommerData);
return new DialogConsommer(actor, item, consommerData, html, options)
}
constructor(actor, item, consommerData, html, options = {}) {
mergeObject(options, { classes: ["dialogconsommer"], width: 350, height: 450, 'z-index': 99999 }, { overwrite: false })
let conf = {
title: consommerData.title,
content: html,
default: consommerData.buttonName,
buttons: {
[consommerData.buttonName]: {
label: consommerData.buttonName, callback: it => this.onConsommer(it)
}
}
};
super(conf, options);
this.actor = actor;
this.item = item;
this.consommerData = consommerData;
}
async onConsommer(event) {
await $(".se-forcer").change();
await $(".consommer-doses").change();
this.actor.consommer(this.item, this.consommerData.choix);
}
/* -------------------------------------------- */
static prepareData(actor, item, options) {
const itemData = duplicate(Misc.data(item));
let consommerData = {
item: itemData,
cuisine: Misc.data(actor.getCompetence('cuisine')),
choix: {
doses: options.doses ?? 1,
seForcer: options.seForcer ?? false,
}
}
switch (itemData.type) {
case 'nourritureboisson':
consommerData.title = itemData.data.boisson ? `${itemData.name}: boire une dose` : `${itemData.name}: manger une portion`;
consommerData.buttonName = itemData.data.boisson ? "Boire" : "Manger";
break;
case 'potion':
consommerData.title = `${itemData.name}: boire la potion`;
consommerData.buttonName = "Boire";
break;
}
DialogConsommer.calculDoses(consommerData, consommerData.choix.doses)
return consommerData;
}
static calculDoses(consommerData) {
const doses = consommerData.choix.doses;
consommerData.totalSust = Misc.keepDecimals(doses * (consommerData.item.data.sust ?? 0), 2);
consommerData.totalDesaltere = consommerData.item.data.boisson
? Misc.keepDecimals(doses * (consommerData.item.data.desaltere ?? 0), 2)
: 0;
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".se-forcer").change(event => this.setSeForcer(event));
html.find(".consommer-doses").change(event => this.selectDoses(event));
}
setSeForcer(event) {
this.consommerData.choix.seForcer = event.currentTarget.checked;
}
selectDoses(event) {
this.consommerData.choix.doses = Number(event.currentTarget.value);
DialogConsommer.calculDoses(this.consommerData);
$(".total-sust").text(this.consommerData.totalSust);
$(".total-desaltere").text(this.consommerData.totalDesaltere);
}
}

View File

@ -1,94 +0,0 @@
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
export class DialogItemVente extends Dialog {
static async create(item, callback) {
const itemData = Misc.data(item);
const venteData = {
item: itemData,
alias: item.actor?.name ?? game.user.name,
vendeurId: item.actor?.id,
prixOrigine: itemData.data.cout,
prixUnitaire: itemData.data.cout,
prixLot: itemData.data.cout,
tailleLot: 1,
quantiteNbLots: itemData.data.quantite,
quantiteMaxLots: itemData.data.quantite,
quantiteMax: itemData.data.quantite,
quantiteIllimite: !item.isOwned,
isOwned: item.isOwned,
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-vente.html`, venteData);
return new DialogItemVente(venteData, html, callback);
}
constructor(venteData, html, callback) {
let options = { classes: ["dialogvente"], width: 400, height: 300, 'z-index': 99999 };
let conf = {
title: "Proposer",
content: html,
default: "proposer",
buttons: { "proposer": { label: "Proposer", callback: it => { this.onProposer(it); } } }
};
super(conf, options);
this.callback = callback;
this.venteData = venteData;
}
async onProposer(it) {
await $(".tailleLot").change();
await $(".quantiteNbLots").change();
await $(".quantiteIllimite").change();
await $(".prixLot").change();
this.callback(this.venteData);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
html.find(".tailleLot").change(event => this.setTailleLot(Number(event.currentTarget.value)));
html.find(".quantiteNbLots").change(event => this.setNbLots(Number(event.currentTarget.value)));
html.find(".quantiteIllimite").change(event => this.setQuantiteIllimite(event.currentTarget.checked));
html.find(".prixLot").change(event => this.setPrixLot(Number(event.currentTarget.value)));
}
setPrixLot(prixLot) {
this.venteData.prixLot = prixLot;
}
setTailleLot(tailleLot) {
// recalculer le prix du lot
if (tailleLot != this.venteData.tailleLot) {
this.venteData.prixLot = (tailleLot * this.venteData.prixOrigine).toFixed(2);
$(".prixLot").val(this.venteData.prixLot);
}
this.venteData.tailleLot = tailleLot;
if (this.venteData.isOwned) {
// recalculer le nombre de lots max
this.venteData.quantiteMaxLots = Math.floor(this.venteData.quantiteMax / tailleLot);
this.venteData.quantiteNbLots = Math.min(this.venteData.quantiteMaxLots, this.venteData.quantiteNbLots);
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
$(".quantiteNbLots").attr("max", this.venteData.quantiteMaxLots)
}
}
setNbLots(nbLots) {
if (this.venteData.isOwned) {
nbLots = Math.max(0, Math.min(nbLots, this.venteData.quantiteMaxLots));
}
this.venteData.quantiteNbLots = nbLots;
$(".quantiteNbLots").val(this.venteData.quantiteNbLots);
}
setQuantiteIllimite(checked) {
this.venteData.quantiteIllimite = checked;
$(".label-quantiteIllimite").text(this.venteData.quantiteIllimite ? "Illimités" : "disponibles");
HtmlUtility._showControlWhen($(".quantiteNbLots"), !this.venteData.quantiteIllimite)
}
}

View File

@ -1,52 +0,0 @@
import { Misc } from "./misc.js";
export class DialogSplitItem extends Dialog {
static async create(item, callback) {
const itemData = Misc.data(item);
const splitData = {
item: itemData,
choix: { quantite: 1, max: itemData.data.quantite - 1 }
};
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-item-split.html`, splitData);
return new DialogSplitItem(item, splitData, html, callback)
}
constructor(item, splitData, html, callback) {
let options = { classes: ["dialogsplit"], width: 300, height: 160, 'z-index': 99999 };
let conf = {
title: "Séparer en deux",
content: html,
default: "separer",
buttons: {
"separer": {
label: "Séparer", callback: it => {
this.onSplit();
}
}
}
};
super(conf, options);
this.callback = callback;
this.item = item;
this.splitData = splitData;
}
async onSplit(){
await $(".choix-quantite").change();
this.callback(this.item, this.splitData.choix.quantite);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
html.find(".choix-quantite").change(event => {
this.splitData.choix.quantite = Number(event.currentTarget.value);
});
}
}

View File

@ -24,11 +24,6 @@ export class Grammar {
return words?.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "") ?? words;
}
/* -------------------------------------------- */
static toLowerCaseNoAccentNoSpace(words) {
return words?.toLowerCase().normalize("NFD").replace(/[ \u0300-\u036f]/g, "") ?? words;
}
/* -------------------------------------------- */
static articleDetermine(genre) {
switch (Grammar.toLowerCaseNoAccent(genre)) {

View File

@ -3,7 +3,7 @@ import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
// Activate chat listeners defined
// Hooks.on('renderChatLog', (log, html, data) => {
// RdDUtility.chatListeners(html);
// });
Hooks.on('renderChatLog', (log, html, data) => {
RdDUtility.chatListeners(html);
});

View File

@ -112,7 +112,7 @@ export class RdDItemArme extends Item {
if (defCategory == 'boucliers') {
return false;
}
// Parer avec une hache ou une arme dhast exige toujours une significative
// Parer avec une hache ou une arme dhast exige toujours une signi$cative
if (defCategory.match(/(hast|haches)/)) {
return true;
}

View File

@ -4,8 +4,8 @@ import { Misc } from "./misc.js";
const competenceTroncs = [["Esquive", "Dague", "Corps à corps"],
["Epée à 1 main", "Epée à 2 mains", "Hache à 1 main", "Hache à 2 mains", "Lance", "Masse à 1 main", "Masse à 2 mains"]];
const xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
const niveau_max = xp_par_niveau.length - 10;
const competence_xp_par_niveau = [5, 5, 5, 10, 10, 10, 10, 15, 15, 15, 15, 20, 20, 20, 20, 30, 30, 40, 40, 60, 60, 100, 100, 100, 100, 100, 100, 100, 100, 100];
const competence_niveau_max = competence_xp_par_niveau.length - 10;
/* -------------------------------------------- */
const limitesArchetypes = [
{ "niveau": 0, "nombreMax": 100, "nombre": 0 },
@ -24,14 +24,14 @@ const limitesArchetypes = [
/* -------------------------------------------- */
const categorieCompetences = {
"generale": { base: -4, label: "Générales" },
"particuliere": { base: -8, label: "Particulières" },
"specialisee": { base: -11, label: "Spécialisées" },
"connaissance": { base: -11, label: "Connaissances" },
"draconic": { base: -11, label: "Draconics" },
"melee": { base: -6, label: "Mêlée" },
"tir": { base: -8, label: "Tir" },
"lancer": { base: -8, label: "Lancer" }
"generale": { base: "-4", label: "Générales" },
"particuliere": { base: "-8", label: "Particulières" },
"specialisee": { base: "-11", label: "Spécialisées" },
"connaissance": { base: "-11", label: "Connaissances" },
"draconic": { base: "-11", label: "Draconics" },
"melee": { base: "-6", label: "Mêlée" },
"tir": { base: "-8", label: "Tir" },
"lancer": { base: "-8", label: "Lancer" }
}
const compendiumCompetences = {
@ -44,9 +44,9 @@ const compendiumCompetences = {
function _buildCumulXP() {
let cumulXP = { "-11": 0 };
let cumul = 0;
for (let i = 0; i <= xp_par_niveau.length; i++) {
for (let i = 0; i <= competence_xp_par_niveau.length; i++) {
let level = i - 10;
cumul += xp_par_niveau[i];
cumul += competence_xp_par_niveau[i];
cumulXP[level] = cumul;
}
return cumulXP;
@ -56,48 +56,29 @@ const competence_xp_cumul = _buildCumulXP();
export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static actorCompendium(actorType) {
return compendiumCompetences[actorType];
}
/* -------------------------------------------- */
static getCategorieCompetences() {
return categorieCompetences;
}
/* -------------------------------------------- */
static getNiveauBase(category) {
return categorieCompetences[category].base;
}
/* -------------------------------------------- */
static getLabelCategorie(category) {
return categorieCompetences[category].label;
}
/* -------------------------------------------- */
static getCategorie(competence) {
return Misc.data(competence)?.data.categorie;
}
static isDraconic(competence) {
return Misc.data(competence).data.categorie == 'draconic';
}
/* -------------------------------------------- */
static getVoieDraconic(competences, voie) {
voie = Grammar.toLowerCaseNoAccent(voie);
return competences.find(it => RdDItemCompetence.isDraconic(it) && Grammar.toLowerCaseNoAccent(Misc.data(it).name).includes(voie));
}
/* -------------------------------------------- */
static getEsquive(competences) {
return { name: 'Esquive', niveau: RdDItemCompetence.findCompetence(competences, 'Esquive')?.data.niveau ?? -6 };
}
/* -------------------------------------------- */
static isCompetenceArme(competence) {
switch (Misc.templateData(competence).categorie) {
switch (competence.data.categorie) {
case 'melee':
return Misc.data(competence).name != 'Esquive';
return competence.name != 'Esquive';
case 'tir':
case 'lancer':
return true;
@ -107,15 +88,15 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static isArmeUneMain(competence) {
return Misc.data(competence)?.name.toLowerCase().includes("1 main");
return competence?.name.toLowerCase().includes("1 main");
}
static isArme2Main(competence) {
return Misc.data(competence)?.name.toLowerCase().includes("2 main");
return competence?.name.toLowerCase().includes("2 main");
}
/* -------------------------------------------- */
static isMalusEncombrementTotal(competence) {
return Misc.data(competence)?.name.toLowerCase().match(/(natation|acrobatie)/);
return competence?.name.toLowerCase().match(/(natation|acrobatie)/);
}
/* -------------------------------------------- */
@ -132,18 +113,17 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static computeTotalXP(competences) {
const total = competences.map(c => RdDItemCompetence.computeXP(c))
.reduce(Misc.sum(), 0);
.reduce((a, b) => a + b, 0);
const economieTronc = RdDItemCompetence.computeEconomieXPTronc(competences);
return total - economieTronc;
}
/* -------------------------------------------- */
static computeXP(competence) {
const itemData = Misc.data(competence);
const factor = itemData.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
const xpNiveau = RdDItemCompetence.computeDeltaXP(itemData.data.base, itemData.data.niveau ?? itemData.data.base);
const xp = itemData.data.xp ?? 0;
const xpSort = itemData.data.xp_sort ?? 0;
const factor = competence.name.includes('Thanatos') ? 2 : 1; // Thanatos compte double !
const xpNiveau = RdDItemCompetence.computeDeltaXP(competence.data.base, competence.data.niveau ?? competence.data.base);
const xp = competence.data.xp ?? 0;
const xpSort = competence.data.xp_sort ?? 0;
return factor * (xpNiveau + xp) + xpSort;
}
@ -169,11 +149,10 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static computeCompetenceXPCost(competence) {
const compData = Misc.data(competence);
let xp = RdDItemCompetence.getDeltaXp(compData.data.base, compData.data.niveau ?? compData.data.base);
xp += compData.data.xp ?? 0;
if (compData.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
xp += compData.data.xp_sort ?? 0;
let xp = RdDItemCompetence.getDeltaXp(competence.data.base, competence.data.niveau ?? competence.data.base);
xp += competence.data.xp ?? 0;
if (competence.name.includes('Thanatos')) xp *= 2; /// Thanatos compte double !
xp += competence.data.xp_sort ?? 0;
return xp;
}
@ -182,22 +161,20 @@ export class RdDItemCompetence extends Item {
let economie = 0;
for (let troncList of competenceTroncs) {
let list = troncList.map(name => RdDItemCompetence.findCompetence(competences, name))
.sort(Misc.descending(c => Misc.templateData(c).niveau)); // tri du plus haut au plus bas
.sort((c1, c2) => c2.data.niveau - c1.data.niveau); // tri du plus haut au plus bas
list.splice(0, 1); // ignorer la plus élevée
list.map(c => Misc.templateData(c)).forEach(tplData => {
economie += RdDItemCompetence.getDeltaXp(tplData.base, Math.min(tplData.niveau, 0));
list.forEach(c => {
economie += RdDItemCompetence.getDeltaXp(c.data.base, Math.min(c.data.niveau, 0));
});
}
return economie;
}
/* -------------------------------------------- */
static levelUp(itemData) {
itemData.data.xpNext = RdDItemCompetence.getCompetenceNextXp(itemData.data.niveau);
itemData.data.isLevelUp = itemData.data.xp >= itemData.data.xpNext;
}
/* -------------------------------------------- */
static isVisible(itemData) {
return Number(itemData.data.niveau) != RdDItemCompetence.getNiveauBase(itemData.data.categorie);
}
@ -209,20 +186,20 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static findCompetence(list, name) {
name = Grammar.toLowerCaseNoAccent(name);
name = Grammar.toLowerCaseNoAccent(name);
const competences = list.filter(it => Grammar.toLowerCaseNoAccent(it.name).includes(name) && (it.type == "competence" || it.type == "competencecreature"));
if (competences.length == 0) {
return undefined;
}
let competence = competences.find(it => Grammar.toLowerCaseNoAccent(it.name) == name);
if (!competence) {
competence = competences[0];
if (competences.length > 1) {
const names = competences.map(it => it.name).reduce((a, b) => `${a}<br>${b}`);
ui.notifications.info(`Plusieurs compétences possibles:<br>${names}<br>La première sera choisie: ${competence.name}`);
}
if (competence) {
return competence;
}
return competence;
if (competences.length>1) {
const names = competences.map(it => it.name).reduce((a, b) => `${a}<br>${b}`);
ui.notifications.info(`Plusieurs compétences possibles:<br>${names}<br>La première sera choisie: ${competences[0].name}`);
}
return competences[0];
}
/* -------------------------------------------- */
@ -233,7 +210,7 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static getCompetenceXp(niveau) {
RdDItemCompetence._valideNiveau(niveau);
return niveau < -10 ? 0 : xp_par_niveau[niveau + 10];
return niveau < -10 ? 0 : competence_xp_par_niveau[niveau + 10];
}
/* -------------------------------------------- */
@ -245,19 +222,19 @@ export class RdDItemCompetence extends Item {
/* -------------------------------------------- */
static _valideNiveau(niveau) {
if (niveau < -11 || niveau > niveau_max) {
console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${niveau_max} ]`);
if (niveau < -11 || niveau > competence_niveau_max) {
console.warn(`Niveau ${niveau} en dehors des niveaux de compétences: [-11, ${competence_niveau_max} ]`);
}
}
/* -------------------------------------------- */
static computeResumeArchetype(competences) {
const archetype = RdDItemCompetence.getLimitesArchetypes();
competences.map(it => Math.max(0, Misc.templateData(it).niveau_archetype))
.forEach(niveau => {
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
});
competences.forEach(it => {
let niveau = Math.max(0, it.data.niveau_archetype);
archetype[niveau] = archetype[niveau] ?? { "niveau": niveau, "nombreMax": 0, "nombre": 0 };
archetype[niveau].nombre = (archetype[niveau]?.nombre ?? 0) + 1;
});
return archetype;
}

View File

@ -5,8 +5,8 @@ export class RdDItemCompetenceCreature extends Item {
/* -------------------------------------------- */
static setRollDataCreature(rollData) {
rollData.competence = Misc.data(rollData.competence);
rollData.carac = { "carac_creature": { label: rollData.competence.name, value: rollData.competence.data.carac_value } };
rollData.competence = duplicate(rollData.competence);
rollData.competence.data.defaut_carac = "carac_creature";
rollData.competence.data.categorie = "creature";
rollData.selectedCarac = rollData.carac.carac_creature;
@ -19,11 +19,10 @@ export class RdDItemCompetenceCreature extends Item {
/* -------------------------------------------- */
static toArme(itemData) {
if (RdDItemCompetenceCreature.isCompetenceAttaque(itemData)) {
itemData = Misc.data(itemData);
let arme = { name: itemData.name, data: duplicate(itemData) };
let arme = duplicate(Misc.data(itemData));
mergeObject(arme.data,
{
competence: itemData.name,
competence: arme.name,
resistance: 100,
equipe: true,
dommagesReels: arme.data.dommages,

View File

@ -1,23 +1,22 @@
import { Misc } from "./misc.js";
const monnaiesData = [
{
name: "Etain (1 denier)", type: 'monnaie',
_id: randomID(16), name: "Etain (1 denier)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_etain_poisson.webp",
data: { quantite: 0, valeur_deniers: 1, encombrement: 0.001, description: "" }
},
{
name: "Bronze (10 deniers)", type: 'monnaie',
_id: randomID(16), name: "Bronze (10 deniers)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_bronze_epees.webp",
data: { quantite: 0, valeur_deniers: 10, encombrement: 0.002, description: "" }
},
{
name: "Argent (1 sol)", type: 'monnaie',
_id: randomID(16), name: "Argent (1 sol)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_argent_sol.webp",
data: { quantite: 0, valeur_deniers: 100, encombrement: 0.003, description: "" }
},
{
name: "Or (10 sols)", type: 'monnaie',
_id: randomID(16), name: "Or (10 sols)", type: 'monnaie',
img: "systems/foundryvtt-reve-de-dragon/icons/objets/piece_or_sol.webp",
data: { quantite: 0, valeur_deniers: 1000, encombrement: 0.004, description: "" }
}
@ -25,37 +24,17 @@ const monnaiesData = [
export class Monnaie {
static isSystemMonnaie(item) {
let present = monnaiesData.find(monnaie => monnaie.data.valeur_deniers == Misc.data(item)?.data?.valeur_deniers);
return present;
}
static monnaiesData() {
return monnaiesData;
}
static filtrerMonnaies(items) {
return items.filter(it => Misc.data(it).type == 'monnaie');
return items.filter(it => it.type == 'monnaie');
}
static monnaiesManquantes(items) {
const valeurs = Monnaie.filtrerMonnaies(items)
.map(it => Misc.templateData(it).valeur_deniers);
const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers));
//const manquantes = monnaiesData.filter(monnaie => !valeurs.find(v => v != Misc.templateData(monnaie).valeur_deniers) );
//console.log("Valeurs : ", valeurs, manquantes);
return []; //manquantes;
}
static deValeur(monnaie, v) {
return v != monnaie.data.valeur_deniers;
}
static arrondiDeniers(sols) {
return sols.toFixed(2);
}
static triValeurDenier() {
return Misc.ascending(item => Misc.data(item).data.valeur_deniers);
.map(it => it.data.valeur_deniers)
return duplicate(monnaiesData.filter(monnaie => !valeurs.find(v => v != monnaie.data.valeur_deniers)));
}
}

315
module/item-rdd.js Normal file
View File

@ -0,0 +1,315 @@
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
export class RdDItem extends Item {
/* -------------------------------------------- */
async postItem() {
console.log(this);
const properties = this[`_${this.data.type}ChatData`]();
const itemData = Misc.data(this);
let chatData = duplicate(itemData);
chatData["properties"] = properties
//Check if the posted item should have availability/pay buttons
chatData.hasPrice = "cout" in chatData.data;
chatData.data.cout_deniers = 0;
let dialogResult = [-1, -1]; // dialogResult[0] = quantité, dialogResult[1] = prix
if (chatData.hasPrice )
{
let sols = chatData.data.cout;
chatData.data.cout_deniers = Math.floor(sols * 100);
dialogResult = await new Promise( (resolve, reject) => {new Dialog({
content :
`<p>Modifier la quantité?</p>
<div class="form-group">
<label> Quantité</label>
<input name="quantity" type="text" value="1"/>
</div>
<p>Modifier la prix?</p>
<div class="form-group">
<label> Prix en Sols</label>
<input name="price" type="text" value="${chatData.data.cout}"/>
</div>
`,
title : "Quantité & Prix",
buttons : {
post : {
label : "Soumettre",
callback: (dlg) => {
resolve( [ dlg.find('[name="quantity"]').val(), dlg.find('[name="price"]').val() ] )
}
},
}
}).render(true)
})
}
if (dialogResult[0] > 0)
{
if (this.isOwned)
{
if (itemData.data.quantite == 0)
dialogResult[0] = -1
else if (itemData.data.quantite < dialogResult[0])
{
dialogResult[0] = itemData.data.quantite;
ui.notifications.notify(`Impossible de poster plus que ce que vous avez. La quantité à été réduite à ${dialogResult[0]}.`)
this.update({"data.quantite" : 0})
}
else {
ui.notifications.notify(`Quantité réduite par ${dialogResult[0]}.`)
this.update({"data.quantite" : itemData.data.quantite - dialogResult[0]})
}
}
}
if ( chatData.hasPrice ) {
if (dialogResult[0] > 0)
chatData.postQuantity = Number(dialogResult[0]);
if (dialogResult[1] > 0) {
chatData.postPrice = dialogResult[1];
chatData.data.cout_deniers = Math.floor(dialogResult[1] * 100); // Mise à jour cout en deniers
}
chatData.finalPrice = Number(chatData.postPrice) * Number(chatData.postQuantity);
chatData.data.cout_deniers_total = chatData.data.cout_deniers * Number(chatData.postQuantity);
chatData.data.quantite = chatData.postQuantity;
console.log("POST : ", chatData.finalPrice, chatData.data.cout_deniers_total, chatData.postQuantity);
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png"))
chatData.img = null;
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium : "postedItem",
payload: itemData,
});
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-item.html', chatData).then(html => {
let chatOptions = RdDUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
/* -------------------------------------------- */
_objetChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armeChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Dommages</b>: ${rddData.dommages}`,
`<b>Force minimum</b>: ${rddData.force}`,
`<b>Resistance</b>: ${rddData.resistance}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_conteneurChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Capacité</b>: ${rddData.capacite} Enc.`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_munitionChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armureChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Protection</b>: ${rddData.protection}`,
`<b>Détérioration</b>: ${rddData.deterioration}`,
`<b>Malus armure</b>: ${rddData.malus}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_competenceChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Niveau</b>: ${rddData.niveau}`,
`<b>Caractéristique par défaut</b>: ${rddData.carac_defaut}`,
`<b>XP</b>: ${rddData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_competencecreatureChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Niveau</b>: ${rddData.niveau}`,
`<b>Caractéristique</b>: ${rddData.carac_value}`,
`<b>XP</b>: ${rddData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_sortChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Draconic</b>: ${rddData.draconic}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Case TMR</b>: ${rddData.caseTMR}`,
`<b>Points de Rêve</b>: ${rddData.ptreve}`
]
return properties;
}
/* -------------------------------------------- */
_herbeChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Milieu</b>: ${rddData.milieu}`,
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_ingredientChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Milieu</b>: ${rddData.milieu}`,
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_tacheChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Caractéristique</b>: ${rddData.carac}`,
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Périodicité</b>: ${rddData.periodicite}`,
`<b>Fatigue</b>: ${rddData.fatigue}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Points de Tâche</b>: ${rddData.points_de_tache}`,
`<b>Points de Tâche atteints</b>: ${rddData.points_de_tache_courant}`
]
return properties;
}
/* -------------------------------------------- */
_livreChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Auteur</b>: ${rddData.auteur}`,
`<b>Difficulté</b>: ${rddData.difficulte}`,
`<b>Points de Tâche</b>: ${rddData.points_de_tache}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_potionChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Rareté</b>: ${rddData.rarete}`,
`<b>Catégorie</b>: ${rddData.categorie}`,
`<b>Encombrement</b>: ${rddData.encombrement}`,
]
return properties;
}
/* -------------------------------------------- */
_queueChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Refoulement</b>: ${rddData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_ombreChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Refoulement</b>: ${rddData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_souffleChatData() {
const rddData = Misc.data(this).data;
let properties = [];
return properties;
}
/* -------------------------------------------- */
_teteChatData() {
const rddData = Misc.data(this).data;
let properties = [];
return properties;
}
/* -------------------------------------------- */
_tarotChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Concept</b>: ${rddData.concept}`,
`<b>Aspect</b>: ${rddData.aspect}`,
]
return properties;
}
/* -------------------------------------------- */
_nombreastralChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Valeur</b>: ${rddData.value}`,
`<b>Jour</b>: ${rddData.jourlabel}`,
]
return properties;
}
/* -------------------------------------------- */
_monnaieChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Valeur en Deniers</b>: ${rddData.valeur_deniers}`,
`<b>Encombrement</b>: ${rddData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_meditationChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Thème</b>: ${rddData.theme}`,
`<b>Compétence</b>: ${rddData.competence}`,
`<b>Support</b>: ${rddData.support}`,
`<b>Heure</b>: ${rddData.heure}`,
`<b>Purification</b>: ${rddData.purification}`,
`<b>Vêture</b>: ${rddData.veture}`,
`<b>Comportement</b>: ${rddData.comportement}`,
`<b>Case TMR</b>: ${rddData.tmr}`
]
return properties;
}
/* -------------------------------------------- */
_casetmrChatData() {
const rddData = Misc.data(this).data;
let properties = [
`<b>Coordonnée</b>: ${rddData.coord}`,
`<b>Spécificité</b>: ${rddData.specific}`
]
return properties;
}
}

View File

@ -1,11 +1,9 @@
import { RdDItemSort } from "./item-sort.js";
import { RdDUtility } from "./rdd-utility.js";
import { RdDItem } from "./item-rdd.js";
import { RdDAlchimie } from "./rdd-alchimie.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/**
* Extend the basic ItemSheet with some very simple modifications
@ -14,139 +12,85 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
export class RdDItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
width: 550,
height: 550
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-sheet.html",
width: 550,
height: 550
//tabs: [{navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description"}]
});
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
const videSiConteneur = this.object.isConteneur() ? this.object.isVide() : true;
// Add "Post to chat" button
// We previously restricted this to GM and editable items only. If you ever find this comment because it broke something: eh, sorry!
if ("cout" in Misc.templateData(this.object) && videSiConteneur) {
buttons.unshift({
class: "post",
icon: "fas fa-comments-dollar",
onclick: ev => this.item.proposerVente()
});
}
else {
buttons.unshift({
buttons.unshift(
{
class: "post",
icon: "fas fa-comment",
onclick: ev => this.item.postItem()
});
}
onclick: ev => new RdDItem(Misc.data(this.item)).postItem()
})
return buttons
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
setPosition(options={}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight;
const bodyHeight = position.height - 192;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
async getData() {
const objectData = Misc.data(this.object);
let formData = {
title: objectData.name,
id: objectData.id,
type: objectData.type,
img: objectData.img,
name: objectData.name,
data: objectData.data,
isGM: game.user.isGM,
owner: this.document.isOwner,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
isSoins: false
}
if (this.actor) {
formData.isOwned = true;
formData.actorId = this.actor.id;
}
let formData = super.getData();
formData.categorieCompetences = RdDItemCompetence.getCategorieCompetences();
if (formData.type == 'tache' || formData.type == 'livre' || formData.type == 'meditation' || formData.type == 'oeuvre') {
if ( formData.item.type == 'tache' || formData.item.type == 'livre' || formData.item.type == 'meditation' || formData.item.type == 'oeuvre') {
formData.caracList = duplicate(game.system.model.Actor.personnage.carac);
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences');
formData.competences = await RdDUtility.loadCompendiumNames( 'foundryvtt-reve-de-dragon.competences' );
}
if (formData.type == 'arme') {
formData.competences = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
console.log(formData.competences);
if (formData.item.type == 'arme') {
formData.competences = await RdDUtility.loadCompendium( 'foundryvtt-reve-de-dragon.competences', it => RdDItemCompetence.isCompetenceArme(it));
}
if (formData.type == 'recettealchimique') {
RdDAlchimie.processManipulation(objectData, this.actor && this.actor.id);
if ( formData.item.type == 'recettealchimique' ) {
RdDAlchimie.processManipulation(formData.item, this.actor && this.actor._id );
}
if (formData.type == 'potion') {
if (this.dateUpdated) {
formData.data.prdate = this.dateUpdated;
this.dateUpdated = undefined;
}
RdDHerbes.updatePotionData(formData);
}
if (formData.isOwned && formData.type == 'herbe' && (formData.data.categorie == 'Soin' || formData.data.categorie == 'Repos')) {
formData.isIngredientPotionBase = true;
if ( this.actor ) {
formData.isOwned = true;
formData.actorId = this.actor._id;
}
formData.bonusCaseList = RdDItemSort.getBonusCaseList(formData, true);
formData.isGM = game.user.isGM; // Pour verrouiller certaines éditions
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".item-cout"), ReglesOptionelles.isUsing('afficher-prix-joueurs') || game.user.isGM || !this.object.isOwned);
HtmlUtility._showControlWhen($(".item-magique"), this.object.isMagique());
// Everything below here is only needed if the sheet is editable
if (!this.options.editable) return;
// Select competence categorie
html.find(".categorie").change(event => this._onSelectCategorie(event));
html.find("#categorie").on("click", this._onClickSelectCategorie.bind(this) );
html.find('.sheet-competence-xp').change((event) => {
if (this.object.data.type == 'competence') {
RdDUtility.checkThanatosXP(this.object.data.name);
html.find('#sheet-competence-xp').change((event) => {
if ( this.object.data.type == 'competence') {
RdDUtility.checkThanatosXP( this.object.data.name );
}
});
} );
html.find('.enchanteDate').change((event) => {
let jour = Number($('#jourMois').val());
let mois = $('#nomMois').val();
this.dateUpdated = game.system.rdd.calendrier.getIndexFromDate(jour, mois);
});
html.find('.creer-tache-livre').click((event) => {
html.find('#creer-tache-livre').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.creerTacheDepuisLivre(this.item);
});
html.find('.consommer-potion').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.consommerPotion(this.item);
});
html.find('.creer-potion-base').click((event) => {
let actorId = event.currentTarget.attributes['data-actor-id'].value;
let actor = game.actors.get(actorId);
actor.dialogFabriquerPotion(this.item);
let actor = game.actors.get( actorId );
actor.creerTacheDepuisLivre( this.item );
});
html.find('.alchimie-tache a').click((event) => {
@ -154,42 +98,39 @@ export class RdDItemSheet extends ItemSheet {
let recetteId = event.currentTarget.attributes['data-recette-id'].value;
let tacheName = event.currentTarget.attributes['data-alchimie-tache'].value;
let tacheData = event.currentTarget.attributes['data-alchimie-data'].value;
let actor = game.actors.get(actorId);
if (actor) {
let actor = game.actors.get( actorId );
if ( actor ) {
actor.effectuerTacheAlchimie(recetteId, tacheName, tacheData);
} else {
ui.notifications.info("Impossible trouver un actur pour réaliser cette tache Alchimique.");
ui.notifications.info("Impossible de trouver un acteur pour réaliser cette tâche alchimique.");
}
});
}
/* -------------------------------------------- */
async _onSelectCategorie(event) {
async _onClickSelectCategorie(event) {
event.preventDefault();
if (this.object.isCompetence()){
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
Misc.templateData(this.object).base = level;
$("#base").val(level);
}
let level = RdDItemCompetence.getNiveauBase(event.currentTarget.value);
this.object.data.data.base = level;
$("#base").val( level );
}
/* -------------------------------------------- */
get template() {
//console.log(this);
let type = this.object.data.type;
get template()
{
let type = this.item.type;
return `systems/foundryvtt-reve-de-dragon/templates/item-${type}-sheet.html`;
}
/* -------------------------------------------- */
/** @override */
_updateObject(event, formData) { // Deprecated en v0.8 à clarifier
//console.log("UPDATE !", formData);
_updateObject(event, formData) {
// Données de bonus de cases ?
formData = RdDItemSort.buildBonusCaseStringFromFormData(formData);
formData = RdDItemSort.buildBonusCaseStringFromFormData( formData );
return this.object.update(formData);
}
}

View File

@ -1,95 +0,0 @@
import { RdDItemSigneDraconique } from "./item-signedraconique.js";
import { Misc } from "./misc.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
/**
* Item sheet pour signes draconiques
* @extends {ItemSheet}
*/
export class RdDSigneDraconiqueItemSheet extends ItemSheet {
/** @override */
static get defaultOptions() {
return mergeObject(super.defaultOptions, {
classes: ["foundryvtt-reve-de-dragon", "sheet", "item"],
template: "systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html",
width: 550,
height: 550
});
}
/* -------------------------------------------- */
_getHeaderButtons() {
let buttons = super._getHeaderButtons();
buttons.unshift({ class: "post", icon: "fas fa-comment", onclick: ev => this.item.postItem() });
return buttons;
}
/* -------------------------------------------- */
/** @override */
setPosition(options = {}) {
const position = super.setPosition(options);
const sheetHeader = this.element.find(".sheet-header");
const sheetBody = this.element.find(".sheet-body");
const bodyHeight = position.height - sheetHeader[0].clientHeight;
sheetBody.css("height", bodyHeight);
return position;
}
/* -------------------------------------------- */
async getData() {
const formData = duplicate(Misc.data(this.object));
mergeObject(formData, {
title: formData.name,
isGM: game.user.isGM,
owner: this.document.isOwner,
isOwned: this.actor ? true : false,
actorId: this.actor?.id,
editable: this.isEditable,
cssClass: this.isEditable ? "editable" : "locked",
});
formData.tmrs = TMRUtility.listSelectedTMR(formData.data.typesTMR ?? []);
return formData;
}
/* -------------------------------------------- */
/** @override */
activateListeners(html) {
super.activateListeners(html);
if (!this.options.editable) return;
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
html.find(".select-tmr").change((event) => this.onSelectTmr(event));
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event.currentTarget.attributes['data-typereussite']?.value, Number(event.currentTarget.value)));
}
async setSigneAleatoire() {
const newSigne = await RdDItemSigneDraconique.randomSigneDraconique();
this.object.update(newSigne);
}
async onSelectTmr(event) {
event.preventDefault();
const selectedTMR = $(".select-tmr").val();
this.object.update({ 'data.typesTMR': selectedTMR });
}
async onValeurXpSort(event) {
const codeReussite = event.currentTarget.attributes['data-typereussite']?.value ?? 0;
const xp = Number(event.currentTarget.value);
const oldValeur = Misc.templateData(this.object).valeur;
const newValeur = RdDItemSigneDraconique.calculValeursXpSort(codeReussite, xp, oldValeur);
await this.object.update({ 'data.valeur': newValeur });
}
/* -------------------------------------------- */
get template() {
return `systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html`;
}
get title() {
return `Signe draconique: ${this.object.name}`;
}
}

View File

@ -1,103 +0,0 @@
import { defaultItemImg } from "./item.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDRollTables } from "./rdd-rolltables.js";
import { TMRType, TMRUtility } from "./tmr-utility.js";
const tableSignesIndicatifs = [
{ rarete: "Très facile", difficulte: 0, xp: 6, nbCases: 14 },
{ rarete: "Facile", difficulte: -2, xp: 10, nbCases: 10 },
{ rarete: "Moyen", difficulte: -3, xp: 15, nbCases: 7 },
{ rarete: "Difficile", difficulte: -5, xp: 20, nbCases: 4 },
{ rarete: "Ardu", difficulte: -8, xp: 30, nbCases: 1 }
]
export class RdDItemSigneDraconique {
static prepareSigneDraconiqueMeditation(meditation, rolled) {
if (rolled.isSuccess != undefined) {
meditation = Misc.data(meditation);
return {
name: "de la " + meditation.name,
type: "signedraconique",
img: meditation.img,
data: {
typesTMR: [TMRUtility.typeTmrName(meditation.data.tmr)],
difficulte: RdDItemSigneDraconique.getDiffSigneMeditation(rolled.code),
ephemere: true,
duree: "1 round",
valeur: { "norm": 3, "sign": 5, "part": 10 }
}
};
}
return undefined;
}
static getDiffSigneMeditation(code) {
switch (code) {
case "norm": return -7;
case "sign": return -3;
case "part": return 0;
}
return undefined;
}
static getXpSortSigneDraconique(code, signe) {
return Misc.data(signe).data.valeur[code] ?? 0;
}
static calculValeursXpSort(qualite, valeur, avant) {
switch (qualite) {
case "norm":
return {
norm: valeur,
sign: Math.max(valeur, avant.sign),
part: Math.max(valeur, avant.part)
}
case "sign":
return {
norm: Math.min(valeur, avant.norm),
sign: valeur,
part: Math.max(valeur, avant.part)
}
case "part":
return {
norm: Math.min(valeur, avant.norm),
sign: Math.min(valeur, avant.sign),
part: valeur
}
}
}
static async randomSigneDraconique(options = { ephemere: undefined }) {
let modele = await RdDDice.rollOneOf(tableSignesIndicatifs);
return {
name: await RdDItemSigneDraconique.randomSigneDescription(),
type: "signedraconique",
img: defaultItemImg.signedraconique,
data: {
typesTMR: await RdDItemSigneDraconique.randomTmrs(modele.nbCases),
ephemere: options?.ephemere == undefined ? RdDDice.rollTotal("1d2") == 2 : options.ephemere,
duree: "1 round",
difficulte: modele.difficulte,
valeur: { norm: modele.xp, sign: modele.xp, part: Math.floor(modele.xp * 1.5) },
}
};
}
static async randomTmrs(nbTmr = undefined) {
let tmrs = Object.values(TMRType)
.map(value => TMRUtility.typeTmrName(value.name));
let keep = nbTmr ?? (await RdDDice.rollTotal("1d" + TMRType.length) + 1);
for (let i = tmrs.length; i > keep; i--) {
tmrs.splice(await RdDDice.rollTotal("1d" + i), 1);
}
return tmrs;
}
static async randomSigneDescription() {
return await RdDRollTables.drawTextFromRollTable("Signes draconiques", false);
}
}

View File

@ -51,10 +51,10 @@ export class RdDItemSort extends Item {
* Retourne une liste de bonus/case pour un item-sheet
* @param {} item
*/
static getBonusCaseList( item, newCase = false ) {
static getBonusCaseList( data, newCase = false ) {
// Gestion spéciale case bonus
if ( item.type == 'sort') {
return this.buildBonusCaseList(item.data.bonuscase, newCase );
if ( data.item.type == 'sort') {
return this.buildBonusCaseList(data.data.bonuscase, newCase );
}
return undefined;
}
@ -106,7 +106,7 @@ export class RdDItemSort extends Item {
// Sauvegarde/update
let bonuscase = StringList.toString();
//console.log("Bonus cae :", bonuscase);
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'data.bonuscase': bonuscase }] );
actor.updateEmbeddedEntity("OwnedItem", { _id: sort._id, 'data.bonuscase': bonuscase } );
}
/* -------------------------------------------- */

View File

@ -1,562 +0,0 @@
import { DialogItemVente } from "./dialog-item-vente.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDUtility } from "./rdd-utility.js";
const typesObjetsEquipement = ["objet", "arme", "armure", "conteneur", "herbe", "ingredient", "livre", "potion", "munition", "nourritureboisson", "monnaie"];
const typesObjetsOeuvres = ["oeuvre", "recettecuisine", "musique", "chant", "danse", "jeu"];
const encBrin = 0.00005;// un brin = 1 décigramme = 1/10g = 1/10000kg = 1/20000 enc
export const defaultItemImg = {
competence: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
compcreature: "systems/foundryvtt-reve-de-dragon/icons/competence_defaut.webp",
arme: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/epee_gnome.webp",
armure: "systems/foundryvtt-reve-de-dragon/icons/armes_armures/armure_plaques.webp",
conteneur: "systems/foundryvtt-reve-de-dragon/icons/objets/sac_a_dos.webp",
sort: "systems/foundryvtt-reve-de-dragon/icons/competence_oniros.webp",
herbe: "systems/foundryvtt-reve-de-dragon/icons/botanique/Endorlotte.png",
ingredient: "systems/foundryvtt-reve-de-dragon/icons/objets/sable_poudre.webp",
livre: "systems/foundryvtt-reve-de-dragon/icons/objets/livre.webp",
potion: "systems/foundryvtt-reve-de-dragon/icons/objets/liqueur_de_bagdol.webp",
queue: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
ombre: "systems/foundryvtt-reve-de-dragon/icons/queue_dragon.webp",
souffle: "systems/foundryvtt-reve-de-dragon/icons/souffle_dragon.webp",
tete: "systems/foundryvtt-reve-de-dragon/icons/tete_dragon.webp",
meditation: "systems/foundryvtt-reve-de-dragon/icons/meditations_ecrits/meditation_alchimie.webp",
recettealchimique: "systems/foundryvtt-reve-de-dragon/icons/competence_alchimie.webp",
chant: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
danse: "systems/foundryvtt-reve-de-dragon/icons/arts/danse_0.webp",
jeu: "systems/foundryvtt-reve-de-dragon/icons/arts/jeux_petasse.webp",
recettecuisine: "systems/foundryvtt-reve-de-dragon/icons/arts/recette_cuisine_1.webp",
musique: "systems/foundryvtt-reve-de-dragon/icons/arts/chant_0.webp",
maladie: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/maladie.webp",
poison: "systems/foundryvtt-reve-de-dragon/icons/maladies_venins/venin.webp",
oeuvre: "systems/foundryvtt-reve-de-dragon/icons/competence_comedie.webp",
nourritureboisson: "systems/foundryvtt-reve-de-dragon/icons/objets/provision_crue.webp",
signedraconique: "systems/foundryvtt-reve-de-dragon/icons/tmr/signe_draconique.webp",
}
/* -------------------------------------------- */
export class RdDItem extends Item {
constructor(data, context) {
if (!data.img) {
data.img = defaultItemImg[data.type];
}
super(data, context);
}
static getTypeObjetsEquipement() {
return typesObjetsEquipement;
}
static getTypesOeuvres() {
return typesObjetsOeuvres;
}
isCompetence() {
return Misc.data(this).type == 'competence';
}
isConteneur() {
return Misc.data(this).type == 'conteneur';
}
isVide() {
return this.isConteneur() && (Misc.templateData(this).contenu ?? []).length == 0;
}
isAlcool() {
const itemData = Misc.data(this);
return itemData.type == 'nourritureboisson' && itemData.data.boisson && itemData.data.alcoolise;
}
isPotion() {
return Misc.data(this).type == 'potion';
}
isEquipement() {
return RdDItem.getTypeObjetsEquipement().includes(Misc.data(this).type);
}
isCristalAlchimique() {
const itemData = Misc.data(this);
return itemData.type == 'objet' && Grammar.toLowerCaseNoAccent(itemData.name) == 'cristal alchimique' && itemData.data.quantite > 0;
}
isMagique() {
return Misc.templateData(this).magique;
}
getEncTotal() {
const itemData = Misc.data(this);
return Number(itemData.data.encombrement ?? 0) * Number(itemData.data.quantite ?? 1);
}
getEnc() {
const itemData = Misc.data(this);
switch (itemData.type) {
case 'herbe':
return encBrin;
}
return itemData.data.encombrement ?? 0;
}
prepareDerivedData() {
super.prepareDerivedData();
if (this.isEquipement(this)) {
this._calculsEquipement();
}
if (this.isPotion()) {
this.prepareDataPotion()
}
const itemData = Misc.data(this);
itemData.data.actionPrincipale = this.getActionPrincipale({ warnIfNot: false });
}
prepareDataPotion() {
const tplData = Misc.templateData(this);
const categorie = Grammar.toLowerCaseNoAccent(tplData.categorie);
tplData.magique = categorie.includes('enchante');
if (tplData.magique) {
if (categorie.includes('soin') || categorie.includes('repos')) {
tplData.puissance = tplData.herbebonus * tplData.pr;
}
}
}
_calculsEquipement() {
const tplData = Misc.templateData(this);
const quantite = this.isConteneur() ? 1 : (tplData.quantite ?? 0);
const enc = this.getEnc();
if (enc != undefined) {
tplData.encTotal = Math.max(enc, 0) * quantite;
}
if (tplData.cout != undefined) {
tplData.prixTotal = Math.max(tplData.cout, 0) * quantite;
}
}
getActionPrincipale(options = { warnIfNot: true }) {
const itemData = Misc.data(this);
if ((itemData.data.quantite ?? 0) <= 0) {
if (options.warnIfNot) {
ui.notifications.warn(`Vous n'avez plus de ${itemData.name}.`);
}
return undefined;
}
switch (itemData.type) {
case 'nourritureboisson': return itemData.data.boisson ? 'Boire' : 'Manger';
case 'potion': return 'Boire';
case 'livre': return 'Lire';
}
if (options.warnIfNot) {
ui.notifications.warn(`Impossible d'utilise un ${itemData.name}, aucune action associée définie.`);
}
return undefined;
}
async diminuerQuantite(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
if (options.diminuerQuantite == false) return;
await this.quantiteIncDec(-nombre, options);
}
async quantiteIncDec(nombre, options = { diminuerQuantite: true, supprimerSiZero: false }) {
const itemData = Misc.data(this);
const quantite = Number(itemData.data.quantite ?? -1);
if (quantite >= 0) {
const reste = Math.max(quantite + Number(nombre), 0);
if (reste == 0) {
if (options.supprimerSiZero) {
ui.notifications.notify(`${itemData.name} supprimé de votre équipement`);
await this.delete();
}
else {
ui.notifications.notify(`Il ne vous reste plus de ${itemData.name}, vous pouvez le supprimer de votre équipement, ou trouver un moyen de vous en procurer.`);
await this.update({ "data.quantite": 0 });
}
}
else {
await this.update({ "data.quantite": reste });
}
}
}
/* -------------------------------------------- */
// détermine si deux équipements sont similaires: de même type, et avec les même champs hormis la quantité
isEquipementSimilaire(other) {
const itemData = Misc.data(this);
const otherData = Misc.data(other);
const tplData = Misc.templateData(this);
const otherTplData = Misc.templateData(other);
if (!this.isEquipement()) return false;
if (itemData.type != otherData.type) return false;
if (itemData.name != otherData.name) return false;
if (tplData.quantite == undefined) return false;
const differences = Object.entries(tplData).filter(([key, value]) => !['quantite', 'encTotal', 'prixTotal', 'cout'].includes(key))
.filter(([key, value]) => value != otherTplData[key]);
if (differences.length > 0) {
let message = `Impossible de regrouper les ${itemData.type} ${itemData.name}: `;
for (const [key, value] of differences){
message += `<br>${key}: ${value} vs ${otherTplData[key]}`;
}
ui.notifications.info(message)
return false;
}
return true;
}
async proposerVente() {
console.log(this);
const dialog = await DialogItemVente.create(this, (vente) => this._onProposerVente(vente))
dialog.render(true);
}
async _onProposerVente(venteData) {
venteData["properties"] = this.getProprietes();
if (venteData.isOwned) {
if (venteData.quantiteNbLots * venteData.tailleLot > venteData.quantiteMax) {
ui.notifications.warn(`Vous avez ${venteData.quantiteMax} ${venteData.item.name}, ce n'est pas suffisant pour vendre ${venteData.quantiteNbLots} de ${venteData.tailleLot}`)
return;
}
}
venteData.jsondata = JSON.stringify(venteData.item);
console.log(venteData);
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-vente-item.html', venteData);
ChatMessage.create(RdDUtility.chatDataSetup(html));
}
getProprietes() {
return this[`_${Misc.data(this).type}ChatData`]();
}
/* -------------------------------------------- */
async postItem() {
console.log(this);
let chatData = duplicate(Misc.data(this));
const properties = this.getProprietes();
chatData["properties"] = properties
if (this.actor) {
chatData.actor = { id: this.actor.id };
}
//Check if the posted item should have availability/pay buttons
chatData.hasPrice = "cout" in chatData.data;
chatData.data.cout_deniers = 0;
let dialogResult = [-1, -1]; // dialogResult[0] = quantité, dialogResult[1] = prix
if (chatData.hasPrice) {
chatData.data.cout_deniers = Math.floor(chatData.data.cout * 100);
dialogResult = await new Promise((resolve, reject) => {
new Dialog({
content:
`<p>Modifier la quantité?</p>
<div class="form-group">
<label> Quantité</label>
<input name="quantity" type="text" value="1"/>
</div>
<p>Modifier la prix?</p>
<div class="form-group">
<label>Prix en Sols</label>
<input name="price" type="text" value="${chatData.data.cout}"/>
</div>
`,
title: "Quantité & Prix",
buttons: {
post: {
label: "Soumettre",
callback: (dlg) => {
resolve([Number(dlg.find('[name="quantity"]').val()), Number(dlg.find('[name="price"]').val())])
}
},
}
}).render(true)
})
}
let quantiteEnvoi = this.isOwned ? Math.min(dialogResult[0], chatData.data.quantite) : dialogResult[0];
const prixTotal = dialogResult[1];
if (quantiteEnvoi > 0) {
if (this.isOwned) {
if (chatData.data.quantite == 0) {
quantiteEnvoi = -1
}
else if (quantiteEnvoi > chatData.data.quantite) {
quantiteEnvoi = chatData.data.quantite;
ui.notifications.notify(`Impossible de poster plus que ce que vous avez. La quantité à été réduite à ${quantiteEnvoi}.`)
}
if (quantiteEnvoi > 0) {
this.diminuerQuantite(quantiteEnvoi);
}
}
}
if (chatData.hasPrice) {
if (quantiteEnvoi > 0)
chatData.postQuantity = Number(quantiteEnvoi);
if (prixTotal >= 0) {
chatData.postPrice = prixTotal;
chatData.data.cout_deniers = Math.floor(prixTotal * 100); // Mise à jour cout en deniers
}
chatData.finalPrice = Number(chatData.postPrice) * Number(chatData.postQuantity);
chatData.data.cout_deniers_total = chatData.data.cout_deniers * Number(chatData.postQuantity);
chatData.data.quantite = chatData.postQuantity;
console.log("POST : ", chatData.finalPrice, chatData.data.cout_deniers_total, chatData.postQuantity);
}
// Don't post any image for the item (which would leave a large gap) if the default image is used
if (chatData.img.includes("/blank.png"))
chatData.img = null;
// JSON object for easy creation
chatData.jsondata = JSON.stringify(
{
compendium: "postedItem",
payload: chatData,
});
renderTemplate('systems/foundryvtt-reve-de-dragon/templates/post-item.html', chatData).then(html => {
let chatOptions = RdDUtility.chatDataSetup(html);
ChatMessage.create(chatOptions)
});
}
static propertyIfDefined(name, val, condition = (it) => true) {
return condition ? [`<b>${name}</b>: ${val}`] : [];
}
/* -------------------------------------------- */
_objetChatData() {
const tplData = Misc.templateData(this);
let properties = [].concat(
RdDItem.propertyIfDefined('Résistance', tplData.resistance, tplData.resistance),
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
}
/* -------------------------------------------- */
_nourritureboissonChatData() {
const tplData = Misc.templateData(this);
let properties = [].concat(
RdDItem.propertyIfDefined('Sustentation', tplData.sust, tplData.sust > 0),
RdDItem.propertyIfDefined('Désaltère', tplData.desaltere, tplData.boisson),
RdDItem.propertyIfDefined('Force alcool', tplData.force, tplData.boisson && tplData.alcoolise),
RdDItem.propertyIfDefined('Exotisme', tplData.exotisme, tplData.exotisme < 0),
RdDItem.propertyIfDefined('Qualité', tplData.qualite, tplData.qualite),
RdDItem.propertyIfDefined('Encombrement', tplData.encombrement),
);
return properties;
}
/* -------------------------------------------- */
_armeChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Dommages</b>: ${tplData.dommages}`,
`<b>Force minimum</b>: ${tplData.force}`,
`<b>Resistance</b>: ${tplData.resistance}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_conteneurChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Capacité</b>: ${tplData.capacite} Enc.`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_munitionChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_armureChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Protection</b>: ${tplData.protection}`,
`<b>Détérioration</b>: ${tplData.deterioration}`,
`<b>Malus armure</b>: ${tplData.malus}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_competenceChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Niveau</b>: ${tplData.niveau}`,
`<b>Caractéristique par défaut</b>: ${tplData.carac_defaut}`,
`<b>XP</b>: ${tplData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_competencecreatureChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Niveau</b>: ${tplData.niveau}`,
`<b>Caractéristique</b>: ${tplData.carac_value}`,
`<b>XP</b>: ${tplData.xp}`
]
return properties;
}
/* -------------------------------------------- */
_sortChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Draconic</b>: ${tplData.draconic}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Case TMR</b>: ${tplData.caseTMR}`,
`<b>Points de Rêve</b>: ${tplData.ptreve}`
]
return properties;
}
/* -------------------------------------------- */
_herbeChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Milieu</b>: ${tplData.milieu}`,
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_ingredientChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Milieu</b>: ${tplData.milieu}`,
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
]
return properties;
}
/* -------------------------------------------- */
_tacheChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Caractéristique</b>: ${tplData.carac}`,
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Périodicité</b>: ${tplData.periodicite}`,
`<b>Fatigue</b>: ${tplData.fatigue}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Points de Tâche</b>: ${tplData.points_de_tache}`,
`<b>Points de Tâche atteints</b>: ${tplData.points_de_tache_courant}`
]
return properties;
}
/* -------------------------------------------- */
_livreChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Auteur</b>: ${tplData.auteur}`,
`<b>Difficulté</b>: ${tplData.difficulte}`,
`<b>Points de Tâche</b>: ${tplData.points_de_tache}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_potionChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Rareté</b>: ${tplData.rarete}`,
`<b>Catégorie</b>: ${tplData.categorie}`,
`<b>Encombrement</b>: ${tplData.encombrement}`,
]
return properties;
}
/* -------------------------------------------- */
_queueChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Refoulement</b>: ${tplData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_ombreChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Refoulement</b>: ${tplData.refoulement}`
]
return properties;
}
/* -------------------------------------------- */
_souffleChatData() {
const tplData = Misc.templateData(this);
let properties = [];
return properties;
}
/* -------------------------------------------- */
_teteChatData() {
const tplData = Misc.templateData(this);
let properties = [];
return properties;
}
/* -------------------------------------------- */
_tarotChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Concept</b>: ${tplData.concept}`,
`<b>Aspect</b>: ${tplData.aspect}`,
]
return properties;
}
/* -------------------------------------------- */
_nombreastralChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Valeur</b>: ${tplData.value}`,
`<b>Jour</b>: ${tplData.jourlabel}`,
]
return properties;
}
/* -------------------------------------------- */
_monnaieChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Valeur en Deniers</b>: ${tplData.valeur_deniers}`,
`<b>Encombrement</b>: ${tplData.encombrement}`
]
return properties;
}
/* -------------------------------------------- */
_meditationChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Thème</b>: ${tplData.theme}`,
`<b>Compétence</b>: ${tplData.competence}`,
`<b>Support</b>: ${tplData.support}`,
`<b>Heure</b>: ${tplData.heure}`,
`<b>Purification</b>: ${tplData.purification}`,
`<b>Vêture</b>: ${tplData.veture}`,
`<b>Comportement</b>: ${tplData.comportement}`,
`<b>Case TMR</b>: ${tplData.tmr}`
]
return properties;
}
/* -------------------------------------------- */
_casetmrChatData() {
const tplData = Misc.templateData(this);
let properties = [
`<b>Coordonnée</b>: ${tplData.coord}`,
`<b>Spécificité</b>: ${tplData.specific}`
]
return properties;
}
}

View File

@ -1,4 +1,3 @@
import { RdDDice } from "./rdd-dice.js";
/**
* This class is intended as a placeholder for utility methods unrelated
@ -23,13 +22,13 @@ export class Misc {
return (a, b) => a + b;
}
static ascending(orderFunction = x => x) {
static ascending(orderFunction = x=>x) {
return (a, b) => Misc.sortingBy(orderFunction(a), orderFunction(b));
}
}
static descending(orderFunction = x => x) {
static descending(orderFunction = x=>x) {
return (a, b) => Misc.sortingBy(orderFunction(b), orderFunction(a));
}
}
static sortingBy(a, b) {
if (a > b) return 1;
@ -49,12 +48,6 @@ export class Misc {
return isNaN(parsed) ? 0 : parsed;
}
static keepDecimals(num, decimals) {
if (decimals <= 0 || decimals > 6) return num;
const decimal = Math.pow(10, parseInt(decimals));
return Math.round(num * decimal) / decimal;
}
static getFractionHtml(diviseur) {
if (!diviseur || diviseur <= 1) return undefined;
switch (diviseur || 1) {
@ -64,9 +57,9 @@ export class Misc {
}
}
static classify(items, classifier = it => it.type) {
static classify(items, classifier = it => it.type, transform = it => it) {
let itemsBy = {};
Misc.classifyInto(itemsBy, items, classifier);
Misc.classifyInto(itemsBy, items, classifier, transform);
return itemsBy;
}
@ -81,7 +74,7 @@ export class Misc {
return itemsBy;
}
static classifyInto(itemsBy, items, classifier = it => it.type) {
static classifyInto(itemsBy, items, classifier = it => it.type, transform = it => it) {
for (const item of items) {
const classification = classifier(item);
let list = itemsBy[classification];
@ -89,16 +82,31 @@ export class Misc {
list = [];
itemsBy[classification] = list;
}
list.push(item);
list.push(transform(item));
}
}
static rollOneOf(array) {
return array[new Roll("1d" + array.length).evaluate().total - 1];
}
static distinct(array) {
return [...new Set(array)];
}
static actorData(actor) {
return Misc.data(actor);
}
static itemData(item) {
return Misc.data(item);
}
static data(it) {
if (it instanceof Actor || it instanceof Item || it instanceof Combatant) {
if (it instanceof Item) {
return it.data;
}
if (it instanceof Actor) {
return it.data;
}
return it;
@ -108,22 +116,13 @@ export class Misc {
return Misc.data(it)?.data ?? {}
}
static getEntityTypeLabel(entity) {
const documentName = entity?.documentName;
const type = entity?.data.type;
if (documentName === 'Actor' || documentName === 'Item') {
const label = CONFIG[documentName]?.typeLabels?.[type] ?? type;
return game.i18n.has(label) ? game.i18n.localize(label) : t;
}
return type;
}
static connectedGMOrUser(ownerId = undefined) {
if (ownerId && game.user.id == ownerId) {
if (ownerId && game.user.id == ownerId){
return ownerId;
}
return (game.user.isGM ? game.user.id : game.users.entities.find(u => u.isGM && u.active)?.id) ?? game.user.id;
}
static isElectedUser() {
return game.user.id == Misc.connectedGMOrUser();
}

View File

@ -1,5 +1,4 @@
import { Misc } from "./misc.js"
import { RdDDice } from "./rdd-dice.js";
const poesieHautReve = [
{
@ -65,8 +64,8 @@ const poesieHautReve = [
]
export class Poetique {
static async getExtrait(){
return await RdDDice.rollOneOf(poesieHautReve);
static getExtrait(){
return Misc.rollOneOf(poesieHautReve);
}
}

View File

@ -1,46 +1,51 @@
/* -------------------------------------------- */
import { Misc } from "./misc.js";
const matchOperations = new RegExp(/@(\w*){([\w\-]+)}/ig);
const matchOperationTerms = new RegExp(/@(\w*){([\w\-]+)}/i);
/* -------------------------------------------- */
export class RdDAlchimie {
/* -------------------------------------------- */
static processManipulation(recetteData, actorId = undefined) {
static processManipulation( recette, actorId = undefined ) {
//console.log("CALLED", recette, recette.isOwned, actorId );
let manip = recetteData.data.manipulation;
let matchArray = manip.match(matchOperations);
if (matchArray) {
for (let matchStr of matchArray) {
let result = matchStr.match(matchOperationTerms);
let manip = duplicate(recette.data.manipulation);
let reg1 = new RegExp(/@(\w*){([\w\-]+)}/ig);
let matchArray = manip.match( reg1 );
if ( matchArray ) {
for( let matchStr of matchArray) {
let reg2 = new RegExp(/@(\w*){([\w\-]+)}/i);
let result = matchStr.match(reg2);
//console.log("RESULT ", result);
if (result[1] && result[2]) {
let commande = Misc.upperFirst(result[1]);
let replacement = this[`_alchimie${commande}`](recetteData, result[2], actorId);
manip = manip.replace(result[0], replacement);
if ( result[1] && result[2]) {
let commande = Misc.upperFirst( result[1] );
let replacement = this[`_alchimie${commande}`](recette, result[2], actorId);
manip = manip.replace( result[0], replacement);
}
}
}
recetteData.data.manipulation_update = manip;
recette.data.manipulation_update = manip;
}
/* -------------------------------------------- */
static _alchimieCouleur(recette, couleurs, actorId) {
if (actorId) {
return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="couleur" data-alchimie-data="${couleurs}">couleur ${couleurs}</a></span>`;
static _alchimieCouleur( recette, couleurs, actorId ) {
let replacement
if ( actorId ) {
replacement = `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="couleur" data-alchimie-data="${couleurs}">couleur ${couleurs}</a></span>`;
} else {
return `<span class="alchimie-tache">couleur ${couleurs} </span>`;
replacement = `<span class="alchimie-tache">couleur ${couleurs} </span>`;
}
return replacement;
}
/* -------------------------------------------- */
static _alchimieConsistance(recette, consistances, actorId) {
if (actorId) {
return `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="consistance" data-alchimie-data="${consistances}">consistance ${consistances}</a></span>`;
static _alchimieConsistance( recette, consistances, actorId ) {
let replacement
if ( actorId ) {
replacement = `<span class="alchimie-tache"><a data-recette-id="${recette._id}" data-actor-id="${actorId}" data-alchimie-tache="consistance" data-alchimie-data="${consistances}">consistance ${consistances}</a></span>`;
} else {
return `<span class="alchimie-tache">consistance ${consistances} </span>`;
replacement = `<span class="alchimie-tache">consistance ${consistances} </span>`;
}
return replacement;
}
/* -------------------------------------------- */
@ -53,13 +58,4 @@ export class RdDAlchimie {
}
return Math.min(0, -composantes);
}
static getCaracTache(tache) {
switch (tache) {
case "consistance": return 'dexterite';
case "couleur": return 'vue';
}
return 'intellect';
}
}

View File

@ -3,7 +3,7 @@
* Extend the base Dialog entity by defining a custom window to perform roll.
* @extends {Dialog}
*/
export class RdDAstrologieEditeur extends Dialog {
export class RdDAstrologieEditeur extends Dialog {
/* -------------------------------------------- */
constructor(html, calendrier, calendrierData) {
@ -23,9 +23,9 @@
}
/* -------------------------------------------- */
async resetNombreAstraux() {
resetNombreAstraux() {
game.system.rdd.calendrier.resetNombreAstral();
await game.system.rdd.calendrier.rebuildListeNombreAstral();
game.system.rdd.calendrier.rebuildListeNombreAstral();
game.system.rdd.calendrier.showAstrologieEditor();
}

View File

@ -8,51 +8,50 @@ import { Misc } from "./misc.js";
*/
export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */
static async create(actor, dialogConfig) {
let data = {
nombres: this.organizeNombres(actor),
dates: game.system.rdd.calendrier.getJoursSuivants(10),
etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDItemCompetence.findCompetence(actor.data.items, 'Astrologie')
/* -------------------------------------------- */
static async create(actor, dialogConfig) {
let data = { nombres: this.organizeNombres( actor),
dates: game.system.rdd.calendrier.getJoursSuivants( 10 ),
etat: actor.getEtatGeneral(),
ajustementsConditions: CONFIG.RDD.ajustementsConditions,
astrologie: RdDItemCompetence.findCompetence( actor.data.items, 'Astrologie')
}
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true });
}
return new RdDAstrologieJoueur(html, actor, data);
}
const html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html', data);
let options = { classes: ["rdddialog"], width: 600, height: 500, 'z-index': 99999 };
if (dialogConfig.options) {
mergeObject(options, dialogConfig.options, { overwrite: true });
}
return new RdDAstrologieJoueur(html, actor, data);
}
/* -------------------------------------------- */
constructor(html, actor, data) {
constructor(html, actor, data ) {
let myButtons = {
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
};
saveButton: { label: "Fermer", callback: html => this.quitDialog() }
};
// Get all n
// Common conf
let dialogConf = { content: html, title: "Nombres Astraux", buttons: myButtons, default: "saveButton" };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 };
let dialogOptions = { classes: ["rdddialog"], width: 600, height: 300, 'z-index': 99999 } ;
super(dialogConf, dialogOptions);
this.actor = actor;
this.dataNombreAstral = duplicate(data);
}
/* -------------------------------------------- */
static organizeNombres(actor) {
let itemNombres = actor.listItemsData('nombreastral');
let itemNombres = actor.data.items.filter( (item) => item.type == 'nombreastral');
let itemFiltered = {};
for (let item of itemNombres) {
if (itemFiltered[item.data.jourindex]) {
for ( let item of itemNombres) {
if ( itemFiltered[item.data.jourindex] ) {
itemFiltered[item.data.jourindex].listValues.push(item.data.value);
} else {
itemFiltered[item.data.jourindex] = {
listValues: [item.data.value],
listValues: [ item.data.value ],
jourlabel: item.data.jourlabel
}
}
@ -61,22 +60,21 @@ export class RdDAstrologieJoueur extends Dialog {
}
/* -------------------------------------------- */
requestJetAstrologie() {
let data = {
id: this.actor.data._id,
carac_vue: Misc.data(this.actor).data.carac['vue'].value,
etat: this.dataNombreAstral.etat,
astrologie: this.dataNombreAstral.astrologie,
conditions: $("#diffConditions").val(),
date: $("#joursAstrologie").val()
}
if (game.user.isGM) {
game.system.rdd.calendrier.requestNombreAstral(data);
requestJetAstrologie( ) {
let data = { id: this.actor.data._id,
carac_vue: Misc.data(this.actor).data.carac['vue'].value,
etat: this.dataNombreAstral.etat,
astrologie: this.dataNombreAstral.astrologie,
conditions: $("#diffConditions").val(),
date: $("#joursAstrologie").val()
}
if ( game.user.isGM) {
game.system.rdd.calendrier.requestNombreAstral( data );
} else {
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_request_nombre_astral",
data: data
});
data: data
} );
}
this.close();
}
@ -89,7 +87,7 @@ export class RdDAstrologieJoueur extends Dialog {
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
$(function () {
$("#diffConditions").val(0);
});

View File

@ -13,7 +13,7 @@ export class RdDAudio {
let audioData = context2file[context];
if ( audioData ) {
let audioPath = "systems/foundryvtt-reve-de-dragon/sounds/" + audioData.file;
console.log(`foundryvtt-reve-de-dragon | Playing Sound: ${audioPath}`)
console.log(`wfrp4e | Playing Sound: ${audioPath}`)
AudioHelper.play({ src: audioPath }, audioData.isGlobal);
}
}

View File

@ -5,8 +5,6 @@ import { HtmlUtility } from "./html-utility.js";
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { RdDUtility } from "./rdd-utility.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
const dossierIconesHeures = 'systems/foundryvtt-reve-de-dragon/icons/heures/'
@ -37,32 +35,16 @@ const MAX_NOMBRE_ASTRAL = 12;
/* -------------------------------------------- */
export class RdDCalendrier extends Application {
static createCalendrierPos() {
return { top: 200, left: 200 };
}
static getCalendrier(index) {
let calendrier = {
heureRdD: 0, // Index dans heuresList
minutesRelative: 0,
indexJour: index,
annee: Math.floor(index / (28 * 12)),
moisRdD: Math.floor(index / 28) % 12,
jour: (index % 28) // Le calendrier stocke le jour en 0-27, mais en 1-28 à l'affichage
}
return calendrier;
}
/* -------------------------------------------- */
async initCalendrier() {
// Calendrier
this.calendrier = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier"));
this.calendrier.annee = this.calendrier.annee ?? (this.calendrier.moisRdD == 12 ? 1 : 0);
this.calendrier.moisRdD = (this.calendrier.moisRdD ?? 0) % 12;
//console.log("CALENDRIER", this.calendrier);
console.log("CALENDRIER", this.calendrier);
if (this.calendrier == undefined || this.calendrier.moisRdD == undefined) {
this.calendrier = RdDCalendrier.getCalendrier(0);
this.calendrier.heureRdD = 0; // Index dans heuresList
this.calendrier.minutesRelative = 0;
this.calendrier.moisRdD = 0; // Index dans heuresList
this.calendrier.jour = 0;
if (game.user.isGM) { // Uniquement si GM
game.settings.set("foundryvtt-reve-de-dragon", "calendrier", this.calendrier);
}
@ -70,7 +52,8 @@ export class RdDCalendrier extends Application {
// position
this.calendrierPos = duplicate(game.settings.get("foundryvtt-reve-de-dragon", "calendrier-pos"));
if (this.calendrierPos == undefined || this.calendrierPos.top == undefined) {
this.calendrierPos = RdDCalendrier.createCalendrierPos();
this.calendrierPos.top = 200;
this.calendrierPos.left = 200;
if (game.user.isGM) { // Uniquement si GM
game.settings.set("foundryvtt-reve-de-dragon", "calendrier-pos", this.calendrierPos);
}
@ -78,15 +61,14 @@ export class RdDCalendrier extends Application {
// nombre astral
if (game.user.isGM) {
this.listeNombreAstral = this._loadListNombreAstral();
await this.rebuildListeNombreAstral(false); // Ensure always up-to-date
this.rebuildListeNombreAstral(); // Ensure always up-to-date
}
console.log(this.calendrier, this.calendrierPos, this.listeNombreAstral);
}
/* -------------------------------------------- */
_loadListNombreAstral() {
const listeNombreAstraux = game.settings.get("foundryvtt-reve-de-dragon", "liste-nombre-astral");
return listeNombreAstraux ?? [];
return Object.values(game.settings.get("foundryvtt-reve-de-dragon", "liste-nombre-astral"));
}
/* -------------------------------------------- */
@ -99,18 +81,11 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
getDateFromIndex(index) {
const date = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex());
return (date.jour+1) + ' ' + heuresDef[heuresList[date.moisRdD]].label;
}
/* -------------------------------------------- */
getNumericDateFromIndex(index = undefined) {
const dateRdD = RdDCalendrier.getCalendrier(index ?? this.getCurrentDayIndex());
return {
day: dateRdD.jour + 1,
month: heuresList[dateRdD.moisRdD]
}
getDateFromIndex(index = undefined) {
if (!index) index = this.getCurrentDayIndex();
let month = Math.floor(index / 28);
let day = (index - (month * 28)) + 1;
return day + " " + heuresList[month];
}
/* -------------------------------------------- */
@ -120,13 +95,9 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
getCurrentDayIndex() {
return (((this.calendrier.annee ?? 0) * 12 + (this.calendrier.moisRdD ?? 0)) * 28) + (this.calendrier.jour ?? 0);
return (this.calendrier.moisRdD * 28) + this.calendrier.jour;
}
/* -------------------------------------------- */
getIndexFromDate(jour, mois) {
return (heuresDef[mois].heure * 28) + (jour - 1);
}
/* -------------------------------------------- */
getJoursSuivants(num) {
let jours = [];
@ -139,17 +110,9 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
async ajouterNombreAstral(index, showDice = true) {
const nombreAstral = await RdDDice.rollTotal("1dh", { showDice: showDice, hideDice: !showDice, rollMode: "selfroll" });
const dateFuture = this.getDateFromIndex(index);
if (showDice) {
ChatMessage.create({
whisper: ChatMessage.getWhisperRecipients("GM"),
content: `Le chiffre astrologique du ${dateFuture} sera le ${nombreAstral}`
});
}
ajouterNombreAstral(index) {
return {
nombreAstral: nombreAstral,
nombreAstral: new Roll("1d12").roll().total,
valeursFausses: [],
index: index
}
@ -162,56 +125,45 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
resetNombreAstral() {
getNombreAstral(indexDate) {
const liste = this.listeNombreAstral ?? this._loadListNombreAstral();
let astralData = liste.find((nombreAstral, i) => nombreAstral.index == indexDate);
if (!astralData?.nombreAstral) {
this.rebuildListeNombreAstral();
astralData = liste.find((nombreAstral, i) => nombreAstral.index == indexDate);
}
return astralData?.nombreAstral ?? "N/A";
}
/* -------------------------------------------- */
resetNombreAstral( ) {
this.listeNombreAstral = [];
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_reset_nombre_astral",
data: {}
});
}
/* -------------------------------------------- */
getNombreAstral(indexDate) {
if ( this.listeNombreAstral == undefined ) {
this.listeNombreAstral = this._loadListNombreAstral();
}
let liste = this.listeNombreAstral || [];
let astralData = liste.find((nombreAstral, i) => nombreAstral.index == indexDate);
return astralData?.nombreAstral;
}
/* -------------------------------------------- */
async rebuildListeNombreAstral(showDice = true) {
if (game.user.isGM) {
let jourCourant = this.getCurrentDayIndex();
let newList = [];
for (let i = 0; i < 12; i++) {
let dayIndex = jourCourant + i;
let na = this.listeNombreAstral.find( n => n.index == dayIndex);
if ( na ) {
newList[i] = duplicate(na);
} else {
newList[i] = await this.ajouterNombreAstral(dayIndex, showDice );
rebuildListeNombreAstral() {
let jourCourant = this.getCurrentDayIndex();
let jourFin = jourCourant + 12;
let newList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11].map(i => this.ajouterNombreAstral(jourCourant + i));
if (this.listeNombreAstral) {
for (const na of this.listeNombreAstral) {
if (na && na.index >= jourCourant && na.index < jourFin) {
newList[na.index - jourCourant] = na;
}
}
console.log("SAVE list", newList, jourCourant);
this.listeNombreAstral = newList;
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
}
this.listeNombreAstral = newList;
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
}
/* -------------------------------------------- */
async onCalendarButton(ev) {
onCalendarButton(ev) {
ev.preventDefault();
const calendarAvance = ev.currentTarget.attributes['data-calendar-avance'];
const calendarSet = ev.currentTarget.attributes['data-calendar-set'];
if (calendarAvance) {
await this.incrementTime(Number(calendarAvance.value));
this.incrementTime(Number(calendarAvance.value));
}
else if (calendarSet) {
this.positionnerHeure(Number(calendarSet.value));
@ -220,7 +172,7 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
async incrementTime(minutes = 0) {
incrementTime(minutes = 0) {
this.calendrier.minutesRelative += minutes;
if (this.calendrier.minutesRelative >= 120) {
this.calendrier.minutesRelative -= 120;
@ -240,8 +192,14 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
incrementerJour() {
const index = this.getCurrentDayIndex() + 1;
this.calendrier = RdDCalendrier.getCalendrier(index);
this.calendrier.jour += 1;
if (this.calendrier.jour >= RDD_JOUR_PAR_MOIS) {
this.calendrier.jour -= RDD_JOUR_PAR_MOIS;
if (this.calendrier.jour <= 0)
this.calendrier.jour = 0;
this.calendrier.moisRdD += 1;
// Reconstruire les nombres astraux
}
this.rebuildListeNombreAstral();
}
@ -252,10 +210,9 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
async positionnerHeure(indexHeure) {
if (indexHeure <= this.calendrier.heureRdD) {
positionnerHeure(indexHeure) {
if (indexHeure <= this.calendrier.heureRdD)
this.incrementerJour();
}
this.calendrier.heureRdD = indexHeure;
this.calendrier.minutesRelative = 0;
game.settings.set("foundryvtt-reve-de-dragon", "calendrier", duplicate(this.calendrier));
@ -297,11 +254,10 @@ export class RdDCalendrier extends Application {
console.log(request);
let jourDiff = this.getLectureAstrologieDifficulte(request.date);
let niveau = Number(request.astrologie.data.niveau) + Number(request.conditions) + Number(jourDiff) + Number(request.etat);
let rollData = {
let rollData= {
caracValue: request.carac_vue,
finalLevel: niveau,
showDice: false,
rollMode: "blindroll"
showDice: false
};
await RdDResolutionTable.rollData(rollData);
let nbAstral = this.getNombreAstral(request.date);
@ -309,10 +265,11 @@ export class RdDCalendrier extends Application {
request.isValid = true;
if (!request.rolled.isSuccess) {
request.isValid = false;
nbAstral = await RdDDice.rollTotal("1dhr" + nbAstral, { showDice: true, rollMode: "selfroll" });
let nbAstralFaux = new Roll("1d11").evaluate().total;
nbAstral = nbAstral==nbAstralFaux ? 12 : nbAstralFaux;
// Mise à jour des nombres astraux du joueur
let astralData = this.listeNombreAstral.find((nombreAstral, i) => nombreAstral.index == request.date);
astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstral });
astralData.valeursFausses.push({ actorId: request.id, nombreAstral: nbAstralFaux });
game.settings.set("foundryvtt-reve-de-dragon", "liste-nombre-astral", this.listeNombreAstral);
}
request.nbAstral = nbAstral;
@ -328,27 +285,11 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
findHeure(heure) {
heure = Grammar.toLowerCaseNoAccentNoSpace(heure);
let parHeureOuLabel = Object.values(heuresDef).filter(it => (it.heure + 1) == heure || Grammar.toLowerCaseNoAccentNoSpace(it.label) == heure);
if (parHeureOuLabel.length == 1) {
return parHeureOuLabel[0];
}
let parLabelPartiel = Object.values(heuresDef).filter(it => Grammar.toLowerCaseNoAccentNoSpace(it.label).includes(heure));
const matchLength = heure.length;
if(parLabelPartiel.length > 0) {
parLabelPartiel.sort((a,b)=> (a.label.length - matchLength)^2 - (b.label.length- matchLength)^2);
return parLabelPartiel[0];
}
return undefined;
}
/* -------------------------------------------- */
getAjustementAstrologique(heureNaissance, name = undefined) {
let defHeure = this.findHeure(heureNaissance);
if (defHeure) {
let hn = defHeure.heure;
let chiffreAstral = this.getCurrentNombreAstral() ?? 0;
getAjustementAstrologique(heureNaissance, name = 'inconnu') {
let heure = Grammar.toLowerCaseNoAccent(heureNaissance);
if (heure && heuresDef[heure]) {
let hn = heuresDef[heure].heure;
let chiffreAstral = this.getCurrentNombreAstral();
let heureCourante = this.calendrier.heureRdD;
let ecartChance = (hn + chiffreAstral - heureCourante) % 12;
switch (ecartChance) {
@ -358,12 +299,9 @@ export class RdDCalendrier extends Application {
case 3: case 9: return -2;
}
}
else if (name) {
else {
ui.notifications.warn(name + " n'a pas d'heure de naissance, ou elle est incorrecte : " + heureNaissance);
}
else{
ui.notifications.warn(heureNaissance+" ne correspond pas à une heure de naissance");
}
return 0;
}
@ -401,9 +339,9 @@ export class RdDCalendrier extends Application {
updateDisplay() {
let data = this.fillCalendrierData();
// Rebuild data
let dateHTML = `Jour ${data.jourMois} de ${data.nomMois} (${data.nomSaison})`
let dateHTML = `Jour ${data.jourMois} de ${data.nomMois} (${data.nomSaison})`;
if (game.user.isGM) {
dateHTML = dateHTML + " - NA: " + (this.getCurrentNombreAstral() ?? "indéterminé");
dateHTML = dateHTML + " - NA: " + this.getCurrentNombreAstral();
}
for (let handle of document.getElementsByClassName("calendar-date-rdd")) {
handle.innerHTML = dateHTML;
@ -420,21 +358,21 @@ export class RdDCalendrier extends Application {
}
/* -------------------------------------------- */
async saveEditeur(calendrierData) {
saveEditeur(calendrierData) {
this.calendrier.minutesRelative = Number(calendrierData.minutesRelative);
this.calendrier.jour = Number(calendrierData.jourMois) - 1;
this.calendrier.moisRdD = heuresList.findIndex(mois => mois === calendrierData.moisKey);
this.calendrier.heureRdD = heuresList.findIndex(heure => heure === calendrierData.heureKey);; // Index dans heuresList
game.settings.set("foundryvtt-reve-de-dragon", "calendrier", duplicate(this.calendrier));
await this.rebuildListeNombreAstral();
this.rebuildListeNombreAstral();
this.updateDisplay();
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_sync_time",
data: duplicate(this.calendrier)
});
this.updateDisplay();
}
/* -------------------------------------------- */
@ -464,7 +402,7 @@ export class RdDCalendrier extends Application {
}
astrologieArray.push(duplicate(astralData));
}
//console.log("ASTRO", astrologieArray);
//console.log("ASTRO", astrologieArray);
calendrierData.astrologieData = astrologieArray;
let html = await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/calendar-astrologie-template.html', calendrierData);
let astrologieEditeur = new RdDAstrologieEditeur(html, this, calendrierData)
@ -474,12 +412,12 @@ export class RdDCalendrier extends Application {
/* -------------------------------------------- */
/** @override */
async activateListeners(html) {
activateListeners(html) {
super.activateListeners(html);
HtmlUtility._showControlWhen($(".gm-only"), game.user.isGM);
await this.updateDisplay();
this.updateDisplay();
html.find('.calendar-btn').click(ev => this.onCalendarButton(ev));

View File

@ -1,5 +1,4 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
const tableCaracDerivee = {
// xp: coût pour passer du niveau inférieur à ce niveau
@ -39,6 +38,29 @@ const tableCaracDerivee = {
export class RdDCarac {
/* -------------------------------------------- */
static findCarac(carac, name) {
name = Grammar.toLowerCaseNoAccent(name);
const pairs = Object.entries(carac)
.filter(([key, value]) => key.includes(name) || Grammar.toLowerCaseNoAccent(value.label).includes(name));
let c = pairs.find(([key, value]) => key == name || Grammar.toLowerCaseNoAccent(value.label) == name);
if (c) {
return c[1];
}
pairs.sort((a, b) => a[0].length- b[0].length);
if (pairs.length > 0) {
c = pairs[0][1];
if (pairs.length > 1) {
const labels = pairs.map(pair => pair[1].label).reduce((a, b) => `${a}<br>${b}`);
ui.notifications.info(`Plusieurs caractéristiques possibles:<br>${labels}<br>La première sera choisie: ${c.label}.`);
}
return c;
}
return undefined;
}
static isAgiliteOuDerivee(selectedCarac) {
return selectedCarac?.label.match(/(Agilité|Dérobée)/);
}
@ -52,19 +74,17 @@ export class RdDCarac {
return selectedCarac?.label?.toLowerCase()?.match(/r(e|ê)ve(( |-)actuel)?/);
}
static isIgnoreEtatGeneral(rollData) {
const selectedCarac = rollData.selectedCarac;
static isIgnoreEtatGeneral(selectedCarac, competence) {
return !selectedCarac ||
rollData.ethylisme ||
RdDCarac.isChance(selectedCarac) ||
(RdDCarac.isReve(selectedCarac) && !rollData.competence);
(RdDCarac.isReve(selectedCarac) && !competence);
}
static computeTotal(carac, beaute = undefined) {
const total = Object.values(carac).filter(c => !c.derivee)
.map(it => parseInt(it.value))
.reduce(Misc.sum(), 0);
.reduce((a, b) => a + b, 0);
const beauteSuperieur10 = Math.max((beaute ?? 10) - 10, 0);
return total + beauteSuperieur10;
}
@ -97,7 +117,7 @@ export class RdDCarac {
* ainsi que de Perception active et volontaire.
*/
static isActionPhysique(selectedCarac) {
return Grammar.toLowerCaseNoAccent(selectedCarac?.label)?.match(/(apparence|force|agilite|dexterite|vue|ouie|odorat|empathie|melee|tir|lancer|derobee)/);
return Grammar.toLowerCaseNoAccent(selectedCarac?.label).match(/(apparence|force|agilite|dexterite|vue|ouie|odorat|empathie|melee|tir|lancer|derobee)/);
}
/* -------------------------------------------- */

View File

@ -75,36 +75,38 @@ export class RdDCombatManager extends Combat {
const currentId = this.combatant._id;
// calculate initiative
for (let cId = 0; cId < ids.length; cId++) {
const combatant = this.getCombatant(ids[cId]);
const c = this.getCombatant(ids[cId]);
//if (!c) return results;
let rollFormula = formula; // Init per default
console.log("RR :", rollFormula);
if (!rollFormula) {
let armeCombat, competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
for (const competenceItemData of combatant.actor.data.items) {
if (c.actor.data.type == 'creature' || c.actor.data.type == 'entite') {
for (const competenceItemData of c.actor.data.items) {
if (competenceItemData.data.iscombat) {
competence = duplicate(competenceItemData);
}
}
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, competence.data.carac_value) + ")/100)";
} else {
for (const itemData of combatant.actor.data.items) {
for (const itemData of c.actor.data.items) {
if (itemData.type == "arme" && itemData.data.equipe) {
armeCombat = duplicate(itemData);
}
}
let compName = (armeCombat == undefined) ? "Corps à corps" : armeCombat.data.competence;
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, compName);
competence = RdDItemCompetence.findCompetence(c.actor.data.items, compName);
let bonusEcaille = (armeCombat && armeCombat.data.magique) ? armeCombat.data.ecaille_efficacite : 0;
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
rollFormula = "2+( (" + RdDCombatManager.calculInitiative(competence.data.niveau, Misc.data(c.actor).data.carac[competence.data.defaut_carac].value, bonusEcaille) + ")/100)";
}
}
//console.log("Combatat", c);
const roll = combatant.getInitiativeRoll(rollFormula);
console.log("RR :", rollFormula);
const roll = super._getInitiativeRoll(c, rollFormula);
if (roll.total <= 0) roll.total = 0.00;
console.log("Compute init for", rollFormula, roll.total);
await this.updateEmbeddedDocuments("Combatant", [{ _id: combatant._id, initiative: roll.total }]);
await this.updateEmbeddedEntity("Combatant", { _id: c._id, initiative: roll.total });
// Send a chat message
let rollMode = messageOptions.rollMode || game.settings.get("core", "rollMode");
@ -112,12 +114,12 @@ export class RdDCombatManager extends Combat {
{
speaker: {
scene: canvas.scene._id,
actor: combatant.actor ? combatant.actor._id : null,
token: combatant.token._id,
alias: combatant.token.name,
actor: c.actor ? c.actor._id : null,
token: c.token._id,
alias: c.token.name,
sound: CONFIG.sounds.dice,
},
flavor: `${combatant.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
flavor: `${c.token.name} a fait son jet d'Initiative (${messageOptions.initInfo})
<br>
`,
},
@ -143,31 +145,35 @@ export class RdDCombatManager extends Combat {
// Gestion des armes 1/2 mains
let armesEquipe = [];
for (const arme of armes) {
let armeData = Misc.data(arme);
if (armeData.data.equipe) {
let compData = competences.map(c => Misc.data(c)).find(c => c.name == armeData.data.competence);
armesEquipe.push(armeData);
armeData.data.initiative = RdDCombatManager.calculInitiative(armeData.data.niveau, carac[compData.data.defaut_carac].value);
if (arme.data.equipe) {
armesEquipe.push(arme);
let comp = competences.find(c => c.name == arme.data.competence);
arme.data.initiative = RdDCombatManager.calculInitiative(arme.data.niveau, carac[comp.data.defaut_carac].value);
// Dupliquer les armes pouvant être à 1 main et 2 mains en patchant la compétence
if (armeData.data.unemain && !armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
} else if (!armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(2m)";
} else if (armeData.data.unemain && armeData.data.deuxmains) {
armeData.data.mainInfo = "(1m)";
let arme2main = duplicate(armeData);
if (arme.data.unemain && !arme.data.deuxmains) {
arme.data.mainInfo = "(1m)";
} else if (!arme.data.unemain && arme.data.deuxmains) {
arme.data.mainInfo = "(2m)";
} else if (arme.data.unemain && arme.data.deuxmains) {
arme.data.mainInfo = "(1m)";
let arme2main = duplicate(arme);
arme2main.data.mainInfo = "(2m)";
arme2main.data.dommages = arme2main.data.dommages.split("/")[1]; // Existence temporaire uniquement dans la liste des armes, donc OK
arme2main.data.competence = arme2main.data.competence.replace(" 1 main", " 2 mains"); // Replace !
let comp = Misc.data(competences.find(c => c.name == arme2main.data.competence));
let comp = competences.find(c => c.name == arme2main.data.competence);
arme2main.data.niveau = comp.data.niveau;
arme2main.data.initiative = RdDCombatManager.calculInitiative(arme2main.data.niveau, carac[comp.data.defaut_carac].value);
armesEquipe.push(arme2main);
}
}
}
return armesEquipe.sort(Misc.ascending(armeData => armeData.name + (armeData.data.mainInfo ?? '')));
return armesEquipe.sort((a, b) => {
const nameA = a.name + (a.data.mainInfo ?? '');
const nameB = b.name + (b.data.mainInfo ?? '');
if (nameA > nameB) return 1;
if (nameA < nameB) return -1;
return 0;
});
}
/* -------------------------------------------- */
@ -185,6 +191,7 @@ export class RdDCombatManager extends Combat {
} else {
// Recupération des items 'arme'
let armes = items.filter(it => RdDItemArme.isArmeUtilisable(it))
.map(arme => duplicate(arme)) /* pas de changements aux armes d'origine */
.concat(RdDItemArme.mainsNues());
let competences = items.filter(it => it.type == 'competence');
@ -266,7 +273,7 @@ export class RdDCombatManager extends Combat {
let initOffset = 0;
let caracForInit = 0;
let compNiveau = 0;
let compData = { name: "Aucune" };
let competence = { name: "Aucune" };
if (combatant.actor.getSurprise() == "totale") {
initOffset = -1; // To force 0
initInfo = "Surprise Totale"
@ -281,24 +288,24 @@ export class RdDCombatManager extends Combat {
initInfo = "Draconic"
} else {
initOffset = 3; // Melée = 3.XX
compData = Misc.data(RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence));
compNiveau = compData.data.niveau;
competence = RdDItemCompetence.findCompetence(combatant.actor.data.items, arme.data.competence);
compNiveau = competence.data.niveau;
initInfo = arme.name + " / " + arme.data.competence;
if (combatant.actor.data.type == 'creature' || combatant.actor.data.type == 'entite') {
caracForInit = compData.data.carac_value;
if (compData.data.categorie == "lancer") {
caracForInit = competence.data.carac_value;
if (competence.data.categorie == "lancer") {
initOffset = 5;
}
} else {
caracForInit = Misc.data(combatant.actor).data.carac[compData.data.defaut_carac].value;
if (compData.data.categorie == "lancer") { // Offset de principe pour les armes de jet
caracForInit = Misc.data(combatant.actor).data.carac[competence.data.defaut_carac].value;
if (competence.data.categorie == "lancer") { // Offset de principe pour les armes de jet
initOffset = 4;
}
if (compData.data.categorie == "tir") { // Offset de principe pour les armes de jet
if (competence.data.categorie == "tir") { // Offset de principe pour les armes de jet
initOffset = 5;
}
if (compData.data.categorie == "melee") { // Offset de principe pour les armes de jet
if (competence.data.categorie == "melee") { // Offset de principe pour les armes de jet
initOffset = 3;
}
}
@ -338,8 +345,8 @@ export class RdDCombat {
static init() {
this.initStorePasseArmes();
Hooks.on("updateCombat", (combat, change, options, userId) => { RdDCombat.onUpdateCombat(combat, change, options, userId) });
Hooks.on("preDeleteCombat", (combat, options, userId) => { RdDCombat.onPreDeleteCombat(combat, options, userId); });
Hooks.on("updateCombat", (combat, data) => { RdDCombat.onUpdateCombat(combat, data) });
Hooks.on("preDeleteCombat", (combat, options) => { RdDCombat.onPreDeleteCombat(combat, options); });
}
/* -------------------------------------------- */
@ -363,14 +370,14 @@ export class RdDCombat {
}
/* -------------------------------------------- */
static onUpdateCombat(combat, change, options, userId) {
static onUpdateCombat(combat, data) {
if (combat.data.round != 0 && combat.turns && combat.data.active) {
RdDCombat.combatNouveauTour(combat);
}
}
/* -------------------------------------------- */
static onPreDeleteCombat(combat, options, userId) {
static onPreDeleteCombat(combat, options) {
if (game.user.isGM) {
combat.cleanItemUse();
ChatUtility.removeChatMessageContaining(`<div data-combatid="${combat.id}" data-combatmessage="actor-turn-summary">`)
@ -393,11 +400,9 @@ export class RdDCombat {
/* -------------------------------------------- */
static combatNouveauTour(combat) {
if (Misc.isElectedUser()) {
let turn = combat.turns.find(t => t.token?.id == combat.current.tokenId);
if (turn?.actor) {
RdDCombat.displayActorCombatStatus(combat, turn.actor);
// TODO Playaudio for player??
}
let turn = combat.turns.find(t => t.tokenId == combat.current.tokenId);
this.displayActorCombatStatus(combat, turn.actor);
// TODO Playaudio for player??
}
}
@ -511,12 +516,15 @@ export class RdDCombat {
RdDCombat._deleteDefense(attackerRoll.passeArme);
RdDCombat._deleteAttaque(data.attackerId);
}
}
/* -------------------------------------------- */
static onMsgDefense(msg) {
let defenderToken = canvas.tokens.get(msg.defenderTokenId);
if (!game.user.isGM && !game.user.character) { // vérification / sanity check
ui.notifications.error("Le joueur " + game.user.name + " n'est connecté à aucun personnage. Impossible de continuer.");
return;
}
if (defenderToken && Misc.isElectedUser()) {
const rddCombat = RdDCombat.createForAttackerAndDefender(msg.attackerId, msg.defenderTokenId);
if (rddCombat) {
@ -814,19 +822,21 @@ export class RdDCombat {
}
// # utilisation esquive
const esquive = Misc.data(this.defender.getCompetence("esquive"));
const corpsACorps = Misc.data(this.defender.getCompetence("Corps à corps"));
const esquiveUsage = esquive ? this.defender.getItemUse(esquive._id) : 0;
let esquiveUsage = 0;
let esquive = this.defender.getCompetence("esquive");
if (esquive) {
esquiveUsage = this.defender.getItemUse(esquive._id);
}
const paramChatDefense = {
passeArme: attackerRoll.passeArme,
essais: attackerRoll.essais,
defender: Misc.data(this.defender),
attacker: Misc.data(this.attacker),
defender: this.defender,
attacker: this.attacker,
attackerId: this.attackerId,
esquiveUsage: esquiveUsage,
defenderTokenId: this.defenderTokenId,
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && corpsACorps,
mainsNues: attackerRoll.dmg.mortalite != 'mortel' && this.defender.getCompetence("Corps à corps"),
armes: this._filterArmesParade(this.defender, attackerRoll.competence, attackerRoll.arme),
diffLibre: attackerRoll.ajustements?.diffLibre?.value ?? 0,
attaqueParticuliere: attackerRoll.particuliere,
@ -863,7 +873,7 @@ export class RdDCombat {
attackerId: this.attacker?.data._id,
defenderId: this.defender?.data._id,
defenderTokenId: this.defenderTokenId,
defenderRoll: defenderRoll,
defenderRoll: duplicate(defenderRoll),
paramChatDefense: paramChatDefense,
rollMode: true
}
@ -899,7 +909,7 @@ export class RdDCombat {
whisper: ChatUtility.getWhisperRecipientsAndGMs(this.attacker.name),
content: await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/chat-demande-attaque-etotal.html', {
attackerId: this.attackerId,
attacker: Misc.data(this.attacker),
attacker: this.attacker,
defenderTokenId: this.defenderTokenId,
essais: attackerRoll.essais
})
@ -911,7 +921,7 @@ export class RdDCombat {
console.log("RdDCombat._onEchecTotal >>>", rollData);
const arme = rollData.arme;
const avecArme = arme && arme.data.categorie_parade != 'sans-armes';
const avecArme = arme?.data.categorie_parade != 'sans-armes';
const action = (rollData.attackerRoll ? (arme ? "la parade" : "l'esquive") : "l'attaque");
ChatUtility.createChatWithRollMode(this.defender.name, {
content: `<strong>Maladresse à ${action}!</strong> ` + await RdDRollTables.getMaladresse({ arme: avecArme })
@ -970,18 +980,17 @@ export class RdDCombat {
_prepareParade(attackerRoll, armeParade) {
const compName = armeParade.data.competence;
const armeAttaque = attackerRoll.arme;
const parade = Misc.data(this.defender.getCompetence(compName));
let defenderRoll = {
passeArme: attackerRoll.passeArme,
diffLibre: attackerRoll.diffLibre,
attackerRoll: attackerRoll,
competence: parade,
competence: this.defender.getCompetence(compName),
arme: armeParade,
surprise: this.defender.getSurprise(true),
needParadeSignificative: ReglesOptionelles.isUsing('categorieParade') && RdDItemArme.needParadeSignificative(armeAttaque, armeParade),
needResist: RdDItemArme.needArmeResist(armeAttaque, armeParade),
carac: Misc.templateData(this.defender).carac,
carac: this.defender.data.data.carac,
show: {}
};
@ -1027,7 +1036,7 @@ export class RdDCombat {
/* -------------------------------------------- */
async esquive(attackerRoll) {
const esquive = Misc.data(this.defender.getCompetence("esquive"));
let esquive = this.defender.getCompetence("esquive");
if (esquive == undefined) {
ui.notifications.error(this.defender.name + " n'a pas de compétence 'esquive'");
return;
@ -1061,7 +1070,7 @@ export class RdDCombat {
competence: competence,
surprise: this.defender.getSurprise(true),
surpriseDefenseur: this.defender.getSurprise(true),
carac: Misc.templateData(this.defender).carac,
carac: this.defender.data.data.carac,
show: {}
};
@ -1129,7 +1138,7 @@ export class RdDCombat {
resistance -= perteResistance;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = perteResistance;
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
}
}
} else {
@ -1146,7 +1155,7 @@ export class RdDCombat {
resistance -= dmg;
defenderRoll.show.deteriorationArme = resistance <= 0 ? 'brise' : 'perte';
defenderRoll.show.perteResistance = dmg;
this.defender.updateEmbeddedDocuments('Item', [{ _id: defenderRoll.arme._id, 'data.resistance': resistance }]);
this.defender.updateEmbeddedEntity("OwnedItem", { _id: defenderRoll.arme._id, 'data.resistance': resistance });
}
}
// Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
@ -1220,14 +1229,14 @@ export class RdDCombat {
await this.computeRecul(defenderRoll);
this.defender.encaisserDommages(attackerRoll, this.attacker, defenderRoll);
}
else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
} else { // envoi à un GM: les joueurs n'ont pas le droit de modifier les personnages qu'ils ne possèdent pas
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_encaisser",
data: {
attackerId: this.attackerId,
defenderTokenId: defenderTokenId,
attackerRoll: attackerRoll
attackerRoll: attackerRoll,
gmId: game.users.entities.find(u => u.isGM)?.id,
}
});
}
@ -1245,7 +1254,7 @@ export class RdDCombat {
return true;
}
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(Misc.templateData(this.defender).carac.niveau.value));
let rolled = await RdDResolutionTable.roll(this.attacker.getReveActuel(), - Number(this.defender.data.data.carac.niveau.value));
let message = {
content: "Jet de points actuels de rêve à " + rolled.finalLevel + RdDResolutionTable.explain(rolled) + "<br>",

View File

@ -1,6 +1,5 @@
/* -------------------------------------------- */
import { DialogCreateSigneDraconique } from "./dialog-create-signedraconique.js";
import { RdDItemCompetence } from "./item-competence.js";
import { Misc } from "./misc.js";
import { RdDCarac } from "./rdd-carac.js";
@ -13,7 +12,7 @@ import { RdDUtility } from "./rdd-utility.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { TMRUtility } from "./tmr-utility.js";
const rddRollNumeric = /^(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
const rddRollNumeric = /$(\d+)\s*([\+\-]?\d+)?\s*(s)?/;
/* -------------------------------------------- */
export class RdDCommands {
@ -79,31 +78,10 @@ export class RdDCommands {
<br><strong>/payer 10d</strong> permet d'envoyer un message pour payer 10 deniers`
});
rddCommands.registerCommand({
path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(RdDCommands.toParamString(params)),
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples pour l'heure de la Lyre:
<br><strong>/astro 7</strong>
<br><strong>/astro Lyre</strong>
<br><strong>/astro Lyr</strong>`
path: ["/astro"], func: (content, msg, params) => RdDUtility.afficherHeuresChanceMalchance(params[0]),
descr: `Affiche les heures de chance et de malchance selon l'heure de naissance donnée en argument. Exemples:
<br><strong>/astro Lyre</strong>`
});
rddCommands.registerCommand({
path: ["/signe", "+"], func: (content, msg, params) => rddCommands.creerSignesDraconiques(),
descr: "Crée un signe draconique et l'ajoute aux haut-rêvants choisis."
});
rddCommands.registerCommand({
path: ["/signe", "-"], func: (content, msg, params) => rddCommands.supprimerSignesDraconiquesEphemeres(),
descr: "Supprime les signes draconiques éphémères"
});
rddCommands.registerCommand({
path: ["/stress"], func: (content, msg, params) => RdDUtility.distribuerStress(params[0], params[1], params[2]),
descr: `Distribue du stress aux personnages. Exemples:
<br><strong>/stress 6</strong> : Distribue 6 points des Stress à tout les personnages joueurs, sans raison renseignée
<br><strong>/stress 6 Tigre</strong> : Distribue 6 points des Stress à tout les personnages joueurs, à cause d'un Tigre Vert
<br><strong>/stress 6 Glou Paulo</strong> : Distribue 6 points de Stres à l'acteur connecté au joueur Paulo, à cause d'un Glou`
});
game.system.rdd.commands = rddCommands;
}
}
@ -111,10 +89,6 @@ export class RdDCommands {
this.commandsTable = {};
}
static toParamString(params) {
return params.length == 1 ? params[0] : params.reduce((a, b) => `${a} ${b}`, '');
}
/* -------------------------------------------- */
registerCommand(command) {
this._addCommand(this.commandsTable, command.path, '', command);
@ -214,7 +188,7 @@ export class RdDCommands {
/* -------------------------------------------- */
static _chatAnswer(msg, content) {
msg.whisper = [game.user.id];
msg.whisper = [game.user._id];
msg.content = content;
ChatMessage.create(msg);
}
@ -289,7 +263,7 @@ export class RdDCommands {
finalLevel: diff,
showDice: true,
diviseurSignificative: significative ? 2 : 1,
show: { title: "Table de résolution"}
show: { title: "Table de résolution" }
};
await RdDResolutionTable.rollData(rollData);
RdDCommands._chatAnswer(msg, await RdDResolutionTable.buildRollDataHtml(rollData));
@ -297,14 +271,16 @@ export class RdDCommands {
/* -------------------------------------------- */
async rollDeDraconique(msg) {
let ddr = await RdDDice.rollTotal("1dr + 7", { showDice:true });
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr}`);
let ddr = new Roll("1dr + 7").evaluate();
ddr.showDice = true;
await RdDDice.showDiceSoNice(ddr);
RdDCommands._chatAnswer(msg, `Lancer d'un Dé draconique: ${ddr.total}`);
}
async getTMRAleatoire(msg, params) {
getTMRAleatoire(msg, params) {
if (params.length < 2) {
let type = params[0];
const tmr = await TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
const tmr = TMRUtility.getTMRAleatoire(type ? (it => it.type == type) : (it => true));
RdDCommands._chatAnswer(msg, `Case aléatoire: ${tmr.coord} - ${tmr.label}`);
}
else {
@ -336,20 +312,5 @@ export class RdDCommands {
}
}
async creerSignesDraconiques() {
DialogCreateSigneDraconique.createSigneForActors();
return true;
}
async supprimerSignesDraconiquesEphemeres() {
game.actors.forEach(actor => {
const ephemeres = actor.filterItems(item => Misc.data(item).type = 'signedraconique' && Misc.data(item).data.ephemere)
.map(item => item.id);
if (ephemeres.length > 0) {
actor.deleteEmbeddedDocuments("Item", ephemeres);
}
});
return true;
}
}

View File

@ -1,29 +1,59 @@
import { Misc } from "./misc.js";
/* -------------------------------------------- */
/**
* Mapping des types d'Item/Actor vers le nom d'affichage.
* Par défaut, on prend le type avec la première lettre
* majuscule, pas besoin d'ajouter tous les types.
*/
const typeDisplayName = {
"competence": "Compétence",
"herbe": "Plante",
"ingredient": "Ingrédient",
"queue": "Queue de dragon",
"ombre": "Ombre de Thanatos",
"souffle": "Souffle de Dragon",
"tete": "Tête de Dragon",
"ingredient": "Ingrédient",
"rencontresTMR": "Rencontre des TMR",
"competencecreature": "Compétence de créature",
"nombreastral": "Nombre astral",
"casetmr": "Effet sur TMR",
"recettealchimique": "Recette alchimique",
"recettecuisine": "Recette de cuisine",
"tarot": "Carte de tarot draconique",
"tache": "Tâche",
"meditation": "Méditation",
"musique": "Morceau de musique",
"chant": "Chanson",
"creature": "Créature",
"entite": "Entité",
"vehicule": "Véhicule"
}
export class RddCompendiumOrganiser {
static init() {
Hooks.on('renderCompendium', async (pack, html, data) => RddCompendiumOrganiser.onRenderCompendium(pack, html, data))
}
static async onRenderCompendium(compendium, html, data) {
console.log('onRenderCompendium', compendium, html, data);
const pack = compendium.collection
static async onRenderCompendium(pack, html, data) {
console.log('onRenderCompendium', pack, html, data);
if (pack.metadata.system === 'foundryvtt-reve-de-dragon') {
const content = await pack.getContent();
html.find('.directory-item').each((i, element) => {
RddCompendiumOrganiser.setEntityTypeName(pack, element);
let entity = content.find(it => it._id === element.dataset.entryId);
if (entity?.entity === 'Actor' || entity?.entity === 'Item') {
const typeName = typeDisplayName[entity.data.type] ?? Misc.upperFirst(entity.data.type);
RddCompendiumOrganiser.insertEntityType(element, typeName);
}
});
}
}
static async setEntityTypeName(pack, element) {
const label = Misc.getEntityTypeLabel(await pack.getDocument(element.dataset.documentId));
RddCompendiumOrganiser.insertEntityType(element, label);
}
static insertEntityType(element, label) {
if (label) {
element.children[1].insertAdjacentHTML('afterbegin', `<label class="type-compendium">${label}: </label>`);
}
static insertEntityType(element, type) {
element.children[1].insertAdjacentHTML('afterbegin', `<label>${type}: </label>`);
}
}

View File

@ -25,7 +25,7 @@ export class De7 extends Die {
return {
type: "d7",
font: "HeuresDraconiques",
fontScale: 0.7,
fontScale : 0.7,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system
}
@ -36,7 +36,7 @@ export class De7 extends Die {
super(termData);
}
async evaluate() {
evaluate() {
super.evaluate();
this.explode("x=8");
return this;
@ -46,11 +46,11 @@ export class De7 extends Die {
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0);
}
getResultLabel(diceTerm) {
switch (diceTerm.result) {
static getResultLabel(result) {
switch (result) {
case 7: return imgSigneDragon;
}
return diceTerm.result.toString();
return result;
}
}
@ -62,7 +62,7 @@ export class DeDraconique extends Die {
return {
type: "dr",
font: "HeuresDraconiques",
fontScale: 0.7,
fontScale : 0.7,
labels: ['1', '2', '3', '4', '5', '6', 'd', '0'],
system: system
}
@ -73,7 +73,7 @@ export class DeDraconique extends Die {
super(termData);
}
async evaluate() {
evaluate() {
super.evaluate();
this.explode("x=7");
return this;
@ -83,12 +83,12 @@ export class DeDraconique extends Die {
return this.values.filter(it => it != 8).reduce(Misc.sum(), 0);
}
getResultLabel(diceTerm) {
switch (diceTerm.result) {
static getResultLabel(result) {
switch (result) {
case 7: return imgSigneDragon;
case 8: return '0';
case 8: return 0;
}
return diceTerm.result.toString();
return result;
}
}
@ -112,8 +112,8 @@ export class DeHeure extends Die {
super(termData);
}
getResultLabel(diceTerm) {
return img(imagesHeures[diceTerm.result - 1]);
static getResultLabel(result) {
return img(imagesHeures[result-1]);
}
}
@ -123,33 +123,6 @@ export class RdDDice {
CONFIG.Dice.terms[DeDraconique.DENOMINATION] = DeDraconique;
CONFIG.Dice.terms[DeHeure.DENOMINATION] = DeHeure;
}
static onReady() {
if (game.modules.get("dice-so-nice")?.active) {
if (game.settings.get("core", "noCanvas")) {
ui.notifications.warn("Dice So Nice! n'affichera pas de dés car vous avez coché l'option de Foundry 'Scène de jeu désactivé' 'Disable Game Canvas' ");
}
}
}
static async roll(formula, options = { showDice: false, rollMode: undefined }) {
const roll = new Roll(formula);
await roll.evaluate({ async: true });
if (!options.hideDice) {
roll.showDice = options.showDice;
await RdDDice.show(roll, options.rollMode ?? game.settings.get("core", "rollMode"));
}
return roll;
}
static async rollTotal(formula, options = { showDice: false, hideDice: false }) {
const roll = await RdDDice.roll(formula, options);
return roll.total;
}
static async rollOneOf(array) {
const roll = await RdDDice.rollTotal(`1d${array.length}`);
return array[roll - 1];
}
static diceSoNiceReady(dice3d) {
for (const system of Object.keys(dice3d.DiceFactory.systems)) {
@ -160,7 +133,7 @@ export class RdDDice {
}
/* -------------------------------------------- */
static async show(roll, rollMode) {
static async show(roll, rollMode = undefined) {
if (roll.showDice || game.settings.get(SYSTEM_RDD, "dice-so-nice") == true) {
await this.showDiceSoNice(roll, rollMode);
}
@ -168,27 +141,25 @@ export class RdDDice {
}
/* -------------------------------------------- */
static async showDiceSoNice(roll, rollMode) {
if (game.modules.get("dice-so-nice")?.active) {
if (game.dice3d) {
let whisper = null;
let blind = false;
rollMode = rollMode ?? game.settings.get("core", "rollMode");
switch (rollMode) {
case "blindroll": //GM only
blind = true;
case "gmroll": //GM + rolling player
whisper = ChatUtility.getUsers(user => user.isGM);
break;
case "roll": //everybody
whisper = ChatUtility.getUsers(user => user.active);
break;
case "selfroll":
whisper = [game.user.id];
break;
}
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
static async showDiceSoNice(roll, rollMode = undefined) {
if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) {
let whisper = null;
let blind = false;
rollMode = rollMode ?? game.settings.get("core", "rollMode");
switch (rollMode) {
case "blindroll": //GM only
blind = true;
case "gmroll": //GM + rolling player
whisper = ChatUtility.getUsers(user => user.isGM);
break;
case "roll": //everybody
whisper = ChatUtility.getUsers(user => user.active);
break;
case "selfroll":
whisper = [game.user._id];
break;
}
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind);
}
}
}

View File

@ -1,76 +0,0 @@
/* -------------------------------------------- */
import { RdDUtility } from "./rdd-utility.js";
import { Misc } from "./misc.js";
import { RdDCalendrier } from "./rdd-calendrier.js";
/* -------------------------------------------- */
export class RdDHerbes extends Item {
/* -------------------------------------------- */
static isHerbeSoin( botaniqueItem ) {
return Misc.templateData(botaniqueItem).categorie == 'Soin';
}
/* -------------------------------------------- */
static isHerbeRepos( botaniqueItem ) {
return Misc.templateData(botaniqueItem).categorie == 'Repos';
}
/* -------------------------------------------- */
static async initializeHerbes( ) {
this.herbesSoins = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeSoin(item));
this.herbesRepos = await RdDUtility.loadCompendium('foundryvtt-reve-de-dragon.botanique', item => this.isHerbeRepos(item));
}
/* -------------------------------------------- */
static buildHerbesList(listHerbes, max) {
let list = {}
for ( let herbe of listHerbes) {
let herbeData = Misc.templateData(herbe);
let brins = max - herbeData.niveau;
list[herbe.data.name] = `${herbe.data.name} (Bonus: ${herbeData.niveau}, Brins: ${brins})`;
}
list['Autre'] = 'Autre (Bonus: variable, Brins: variable)'
return list;
}
/* -------------------------------------------- */
static updatePotionData( formData ) {
formData.herbesSoins = this.buildHerbesList(this.herbesSoins, 12);
formData.herbesRepos = this.buildHerbesList(this.herbesRepos, 7);
formData.jourMoisOptions = Array(28).fill().map((item, index) => 1 + index);
formData.dateActuelle = game.system.rdd.calendrier.getDateFromIndex();
formData.splitDate = game.system.rdd.calendrier.getNumericDateFromIndex(formData.data.prdate);
if (formData.data.categorie.includes('Soin') ) {
formData.isHerbe = true;
this.computeHerbeBonus(formData, this.herbesSoins, 12);
} else if (formData.data.categorie.includes('Repos')) {
formData.isRepos = true;
this.computeHerbeBonus(formData, this.herbesRepos, 7);
}
}
/* -------------------------------------------- */
static calculePointsRepos( data ) {
return data.herbebonus * data.pr;
}
/* -------------------------------------------- */
static calculePointsGuerison( data ){
return data.herbebonus * data.pr;
}
/* -------------------------------------------- */
static computeHerbeBonus( formData, herbesList, max) {
if ( Number(formData.data.herbebrins) ) {
let herbe = herbesList.find(item => item.name.toLowerCase() == formData.data.herbe.toLowerCase() );
if( herbe ) {
let herbeData = Misc.templateData(herbe);
let brinsBase = max - herbeData.niveau;
//console.log(herbeData, brinsBase, formData.data.herbebrins);
formData.data.herbebonus = Math.max(herbeData.niveau - Math.max(brinsBase - formData.data.herbebrins, 0), 0);
}
}
}
}

View File

@ -9,12 +9,12 @@ export class RdDHotbar {
*/
static initDropbar( ) {
Hooks.on("hotbarDrop", async (bar, documentData, slot) => {
Hooks.on("hotbarDrop", async (bar, data, slot) => {
// Create item macro if rollable item - weapon, spell, prayer, trait, or skill
if (documentData.type == "Item") {
if (documentData.data.type != "arme" && documentData.data.type != "competence" )
if (data.type == "Item") {
if (data.data.type != "arme" && data.data.type != "competence" )
return
let item = documentData.data
let item = data.data
let command = `game.system.rdd.RdDHotbar.rollMacro("${item.name}", "${item.type}");`;
let macro = game.macros.entities.find(m => (m.name === item.name) && (m.command === command));
if (!macro) {
@ -28,9 +28,9 @@ export class RdDHotbar {
game.user.assignHotbarMacro(macro, slot);
}
// Create a macro to open the actor sheet of the actor dropped on the hotbar
else if (documentData.type == "Actor") {
let actor = game.actors.get(documentData.id);
let command = `game.actors.get("${documentData.id}").sheet.render(true)`
else if (data.type == "Actor") {
let actor = game.actors.get(data.id);
let command = `game.actors.get("${data.id}").sheet.render(true)`
let macro = game.macros.entities.find(m => (m.name === actor.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
@ -43,15 +43,15 @@ export class RdDHotbar {
}
}
// Create a macro to open the journal sheet of the journal dropped on the hotbar
else if (documentData.type == "JournalEntry") {
let journal = game.journal.get(documentData.id);
let command = `game.journal.get("${documentData.id}").sheet.render(true)`
else if (data.type == "JournalEntry") {
let journal = game.journal.get(data.id);
let command = `game.journal.get("${data.id}").sheet.render(true)`
let macro = game.macros.entities.find(m => (m.name === journal.name) && (m.command === command));
if (!macro) {
macro = await Macro.create({
name: journal.data.name,
type: "script",
img: "systems/foundryvtt-reve-de-dragon/icons/templates/icone_parchement_vierge.png",
img: "systems/wfrp4e/icons/buildings/scroll.png",
command: command
}, { displaySheet: false })
game.user.assignHotbarMacro(macro, slot);

View File

@ -28,10 +28,7 @@ import { ReglesOptionelles } from "./regles-optionelles.js";
import { TMRRencontres } from "./tmr-rencontres.js";
import { RdDHotbar } from "./rdd-hotbar-drop.js"
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { RdDHerbes } from "./rdd-herbes.js";
import { RdDItem } from "./item.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDSigneDraconiqueItemSheet } from "./item-signedraconique-sheet.js";
/* -------------------------------------------- */
/* Foundry VTT Initialization */
@ -49,7 +46,8 @@ Hooks.once("init", async function () {
game.system.rdd = {
TMRUtility,
RdDUtility,
RdDHotbar
RdDHotbar,
RdDResolutionTable
}
/* -------------------------------------------- */
@ -72,7 +70,6 @@ Hooks.once("init", async function () {
name: "calendrier",
scope: "world",
config: false,
default: RdDCalendrier.getCalendrier(0),
type: Object
});
@ -81,16 +78,14 @@ Hooks.once("init", async function () {
name: "liste-nombre-astral",
scope: "world",
config: false,
default: [],
type: Object
});
/* -------------------------------------------- */
game.settings.register("foundryvtt-reve-de-dragon", "calendrier-pos", {
name: "calendrierPos",
scope: "client",
scope: "world",
config: false,
default: RdDCalendrier.createCalendrierPos(),
type: Object
});
@ -121,21 +116,7 @@ Hooks.once("init", async function () {
config: true,
default: true,
type: Boolean
});
/* -------------------------------------------- */
game.settings.register("foundryvtt-reve-de-dragon", "appliquer-famine-soif", {
name: "Notifier de la famine et la soif pour",
hint: "Indique si les cas de famine et de soif seront indiqués durant Château Dormant",
scope: "world",
config: true,
type: String,
choices: {
"aucun": "ni la famine, ni la soif",
"famine": "seulement la famine",
"famine-soif": "la famine et la soif",
},
default: "aucun"
});
});
/* -------------------------------------------- */
// Set an initiative formula for the system
@ -145,19 +126,15 @@ Hooks.once("init", async function () {
};
/* -------------------------------------------- */
game.socket.on("system.foundryvtt-reve-de-dragon", sockmsg => {
console.log(">>>>> MSG RECV", sockmsg);
RdDUtility.onSocketMesssage(sockmsg);
RdDCombat.onSocketMessage(sockmsg);
ChatUtility.onSocketMessage(sockmsg);
RdDActor.onSocketMessage(sockmsg);
game.socket.on("system.foundryvtt-reve-de-dragon", data => {
RdDUtility.onSocketMesssage(data);
RdDCombat.onSocketMessage(data);
ChatUtility.onSocketMessage(data);
});
/* -------------------------------------------- */
// Define custom Entity classes
CONFIG.Actor.documentClass = RdDActor;
CONFIG.Item.documentClass = RdDItem;
CONFIG.Actor.entityClass = RdDActor;
CONFIG.RDD = {
resolutionTable: RdDResolutionTable.resolutionTable,
carac_array: RdDUtility.getCaracArray(),
@ -173,24 +150,18 @@ Hooks.once("init", async function () {
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorVehiculeSheet, { types: ["vehicule"], makeDefault: true });
Actors.registerSheet("foundryvtt-reve-de-dragon", RdDActorEntiteSheet, { types: ["entite"], makeDefault: true });
Items.unregisterSheet("core", ItemSheet);
Items.registerSheet("foundryvtt-reve-de-dragon", RdDSigneDraconiqueItemSheet, {
label: "Signe draconique",
types: ["signedraconique"],
makeDefault: true
});
Items.registerSheet("foundryvtt-reve-de-dragon", RdDItemSheet, { makeDefault: true });
CONFIG.Combat.documentClass = RdDCombatManager;
CONFIG.Combat.entityClass = RdDCombatManager;
// préparation des différents modules
ReglesOptionelles.init();
RdDUtility.init();
RdDDice.init();
RdDCommands.init();
RdDCombat.init();
RdDCombatManager.init();
RdDCombatManager.init(),
RdDTokenHud.init();
RdDActor.init();
RddCompendiumOrganiser.init();
ReglesOptionelles.init();
EffetsDraconiques.init()
TMRUtility.init();
TMRRencontres.init();
@ -202,26 +173,25 @@ function messageDeBienvenue() {
if (game.user.isGM) {
ChatUtility.removeChatMessageContaining('<div id="message-bienvenue-rdd">');
ChatMessage.create({
user: game.user.id,
user: game.user._id,
content: `<div id="message-bienvenue-rdd"><span class="rdd-roll-part">Bienvenue dans le Rêve des Dragons !</span>
<br>Vous trouverez quelques informations pour démarrer dans ce document : @Compendium[foundryvtt-reve-de-dragon.rappel-des-regles.7uGrUHGdPu0EmIu2]{Documentation MJ/Joueurs}
<br>La commande <code>/aide</code> dans le chat permet de voir les commandes spécifiques à Rêve de Dragon.</div>
` });
}
}
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
Hooks.once("ready", async function () {
/* -------------------------------------------- */
/* Foundry VTT Initialization */
/* -------------------------------------------- */
Hooks.once("ready", function () {
StatusEffects.onReady();
RdDHerbes.initializeHerbes();
RdDDice.onReady();
/* -------------------------------------------- */
/* Affiche/Init le calendrier */
let calendrier = new RdDCalendrier();
await calendrier.initCalendrier();
calendrier.initCalendrier();
let templatePath = "systems/foundryvtt-reve-de-dragon/templates/calendar-template.html";
let templateData = {};
renderTemplate(templatePath, templateData).then(html => {
@ -234,7 +204,7 @@ Hooks.once("ready", async function () {
ui.notifications.info("Attention ! Vous n'êtes connecté à aucun personnage !");
ChatMessage.create({
content: "<b>ATTENTION</b> Le joueur " + game.user.name + " n'est connecté à aucun personnage !",
user: game.user.id
user: game.user._id
});
//whisper: [ ChatMessage.getWhisperRecipients("GM") ] } );
}
@ -261,3 +231,8 @@ Hooks.on("chatMessage", (html, content, msg) => {
return true;
});
/* -------------------------------------------- */
Hooks.on("renderChatMessage", async (app, html, msg) => {
RdDUtility.onRenderChatMessage(app, html, msg);
});

View File

@ -1,17 +1,14 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
const words = [ 'pore', 'pre', 'flor', 'lane', 'turlu', 'pin', 'a', 'alph', 'i', 'onse', 'iane', 'ane', 'zach', 'arri', 'ba', 'bo', 'bi',
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la', 'al' , 'pul', 'one', 'ner', 'nur', 'mac', 'mery',
'cat', 'do', 'di', 'der', 'er', 'el', 'far', 'fer', 'go', 'guer', 'hot', 'jor', 'jar', 'ji', 'kri', 'ket', 'lor', 'hur',
'lar', 'lir', 'lu', 'pot', 'pro', 'pra', 'pit', 'qua', 'qui', 're', 'ral', 'sal', 'sen', 'ted', 'to', 'ta', 'lars', 'ver',
'vin', 'ov', 'wal', 'ry', 'ly', '' ];
'alta', 'par', 'pir', 'zor', 'zir', 'de', 'pol', 'tran', 'no', 'la','al' , 'pul', 'one', 'ner', 'nur' ];
/* -------------------------------------------- */
export class RdDNameGen {
static async getName( msg, params ) {
let name = Misc.upperFirst( await RdDDice.rollOneOf(words) + await RdDDice.rollOneOf(words) )
static getName( msg, params ) {
let name = Misc.upperFirst( Misc.rollOneOf(words) + Misc.rollOneOf(words) )
//console.log(name);
ChatMessage.create( { content: `Nom : ${name}`, whisper: ChatMessage.getWhisperRecipients("GM") } );
}

View File

@ -102,38 +102,25 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static async rollData(rollData) {
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData);
rollData.rolled = await this.roll(rollData.caracValue, rollData.finalLevel, rollData.bonus, rollData.diviseurSignificative, rollData.showDice);
return rollData;
}
/* -------------------------------------------- */
static async roll(caracValue, finalLevel, rollData = {}){
static async roll(caracValue, finalLevel, bonus = undefined, diviseur = undefined, showDice = true) {
let chances = this.computeChances(caracValue, finalLevel);
this._updateChancesWithBonus(chances, rollData.bonus);
this._updateChancesFactor(chances, rollData.diviseurSignificative);
chances.showDice = rollData.showDice;
chances.rollMode = rollData.rollMode;
this._updateChancesWithBonus(chances, bonus);
this._updateChancesFactor(chances, diviseur);
chances.showDice = showDice;
let rolled = await this.rollChances(chances, rollData.diviseurSignificative);
let rolled = await this.rollChances(chances, diviseur);
rolled.caracValue = caracValue;
rolled.finalLevel = finalLevel;
rolled.bonus = rollData.bonus;
rolled.factorHtml = Misc.getFractionHtml(rollData.diviseurSignificative);
rolled.niveauNecessaire = this.findNiveauNecessaire(caracValue, rolled.roll );
rolled.ajustementNecessaire = rolled.niveauNecessaire - finalLevel;
rolled.bonus = bonus;
rolled.factorHtml = Misc.getFractionHtml(diviseur);
return rolled;
}
/* -------------------------------------------- */
static findNiveauNecessaire(caracValue, rollValue) {
for (let cell of this.resolutionTable[caracValue]) {
if ( rollValue <= cell.norm) {
return cell.niveau;
}
}
return 16; // Dummy default
}
/* -------------------------------------------- */
static _updateChancesFactor(chances, diviseur) {
if (chances.level > -11 && diviseur && diviseur > 1) {
@ -150,13 +137,11 @@ export class RdDResolutionTable {
}
}
/* -------------------------------------------- */
static significativeRequise(chances) {
chances.roll = Math.floor(chances.score / 2);
mergeObject(chances, reussites.find(x => x.code == 'sign'), { overwrite: true });
}
/* -------------------------------------------- */
static succesRequis(chances) {
chances.roll = chances.score;
mergeObject(chances, reussites.find(x => x.code == 'norm'), { overwrite: true });
@ -164,7 +149,10 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static async rollChances(chances, diviseur) {
chances.roll = await RdDDice.rollTotal("1d100", chances);
let myRoll = new Roll("1d100").roll();
myRoll.showDice = chances.showDice;
await RdDDice.show(myRoll);
chances.roll = myRoll.total;
mergeObject(chances, this.computeReussite(chances, chances.roll, diviseur), { overwrite: true });
return chances;
}
@ -177,7 +165,8 @@ export class RdDResolutionTable {
if (difficulte < -10) {
return duplicate(levelDown.find(levelData => levelData.level == difficulte));
}
return duplicate(RdDResolutionTable.resolutionTable[caracValue][difficulte + 10]);
const chances = RdDResolutionTable.resolutionTable[caracValue][difficulte + 10];
return chances ? duplicate(chances) : RdDResolutionTable._computeCell(difficulte, RdDResolutionTable.computeChances(caracValue, difficulte));
}
/* -------------------------------------------- */
@ -236,16 +225,26 @@ export class RdDResolutionTable {
/* -------------------------------------------- */
static _computeRow(caracValue) {
let dataRow = [
this._computeCell(-10, Math.max(Math.floor(caracValue / 4), 1)),
this._computeCell(-9, Math.max(Math.floor(caracValue / 2), 1))
]
for (var diff = -8; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeCell(diff, Math.max(Math.floor(caracValue * (diff + 10) / 2), 1));
let dataRow = [];
for (var diff = -10; diff <= 22; diff++) {
dataRow[diff + 10] = this._computeCell(diff, RdDResolutionTable._computePercentage(caracValue, diff));
}
return dataRow;
}
static _computePercentage(caracValue, diff) {
if (diff <-10) {
return 1;
}
if (diff == -10){
return Math.max(Math.floor(caracValue / 4), 1);
}
if (diff == -9) {
return Math.max(Math.floor(caracValue / 2), 1)
}
return Math.max(Math.floor(caracValue * (diff + 10) / 2), 1);
}
/* -------------------------------------------- */
static _computeCell(niveau, percentage) {
return {

View File

@ -7,23 +7,17 @@ export class RdDEncaisser extends Dialog {
/* -------------------------------------------- */
constructor(html, actor) {
// Common conf
const buttonsCreatures = {
"mortel": { label: "mortel", callback: html => this.performEncaisser("mortel") },
"non-mortel": { label: "non-mortel", callback: html => this.performEncaisser("non-mortel") },
};
const buttonsEntitesCauchemar = {
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser("cauchemar") }
};
const buttons = actor.isEntiteCauchemar() ? buttonsEntitesCauchemar : buttonsCreatures;
let dialogConf = {
title: "Jet d'Encaissement",
content: html,
buttons: buttons,
buttons: {
"mortel": { label: "mortel", callback: html => this.performEncaisser(html, "mortel") },
"non-mortel": { label: "non-mortel", callback: html => this.performEncaisser(html, "non-mortel") },
"cauchemar": { label: "cauchemar", callback: html => this.performEncaisser(html, "cauchemar") }
},
default: "coupMortel"
}
let dialogOptions = {
classes: ["rdddialog"],
width: 320,
@ -38,15 +32,13 @@ export class RdDEncaisser extends Dialog {
this.encaisserSpecial = "aucun";
}
/* -------------------------------------------- */
performEncaisser(mortalite) {
performEncaisser(html, mortalite = "mortel") {
this.actor.encaisserDommages({
dmg: {
dmg:{
total: Number(this.modifier),
encaisserSpecial: this.encaisserSpecial,
loc: { result: 0, label: "" },
loc: { result: 0, label: "Corps" },
mortalite: mortalite
}
});

View File

@ -1,3 +1,4 @@
import { RdDResolutionTable } from "./rdd-resolution-table.js";
import { Misc } from "./misc.js";
/**
@ -7,53 +8,51 @@ import { Misc } from "./misc.js";
export class RdDRollDialogEthylisme extends Dialog {
/* -------------------------------------------- */
constructor(html, rollData, actor, onRoll) {
// Common conf
let dialogConf = {
title: "Test d'éthylisme",
content: html,
default: "rollButton",
buttons: { "rollButton": { label: "Test d'éthylisme", callback: html => this.onButton(html) } }
};
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 270, 'z-index': 99999 }
super(dialogConf, dialogOptions)
constructor(html, rollData, actor) {
let myButtons = {
rollButton: { label: "Test d'éthylisme", callback: html => this.actor.performEthylisme(this.rollData) }
};
// Common conf
let dialogConf = { content: html, title: "Test d'éthylisme", buttons: myButtons, default: "rollButton" };
let dialogOptions = { classes: ["rdddialog"], width: 400, height: 220, 'z-index': 99999 }
super(dialogConf, dialogOptions)
//console.log("ETH", rollData);
this.onRoll = onRoll;
this.rollData = rollData;
this.actor = actor;
}
async onButton(html) {
this.onRoll(this.rollData);
}
/* -------------------------------------------- */
activateListeners(html) {
super.activateListeners(html);
this.bringToTop(); // Ensure top level
// Get the rollData stuff
var rollData = this.rollData;
var dialog = this;
function updateRollResult(rollData) {
rollData.finalLevel = Number(rollData.etat) + Number(rollData.forceAlcool) + rollData.diffNbDoses;
// Mise à jour valeurs
$("#roll-param").text(rollData.vieValue + " / " + Misc.toSignedString(rollData.finalLevel));
$(".table-resolution").remove();
$("#resolutionTable").append(RdDResolutionTable.buildHTMLTableExtract(rollData.vieValue, rollData.finalLevel));
}
// Setup everything onload
$(function () {
$("#forceAlcool").val(Misc.toInt(rollData.forceAlcool));
dialog.updateRollResult();
updateRollResult(rollData);
});
// Update !
html.find('#forceAlcool').change((event) => {
rollData.forceAlcool = Misc.toInt(event.currentTarget.value); // Update the selected bonus/malus
dialog.updateRollResult();
updateRollResult(rollData);
});
}
async updateRollResult() {
// Mise à jour valeurs
$("#roll-param").text(this.rollData.vie + " / " + Misc.toSignedString(Number(this.rollData.etat) + Number(this.rollData.forceAlcool) + this.rollData.diffNbDoses));
$(".table-resolution").remove();
}
}

View File

@ -29,7 +29,6 @@ export class RdDRollResolutionTable extends Dialog {
finalLevel: 0,
diffConditions: 0,
diffLibre: 0,
use: { conditions:true, libre:true }
}
mergeObject(rollData, defRollData, { overwrite: false });
for (let i = 1; i < 21; i++) {
@ -106,8 +105,6 @@ export class RdDRollResolutionTable extends Dialog {
this.updateRollResult();
});
}
/* -------------------------------------------- */
async updateRollResult() {
let rollData = this.rollData;
rollData.caracValue = parseInt(rollData.selectedCarac.value)
@ -130,7 +127,6 @@ export class RdDRollResolutionTable extends Dialog {
return diffLibre + diffConditions;
}
/* -------------------------------------------- */
_computeDiffLibre(rollData) {
return Misc.toInt(rollData.diffLibre);
}

View File

@ -1,6 +1,7 @@
import { RollDataAjustements } from "./rolldata-ajustements.js";
import { HtmlUtility } from "./html-utility.js";
import { RdDItemCompetence } from "./item-competence.js";
import { RdDItemMeditation } from "./item-meditation.js";
import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
@ -63,7 +64,7 @@ export class RdDRoll extends Dialog {
surprise: actor.getSurprise(false),
canClose: true
};
mergeObject(rollData, defaultRollData, { recursive: true, overwrite: false });
if (rollData.forceCarac) {
rollData.carac = rollData.forceCarac;
@ -159,17 +160,14 @@ export class RdDRoll extends Dialog {
function onLoad() {
let rollData = dialog.rollData;
console.log(rollData);
// Update html, according to data
if (rollData.competence) {
const defaut_carac = Misc.templateData(rollData.competence).defaut_carac;
// Set the default carac from the competence item
rollData.selectedCarac = rollData.carac[defaut_carac];
$("#carac").val(defaut_carac);
rollData.selectedCarac = rollData.carac[rollData.competence.data.defaut_carac];
$("#carac").val(rollData.competence.data.defaut_carac);
}
if (rollData.selectedSort) {
dialog.setSelectedSort(rollData.selectedSort);
$(".draconic").val(rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer
$("#draconic").val(rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer
}
RdDItemSort.setCoutReveReel(rollData.selectedSort);
$("#diffLibre").val(Misc.toInt(rollData.diffLibre));
@ -194,20 +192,17 @@ export class RdDRoll extends Dialog {
this.rollData.selectedCarac = this.rollData.carac[caracKey]; // Update the selectedCarac
this.updateRollResult();
});
html.find('.roll-draconic').change((event) => {
html.find('#draconic').change((event) => {
let draconicKey = Misc.toInt(event.currentTarget.value);
this.rollData.competence = this.rollData.draconicList[draconicKey]; // Update the selectedCarac
this.updateRollResult();
});
html.find('.roll-sort').change((event) => {
html.find('#sort').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSort(this.rollData.sortList[sortKey]);
this.updateRollResult();
$("#diffLibre").val(this.rollData.diffLibre);
});
html.find('.roll-signedraconique').change((event) => {
let sortKey = Misc.toInt(event.currentTarget.value);
this.setSelectedSigneDraconique(this.rollData.signes[sortKey]);
this.rollData.selectedSort = this.rollData.sortList[sortKey]; // Update the selectedCarac
this.rollData.bonus = RdDItemSort.getCaseBonus(this.rollData.selectedSort, this.rollData.tmr.coord);
RdDItemSort.setCoutReveReel(this.rollData.selectedSort);
$("#draconic").val(this.rollData.selectedSort.data.listIndex); // Uniquement a la selection du sort, pour permettre de changer
this.updateRollResult();
});
html.find('#ptreve-variable').change((event) => {
@ -220,35 +215,31 @@ export class RdDRoll extends Dialog {
this.rollData.dmg.mortalite = event.currentTarget.checked ? "non-mortel" : "mortel";
this.updateRollResult();
});
html.find('.cuisine-proportions').change((event) => {
this.rollData.proportions = Number(event.currentTarget.value);
html.find('#tactique-combat').change((event) => {
this.rollData.tactique = event.currentTarget.value;
this.updateRollResult();
});
html.find('.select-by-name').change((event) => {
const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.value;
html.find('#useMalusSurenc').change((event) => {
this.rollData.useMalusSurenc = event.currentTarget.checked;
this.updateRollResult();
});
html.find('.checkbox-by-name').change((event) => {
const attribute = event.currentTarget.attributes['name'].value;
this.rollData[attribute] = event.currentTarget.checked;
html.find('#useMalusEncTotal').change((event) => {
this.rollData.useMalusEncTotal = event.currentTarget.checked;
this.updateRollResult();
});
html.find('.appel-moral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
html.find('.imgAppelAuMoral').click((event) => { /* l'appel au moral, qui donne un bonus de +1 */
this.rollData.useMoral = !this.rollData.useMoral;
const appelMoral = html.find('.icon-appel-moral')[0];
const tooltip = html.find('.tooltipAppelAuMoralText')[0];
if (this.rollData.useMoral) {
if (this.rollData.moral > 0) {
tooltip.innerHTML = "Appel au moral";
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg";
html.find('.imgAppelAuMoral')[0].src = "/systems/foundryvtt-reve-de-dragon/icons/moral-heureux.svg";
html.find('.tooltipAppelAuMoralText')[0].innerHTML = "Appel au moral";
} else {
tooltip.innerHTML = "Appel à l'énergie du désespoir";
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-malheureux.svg";
html.find('.imgAppelAuMoral')[0].src = "/systems/foundryvtt-reve-de-dragon/icons/moral-malheureux.svg";
html.find('.tooltipAppelAuMoralText')[0].innerHTML = "Appel à l'énergie du désespoir";
}
} else {
tooltip.innerHTML = "Sans appel au moral";
appelMoral.src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg";
html.find('.imgAppelAuMoral')[0].src = "/systems/foundryvtt-reve-de-dragon/icons/moral-neutre.svg";
html.find('.tooltipAppelAuMoralText')[0].innerHTML = "Sans appel au moral";
}
this.updateRollResult();
});
@ -260,35 +251,6 @@ export class RdDRoll extends Dialog {
});
}
async setSelectedSort(sort) {
this.rollData.selectedSort = sort; // Update the selectedCarac
this.rollData.competence = RdDItemCompetence.getVoieDraconic(this.rollData.draconicList, sort.data.draconic);
this.rollData.bonus = RdDItemSort.getCaseBonus(sort, this.rollData.tmr.coord);
this.rollData.diffLibre = RdDItemSort.getDifficulte(sort, -7);
RdDItemSort.setCoutReveReel(sort);
const htmlSortDescription = await renderTemplate("systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html", { sort: sort });
$(".sort-ou-rituel").text(sort.data.isrituel ? "rituel" : "sort");
$(".bonus-case").text(`${this.rollData.bonus}%`);
$(".details-sort").remove();
$(".description-sort").append(htmlSortDescription);
$(".roll-draconic").val(sort.data.listIndex);
$(".div-sort-difficulte-fixe").text(Misc.toSignedString(sort.data.difficulte));
$(".div-sort-ptreve-fixe").text(sort.data.ptreve);
const diffVariable = RdDItemSort.isDifficulteVariable(sort);
const coutVariable = RdDItemSort.isCoutVariable(sort);
HtmlUtility._showControlWhen($(".div-sort-non-rituel"), !sort.data.isrituel);
HtmlUtility._showControlWhen($(".div-sort-difficulte-var"), diffVariable);
HtmlUtility._showControlWhen($(".div-sort-difficulte-fixe"), !diffVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-var"), coutVariable);
HtmlUtility._showControlWhen($(".div-sort-ptreve-fixe"), !coutVariable);
}
async setSelectedSigneDraconique(signe){
this.rollData.signe = signe;
this.rollData.diffLibre = Misc.data(signe).data.difficulte,
$(".signe-difficulte").text(Misc.toSignedString(this.rollData.diffLibre));
}
/* -------------------------------------------- */
async updateRollResult() {
let rollData = this.rollData;
@ -300,7 +262,12 @@ export class RdDRoll extends Dialog {
let dmgText = Misc.toSignedString(rollData.dmg.total);
if (rollData.coupsNonMortels) {
dmgText = `(${dmgText}) non-mortel`
dmgText = '(' + dmgText + ')';
}
if (rollData.selectedSort) {
rollData.bonus = RdDItemSort.getCaseBonus(rollData.selectedSort, rollData.tmr.coord);
HtmlUtility._showControlWhen($("#div-sort-difficulte"), RdDItemSort.isDifficulteVariable(rollData.selectedSort))
HtmlUtility._showControlWhen($("#div-sort-ptreve"), RdDItemSort.isCoutVariable(rollData.selectedSort))
}
RollDataAjustements.calcul(rollData, this.actor);
@ -308,13 +275,13 @@ export class RdDRoll extends Dialog {
HtmlUtility._showControlWhen($(".diffMoral"), rollData.ajustements.moralTotal.used);
HtmlUtility._showControlWhen($(".divAppelAuMoral"), rollData.use.appelAuMoral);
HtmlUtility._showControlWhen($("#etat-general"), !RdDCarac.isIgnoreEtatGeneral(rollData));
HtmlUtility._showControlWhen($("#etat-general"), !RdDCarac.isIgnoreEtatGeneral(rollData.selectedCarac, rollData.competence));
HtmlUtility._showControlWhen($("#ajust-astrologique"), RdDResolutionTable.isAjustementAstrologique(rollData));
// Mise à jour valeurs
$(".dialog-roll-title").text(this._getTitle(rollData));
$("#compdialogTitle").text(this._getTitle(rollData));
$('#coupsNonMortels').prop('checked', rollData.coupsNonMortels);
$(".dmg-arme-actor").text(dmgText);
$("#dmg-arme-actor").text(dmgText);
$('.table-ajustement').remove();
$(".table-resolution").remove();
$(".table-proba-reussite").remove();
@ -326,7 +293,7 @@ export class RdDRoll extends Dialog {
/* -------------------------------------------- */
async buildAjustements(rollData) {
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html`, rollData);
const html = await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html`, rollData);
return html;
}
@ -380,9 +347,9 @@ export class RdDRoll extends Dialog {
const niveau = Misc.toSignedString(rollData.competence.data.niveau);
if (compName == carac) {
// cas des créatures
return carac + " Niveau " + niveau
return carac + " " + niveau
}
const armeTitle = (rollData.arme) ? " (" + rollData.arme.name + ") " : "";
return carac + "/" + compName + armeTitle + " Niveau " + niveau
return carac + "/" + compName + armeTitle + " " + niveau
}
}

View File

@ -5,23 +5,33 @@ export class RdDRollTables {
const pack = game.packs.get("foundryvtt-reve-de-dragon.tables-diverses");
const index = await pack.getIndex();
const entry = index.find(e => e.name === tableName);
const table = await pack.getDocument(entry._id);
const table = await pack.getEntity(entry._id);
const draw = await table.draw({ displayChat: toChat, rollMode: "gmroll"});
console.log("RdDRollTables", tableName, toChat, ":", draw);
return draw.results.length > 0 ? draw.results[0] : undefined;
return draw;
}
/* -------------------------------------------- */
static async drawItemFromRollTable(tableName, toChat = false) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
const pack = game.packs.get(drawResult.data.collection);
return await pack.getDocument(drawResult.data.resultId);
static async drawItemFromRollTable(tableName, toChat) {
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined;
if (drawnItemRef.collection) {
const pack = game.packs.get(drawnItemRef.collection);
return await pack.getEntity(drawnItemRef.resultId);
}
ui.notifications.warn("le tirage ne correspond pas à une entrée d'un Compendium")
return drawnItemRef.text;
}
/* -------------------------------------------- */
static async drawTextFromRollTable(tableName, toChat) {
const drawResult = await RdDRollTables.genericGetTableResult(tableName, toChat);
return drawResult.data.text;
const draw = await RdDRollTables.genericGetTableResult(tableName, toChat);
const drawnItemRef = draw.results.length > 0 ? draw.results[0] : undefined;
if (drawnItemRef.collection) {
ui.notifications.warn("le tirage correspond à une entrée d'un Compendium, on attendait un texte")
return await pack.getEntity(drawnItemRef.resultId);
}
return drawnItemRef.text;
}
/* -------------------------------------------- */

View File

@ -10,10 +10,8 @@ import { Poetique } from "./poetique.js";
import { EffetsDraconiques } from "./tmr/effets-draconiques.js";
import { PixiTMR } from "./tmr/pixi-tmr.js";
import { Draconique } from "./tmr/draconique.js";
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { HtmlUtility } from "./html-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
export class RdDTMRDialog extends Dialog {
@ -42,7 +40,7 @@ export class RdDTMRDialog extends Dialog {
const dialogOptions = {
classes: ["tmrdialog"],
width: 920, height: 980,
'z-index': 40
'z-index': 20
}
super(dialogConf, dialogOptions);
@ -50,7 +48,7 @@ export class RdDTMRDialog extends Dialog {
this.actor = actor;
this.actor.tmrApp = this; // reference this app in the actor structure
this.viewOnly = tmrData.mode == "visu"
this.fatigueParCase = this.viewOnly || !ReglesOptionelles.isUsing("appliquer-fatigue") ? 0 : this.actor.getTMRFatigue();
this.fatigueParCase = this.viewOnly ? 0 : this.actor.getTMRFatigue();
this.cumulFatigue = 0;
this.loadRencontres();
this.loadSortsReserve();
@ -60,28 +58,24 @@ export class RdDTMRDialog extends Dialog {
this.pixiApp = new PIXI.Application({ width: 720, height: 860 });
this.pixiTMR = new PixiTMR(this, this.pixiApp);
this.cacheTMR = (game.user.isGM) ? false : actor.isTMRCache();
this.callbacksOnAnimate = [];
if (!this.viewOnly) {
this.actor.setStatusDemiReve(true);
this._tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
}
// load the texture we need
this.pixiTMR.load((loader, resources) => this.createPixiSprites());
}
/* -------------------------------------------- */
loadCasesSpeciales() {
this.casesSpeciales = this.actor.data.items.filter(item => Draconique.isCaseTMR(item));
}
/* -------------------------------------------- */
loadSortsReserve() {
this.sortsReserves = Misc.data(this.actor).data.reve.reserve.list;
}
/* -------------------------------------------- */
loadRencontres() {
this.rencontresExistantes = this.actor.getTMRRencontres();
}
@ -89,7 +83,9 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
createPixiSprites() {
EffetsDraconiques.carteTmr.createSprite(this.pixiTMR);
this.updateTokens();
this.demiReve = this._tokenDemiReve();
this._updateDemiReve();
}
@ -105,7 +101,6 @@ export class RdDTMRDialog extends Dialog {
}
}
/* -------------------------------------------- */
updateTokens() {
this._removeTokens(t => true);
this.loadRencontres();
@ -114,7 +109,6 @@ export class RdDTMRDialog extends Dialog {
this._createTokens();
}
/* -------------------------------------------- */
removeToken(tmr, casetmr) {
this._removeTokens(t => t.coordTMR() == tmr.coord && t.caseSpeciale?._id == casetmr._id);
this.updateTokens()
@ -136,50 +130,18 @@ export class RdDTMRDialog extends Dialog {
return EffetsDraconiques.rencontre.token(this.pixiTMR, rencontre, () => rencontre.coord);
}
_tokenCaseSpeciale(casetmr) {
const caseData = Misc.data(casetmr);
const draconique = Draconique.get(caseData.data.specific);
return draconique?.token(this.pixiTMR, caseData, () => caseData.data.coord);
const draconique = Draconique.get(casetmr.data.specific);
return draconique?.token(this.pixiTMR, casetmr, () => casetmr.data.coord);
}
_tokenSortEnReserve(sortEnReserve) {
return EffetsDraconiques.sortReserve.token(this.pixiTMR, sortEnReserve.sort, () => sortEnReserve.coord);
}
_tokenDemiReve() {
const actorData = Misc.data(this.actor);
return EffetsDraconiques.demiReve.token(this.pixiTMR, actorData, () => actorData.data.reve.tmrpos.coord);
return EffetsDraconiques.demiReve.token(this.pixiTMR, this.actor, () => Misc.data(this.actor).data.reve.tmrpos.coord);
}
_updateDemiReve() {
this.notifierResonanceSigneDraconique(this._getActorCoord());
if (!this.cacheTMR) {
this._setTokenPosition(this.demiReve);
}
}
_getActorCoord() {
return Misc.data(this.actor).data.reve.tmrpos.coord;
}
/* -------------------------------------------- */
async moveFromKey(move) {
let pos = TMRUtility.convertToCellPos(this._getActorCoord());
if (move == 'top') pos.y -= 1;
if (move == 'bottom') pos.y += 1;
if (move.includes('left')) pos.x -= 1;
if (move.includes('right')) pos.x += 1;
if (pos.x % 2 == 1) {
if (move == 'top-left') pos.y -= 1;
if (move == 'top-right') pos.y -= 1;
} else {
if (move == 'bottom-left') pos.y += 1;
if (move == 'bottom-right') pos.y += 1;
}
let targetCoord = TMRUtility.convertToTMRCoord(pos);
await this._deplacerDemiReve(targetCoord, 'normal');
this.checkQuitterTMR();
this._setTokenPosition(this.demiReve);
}
/* -------------------------------------------- */
@ -189,72 +151,41 @@ export class RdDTMRDialog extends Dialog {
document.getElementById("tmrrow1").insertCell(0).append(this.pixiApp.view);
if (this.viewOnly) {
html.find('.lancer-sort').remove();
html.find('.lire-signe-draconique').remove();
html.find('#lancer-sort').remove();
}
else {
// Roll Sort
html.find('#lancer-sort').click((event) => {
this.actor.rollUnSort(Misc.data(this.actor).data.reve.tmrpos.coord);
});
}
if (this.viewOnly) {
return;
}
HtmlUtility._showControlWhen($(".appliquerFatigue"), ReglesOptionelles.isUsing("appliquer-fatigue"));
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getActorCoord()));
// Roll Sort
html.find('.lancer-sort').click((event) => {
this.actor.rollUnSort(this._getActorCoord());
});
html.find('.lire-signe-draconique').click((event) => {
this.actor.rollLireSigneDraconique(this._getActorCoord());
});
html.find('#dir-top').click((event) => {
this.moveFromKey("top");
});
html.find('#dir-top-left').click((event) => {
this.moveFromKey("top-left");
});
html.find('#dir-top-right').click((event) => {
this.moveFromKey("top-right");
});
html.find('#dir-bottom-left').click((event) => {
this.moveFromKey("bottom-left");
});
html.find('#dir-bottom-right').click((event) => {
this.moveFromKey("bottom-right");
});
html.find('#dir-bottom').click((event) => {
this.moveFromKey("bottom");
});
// Gestion du cout de montée en points de rêve
let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1) - this.actor.countMonteeLaborieuse();
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
let reveCout = ((this.tmrdata.isRapide && !EffetsDraconiques.isDeplacementAccelere(this.actor)) ? -2 : -1)
- this.actor.countMonteeLaborieuse();
this.cumulFatigue += this.fatigueParCase;
await this.actor.reveActuelIncDec(reveCout);
// Le reste...
this.updateValuesDisplay();
let tmr = TMRUtility.getTMR(this._getActorCoord());
let tmr = TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord);
await this.manageRencontre(tmr, () => {
this.postRencontre(tmr);
});
}
/* -------------------------------------------- */
async updateValuesDisplay() {
const coord = this._getActorCoord();
const actorData = Misc.data(this.actor);
HtmlUtility._showControlWhen($(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(coord));
updateValuesDisplay() {
let ptsreve = document.getElementById("tmr-pointsreve-value");
const actorData = Misc.data(this.actor);
ptsreve.innerHTML = actorData.data.reve.reve.value;
let tmrpos = document.getElementById("tmr-pos");
if (this.cacheTMR) {
tmrpos.innerHTML = '?? (' + TMRUtility.getTMRType(coord) + ')';
} else {
tmrpos.innerHTML = coord + " (" + TMRUtility.getTMRLabel(coord) + ")";
}
let tmr = TMRUtility.getTMR(actorData.data.reve.tmrpos.coord);
tmrpos.innerHTML = actorData.data.reve.tmrpos.coord + " (" + tmr.label + ")";
let etat = document.getElementById("tmr-etatgeneral-value");
etat.innerHTML = this.actor.getEtatGeneral();
@ -262,22 +193,18 @@ export class RdDTMRDialog extends Dialog {
let refoulement = document.getElementById("tmr-refoulement-value");
refoulement.innerHTML = actorData.data.reve.refoulement.value;
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
let fatigueItem = document.getElementById("tmr-fatigue-table");
//console.log("Refresh : ", actorData.data.sante.fatigue.value);
fatigueItem.innerHTML = "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(actorData.data.sante.fatigue.value, actorData.data.sante.endurance.max).html() + "</table>";
}
let fatigueItem = document.getElementById("tmr-fatigue-table");
//console.log("Refresh : ", actorData.data.sante.fatigue.value);
fatigueItem.innerHTML = "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(actorData.data.sante.fatigue.value, actorData.data.sante.endurance.max).html() + "</table>";
}
/* -------------------------------------------- */
close() {
if ( this.actor.tmrApp ) {
this.actor.tmrApp = undefined; // Cleanup reference
if ( !this.viewOnly ) {
this.actor.setStatusDemiReve(false);
this._tellToGM(this.actor.name + " a quitté les terres médianes");
}
this.actor.santeIncDec("fatigue", this.cumulFatigue).then(super.close()); // moving 1 cell costs 1 fatigue
this.actor.santeIncDec("fatigue", this.cumulFatigue).then(super.close()); // moving 1 cell costs 1 fatigue
this.actor.tmrApp = undefined; // Cleanup reference
if (!this.viewOnly) {
this.actor.setStatusDemiReve(false);
this._tellToGM(this.actor.name + " a quitté les terres médianes");
}
}
@ -288,7 +215,6 @@ export class RdDTMRDialog extends Dialog {
this._tellToGM(this.actor.name + " s'est dérobé et quitte les TMR.");
this.close();
}
/* -------------------------------------------- */
async refouler() {
this._tellToGM(this.actor.name + " a refoulé : " + this.currentRencontre.name);
@ -332,14 +258,12 @@ export class RdDTMRDialog extends Dialog {
this.rencontreState = state;
}
/* -------------------------------------------- */
async choisirCasePortee(coord, portee) {
// Récupère la liste des cases à portées
let locList = TMRUtility.getTMRPortee(coord, portee);
this.colorierZoneRencontre(locList);
}
/* -------------------------------------------- */
async choisirCaseType(type) {
const locList = TMRUtility.filterTMR(it => it.type == type).map(it => it.coord);
this.colorierZoneRencontre(locList);
@ -354,7 +278,7 @@ export class RdDTMRDialog extends Dialog {
return true;
}
const resteAvantInconscience = this.actor.getFatigueMax() - this.actor.getFatigueActuelle() - this.cumulFatigue;
if (ReglesOptionelles.isUsing("appliquer-fatigue") && resteAvantInconscience <= 0) {
if (resteAvantInconscience <= 0) {
this._tellToGM("Vous vous écroulez de fatigue : vous quittez les Terres médianes !");
this.quitterLesTMRInconscient();
return true;
@ -388,36 +312,35 @@ export class RdDTMRDialog extends Dialog {
rencontre: this.currentRencontre,
nbRounds: 1,
canClose: false,
selectedCarac: {label: "reve-actuel"},
tmr: TMRUtility.getTMR(this._getActorCoord())
tmr: TMRUtility.getTMR(Misc.data(this.actor).data.reve.tmrpos.coord)
}
await this._tentativeMaitrise(rencontreData);
}
/* -------------------------------------------- */
async _tentativeMaitrise(rencData) {
console.log("-> matriser", rencData);
async _tentativeMaitrise(rencontreData, presentCite) {
console.log("-> matriser", rencontreData);
rencData.reve = this.actor.getReveActuel();
rencData.etat = this.actor.getEtatGeneral();
rencontreData.reve = this.actor.getReveActuel();
rencontreData.etat = this.actor.getEtatGeneral();
RollDataAjustements.calcul(rencData, this.actor);
RollDataAjustements.calcul(rencontreData, this.actor);
rencData.rolled = rencData.presentCite
? this._rollPresentCite(rencData)
: await RdDResolutionTable.roll(rencData.reve, RollDataAjustements.sum(rencData.ajustements));
rencontreData.rolled = rencontreData.presentCite
? this._rollPresentCite(rencontreData)
: await RdDResolutionTable.roll(rencontreData.reve, RollDataAjustements.sum(rencontreData.ajustements));
let postProcess = await TMRRencontres.gererRencontre(this, rencData);
let postProcess = await TMRRencontres.gererRencontre(this, rencontreData);
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencData)
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-rencontre-tmr.html`, rencontreData)
});
if (postProcess) {
/** Gère les rencontres avec du post-processing (passeur, messagers, tourbillons, ...) */
await postProcess(this, rencData);
await postProcess(this, rencontreData);
}
else {
this.currentRencontre = undefined;
@ -427,14 +350,12 @@ export class RdDTMRDialog extends Dialog {
if (this.checkQuitterTMR()) {
return;
}
else if (rencData.rolled.isEchec && rencData.rencontre.isPersistant) {
else if (rencontreData.rolled.isEchec && rencontreData.rencontre.isPersistant) {
setTimeout(() => {
rencData.nbRounds++;
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
this._tentativeMaitrise(rencData);
this._deleteTmrMessages(rencData.actor, rencData.nbRounds);
rencontreData.nbRounds++;
this.cumulFatigue += this.fatigueParCase;
this._tentativeMaitrise(rencontreData);
this._deleteTmrMessages(rencontreData.actor, rencontreData.nbRounds);
}, 2000);
}
}
@ -463,17 +384,17 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
_tellToUser(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id] });
}
/* -------------------------------------------- */
_tellToGM(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: ChatMessage.getWhisperRecipients("GM") });
ChatMessage.create({ content: message, user: game.user._id, whisper: ChatMessage.getWhisperRecipients("GM") });
}
/* -------------------------------------------- */
_tellToUserAndGM(message) {
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id].concat(ChatMessage.getWhisperRecipients("GM")) });
ChatMessage.create({ content: message, user: game.user._id, whisper: [game.user._id].concat(ChatMessage.getWhisperRecipients("GM")) });
}
/* -------------------------------------------- */
@ -539,15 +460,11 @@ export class RdDTMRDialog extends Dialog {
if (rencontre) {
return rencontre;
}
let locTMR = (this.cacheTMR) ? Misc.upperFirst(tmr.type) + " ??" : tmr.label + " (" + tmr.coord + ")";
let myRoll = await RdDDice.rollTotal("1d7");
let myRoll = new Roll("1d7").evaluate().total;
if (TMRUtility.isForceRencontre() || myRoll == 7) {
this._tellToUser(myRoll + ": Rencontre en " + locTMR);
return await this.rencontreTMRRoll(tmr, this.actor.isRencontreSpeciale());
} else {
this._tellToUser(myRoll + ": Pas de rencontre en " + locTMR);
}
this._tellToUser(myRoll + ": Pas de rencontre en " + tmr.label + " (" + tmr.coord + ")");
}
/* -------------------------------------------- */
@ -603,7 +520,7 @@ export class RdDTMRDialog extends Dialog {
await this._rollMaitriseCaseHumide(rollData);
return;
}
rollData.poesie = await Poetique.getExtrait();
rollData.poesie = Poetique.getExtrait();
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -613,7 +530,6 @@ export class RdDTMRDialog extends Dialog {
}
}
/* -------------------------------------------- */
async souffleSiEchecTotal(rollData) {
if (rollData.rolled.isETotal) {
rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
@ -714,14 +630,13 @@ export class RdDTMRDialog extends Dialog {
await this._maitriserTMR(rollData, r => this._onResultatConquerir(r, options));
}
/* -------------------------------------------- */
async _onResultatConquerir(rollData, options) {
if (rollData.rolled.isETotal) {
rollData.souffle = await this.actor.ajouterSouffle({ chat: false });
}
this.toclose = rollData.rolled.isEchec;
rollData.poesie = await Poetique.getExtrait();
rollData.poesie = Poetique.getExtrait();
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-resultat-maitrise-tmr.html`, rollData)
@ -741,7 +656,7 @@ export class RdDTMRDialog extends Dialog {
const dialog = await RdDRoll.create(this.actor, rollData,
{
html: 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-maitrise-tmr.html',
options: { height: 420 },
options: { height: 350 },
close: html => { this.maximize(); } // Re-display TMR
},
{
@ -755,7 +670,6 @@ export class RdDTMRDialog extends Dialog {
dialog.render(true);
}
/* -------------------------------------------- */
async validerVisite(tmr) {
await EffetsDraconiques.pelerinage.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
await EffetsDraconiques.urgenceDraconique.onVisiteSupprimer(this.actor, tmr, (casetmr) => this.removeToken(tmr, casetmr));
@ -870,9 +784,8 @@ export class RdDTMRDialog extends Dialog {
await tmrObject._onClickTMRPos(eventPos); // Vérifier l'état des compteurs reve/fatigue/vie
}
/* -------------------------------------------- */
async _onClickTMRPos(eventPos) {
let currentPos = TMRUtility.convertToCellPos(this._getActorCoord());
let currentPos = TMRUtility.convertToCellPos(Misc.data(this.actor).data.reve.tmrpos.coord);
console.log("deplacerDemiReve >>>>", currentPos, eventPos);
@ -916,37 +829,24 @@ export class RdDTMRDialog extends Dialog {
Si la case est le demi-rêve, ne pas lancer de sort.
Si un lancement de sort est en cours, trouver un moyen de réafficher cette fenêtre si on essaie de lancer un sort (ou bloquer le lancer de sort)
*/
this.notifierResonanceSigneDraconique(targetCoord);
await this.actor.rollUnSort(targetCoord);
this.nettoyerRencontre();
}
/* -------------------------------------------- */
externalRefresh(tmrData) {
this.cacheTMR = (game.user.isGM) ? false : this.actor.isTMRCache();
this.createPixiSprites();
this.forceDemiRevePositionView();
this.updateValuesDisplay();
this.updateTokens();
console.log("TMR REFRESHED !!!");
}
/* -------------------------------------------- */
async _deplacerDemiReve(targetCoord, deplacementType) {
if (this.currentRencontre != 'normal') {
this.nettoyerRencontre();
}
let tmr = TMRUtility.getTMR(targetCoord);
//console.log("deplacerDemiReve", tmr, this);
console.log("deplacerDemiReve", tmr, this);
// Gestion cases spéciales type Trou noir, etc
tmr = await this.manageTmrInnaccessible(tmr);
this.actor.updateCoordTMR(tmr.coord);
await this.actor.updateCoordTMR(tmr.coord);
this._updateDemiReve();
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
this.cumulFatigue += this.fatigueParCase;
}
this.cumulFatigue += this.fatigueParCase;
this.updateValuesDisplay();
game.socket.emit("system.foundryvtt-reve-de-dragon", {
msg: "msg_tmr_move", data: {
@ -963,16 +863,6 @@ export class RdDTMRDialog extends Dialog {
}
}
async notifierResonanceSigneDraconique(coord) {
if (this.actor.isResonanceSigneDraconique(coord)) {
ChatMessage.create({
whisper: ChatUtility.getWhisperRecipientsAndGMs(game.user.name),
content: await renderTemplate(`systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-resonance.html`, { alias: this.actor.name, typeTMR: TMRUtility.getTMRType(coord) })
});
}
}
/* -------------------------------------------- */
async postRencontre(tmr) {
if (!(this.viewOnly || this.currentRencontre)) {
await this.manageCaseHumide(tmr);
@ -1027,9 +917,7 @@ export class RdDTMRDialog extends Dialog {
/* -------------------------------------------- */
_setTokenPosition(token) {
if (!this.cacheTMR) {
this.pixiTMR.setPosition(token.sprite, TMRUtility.convertToCellPos(token.coordTMR()));
}
this.pixiTMR.setPosition(token.sprite, TMRUtility.convertToCellPos(token.coordTMR()));
}
/* -------------------------------------------- */

View File

@ -20,7 +20,7 @@ export class RdDTMRRencontreDialog extends Dialog {
const dialogOptions = {
classes: ["tmrrencdialog"],
width: 320, height: 240,
'z-index': 50
'z-index': 20
}
super(dialogConf, dialogOptions);

View File

@ -1,56 +1,54 @@
/* -------------------------------------------- */
import { HtmlUtility } from "./html-utility.js";
import { Misc } from "./misc.js";
import { RdDCombatManager } from "./rdd-combat.js";
import { RdDUtility } from "./rdd-utility.js";
/* -------------------------------------------- */
export class RdDTokenHud {
static init() {
// Integration du TokenHUD
static init(){
// Integration du TokenHUD
Hooks.on('renderTokenHUD', (app, html, data) => { RdDTokenHud.addTokenHudExtensions(app, html, data._id) });
}
/* -------------------------------------------- */
static async removeExtensionHud(app, html, tokenId) {
html.find('.control-icon.rdd-combat').remove();
html.find('.control-icon.rdd-initiative').remove();
static async removeExtensionHud( app, html, tokenId) {
let combat = html.find('.control-icon.rdd-combat');
combat.remove();
let initiative = html.find('.control-icon.rdd-initiative');
initiative.remove();
}
/* -------------------------------------------- */
static async addExtensionHud(app, html, tokenId) {
static async addExtensionHud( app, html, tokenId ) {
let token = canvas.tokens.get(tokenId);
let actor = token.actor;
let combatant = game.combat.combatants.find(c => Misc.data(c).tokenId == tokenId);
let combatant = game.combat.data.combatants.find(c => c.tokenId == token.data._id);
app.hasExtension = true;
let armesList = RdDCombatManager.buildListeActionsCombat(combatant);
const hudData = {
combatant: combatant, armes: armesList,
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01 }, { name: 'Initiative -1', command: 'dec', value: -0.01 }]
};
let armesList = RdDCombatManager.buildListeActionsCombat(combatant) ;
const hudData = { combatant: combatant, armes: armesList,
commandes: [{ name: 'Initiative +1', command: 'inc', value: 0.01}, { name: 'Initiative -1',command: 'dec', value: -0.01}] };
const controlIconCombat = html.find('.control-icon[data-action=combat]');
// initiative
await RdDTokenHud._configureSubMenu(controlIconCombat, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData,
await RdDTokenHud._configureSubMenu(html.find('.control-icon.combat'), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html', hudData,
(event) => {
let initCommand = event.currentTarget.attributes['data-command'].value;
let combatantId = event.currentTarget.attributes['data-combatant-id'].value;
if (!initCommand) {
if ( !initCommand ) {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex];
RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
RdDCombatManager.rollInitiativeCompetence(combatantId, arme);
} else if (initCommand == 'inc') {
RdDCombatManager.incDecInit(combatantId, 0.01);
} else if (initCommand == 'dec') {
RdDCombatManager.incDecInit(combatantId, -0.01);
RdDCombatManager.incDecInit( combatantId, 0.01 );
} else if ( initCommand == 'dec') {
RdDCombatManager.incDecInit( combatantId, -0.01 );
}
});
const controlIconTarget = html.find('.control-icon[data-action=target]');
// combat
await RdDTokenHud._configureSubMenu(controlIconTarget, 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
await RdDTokenHud._configureSubMenu(html.find('.control-icon.target'), 'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html', hudData,
(event) => {
let armeIndex = event.currentTarget.attributes['data-arme-id'].value;
let arme = armesList[armeIndex];
@ -60,35 +58,38 @@ export class RdDTokenHud {
/* -------------------------------------------- */
static async addTokenHudExtensions(app, html, tokenId) {
const controlIconCombat = html.find('.control-icon[data-action=combat]');
controlIconCombat.click(event => {
if (event.currentTarget.className.includes('active')) {
RdDTokenHud.removeExtensionHud(app, html, tokenId);
} else {
setTimeout(function () { RdDTokenHud.addExtensionHud(app, html, tokenId) }, 200);
}
});
if (controlIconCombat.length>0 && controlIconCombat[0].className.includes('active')) {
RdDTokenHud.addExtensionHud(app, html, tokenId);
html.find('.control-icon.combat').click(event => {
if ( event.currentTarget.className.includes('active')) {
RdDTokenHud.removeExtensionHud( app, html, tokenId);
} else {
setTimeout( function() { RdDTokenHud.addExtensionHud( app, html, tokenId) } , 200 );
}
} );
let combatIcon = html.find('.control-icon.combat');
if ( combatIcon[0].className.includes('active') ) {
RdDTokenHud.addExtensionHud( app, html, tokenId);
}
}
/* -------------------------------------------- */
static async _configureSubMenu(insertionPoint, template, hudData, onMenuItem) {
const hud = $(await renderTemplate(template, hudData));
const imgHud = hud.find('img.rdd-hud-togglebutton');
const list = hud.find('div.rdd-hud-list');
RdDTokenHud._toggleHudListActive(hud, list);
hud.find('img.rdd-hud-togglebutton').click(event => RdDTokenHud._toggleHudListActive(hud, list));
hud.toggleClass('active');
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
imgHud.click(event => {
hud.toggleClass('active');
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
});
list.find('.rdd-hud-menu').click(onMenuItem);
insertionPoint.after(hud);
}
static _toggleHudListActive(hud, list) {
hud.toggleClass('active');
HtmlUtility._showControlWhen(list, hud.hasClass('active'));
}
}

View File

@ -4,12 +4,6 @@ import { ChatUtility } from "./chat-utility.js";
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 { ReglesOptionelles } from "./regles-optionelles.js";
import { RdDDice } from "./rdd-dice.js";
import { RdDItem } from "./item.js";
import { Monnaie } from "./item-monnaie.js";
/* -------------------------------------------- */
// This table starts at 0 -> niveau -10
@ -98,13 +92,6 @@ const definitionsEncaissement = {
/* -------------------------------------------- */
export class RdDUtility {
/* -------------------------------------------- */
static async init() {
Hooks.on("renderChatMessage", async (app, html, msg) => RdDUtility.onRenderChatMessage(app, html, msg));
Hooks.on('renderChatLog', (log, html, data) => RdDUtility.chatListeners(html));
}
/* -------------------------------------------- */
static async preloadHandlebarsTemplates() {
const templatePaths = [
@ -114,14 +101,8 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/actor-entite-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-vehicule-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-competence-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-categorie-competences-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-oeuvre-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-liste-blessures-partial.html',
'systems/foundryvtt-reve-de-dragon/templates/actor-blessure-partial.html',
// Conteneur/item in Actor sheet
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-inventaire-conteneur.html',
"systems/foundryvtt-reve-de-dragon/templates/actor-sheet-inventaire-monnaie.html",
'systems/foundryvtt-reve-de-dragon/templates/actor-sheet-editor-notes-mj.html',
//Items
'systems/foundryvtt-reve-de-dragon/templates/item-competence-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-competencecreature-sheet.html',
@ -143,8 +124,6 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/item-ombre-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-monnaie-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-meditation-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-nourritureboisson-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/item-signedraconique-sheet.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-carac-defaut.html',
'systems/foundryvtt-reve-de-dragon/templates/competence-base.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-aspect-tarot.html',
@ -153,8 +132,6 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-parade.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-vehicule.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-herbesoin-ingredient.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-categorie-potion.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-initpremierround.html',
'systems/foundryvtt-reve-de-dragon/templates/enum-rarete.html',
'systems/foundryvtt-reve-de-dragon/templates/sort-draconic.html',
@ -162,6 +139,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/niveau-ethylisme.html',
'systems/foundryvtt-reve-de-dragon/templates/casetmr-specific-list.html',
// Dialogs
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-resolution.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html',
@ -169,22 +147,17 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-encaisser.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-meditation.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/dialog-astrologie-joueur.html',
// Partials
'systems/foundryvtt-reve-de-dragon/templates/partial-description-overflow.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-description-sort.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-ajustements.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffLibre.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-diffCondition.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-surenc.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-enctotal.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-roll-moral.html',
'systems/foundryvtt-reve-de-dragon/templates/partial-select-carac.html',
// Calendrier
'systems/foundryvtt-reve-de-dragon/templates/calendar-template.html',
'systems/foundryvtt-reve-de-dragon/templates/calendar-editor-template.html',
'systems/foundryvtt-reve-de-dragon/templates/heures-select-option.html',
// Conteneur/item in Actor sheet
'systems/foundryvtt-reve-de-dragon/templates/actor-inventaire-conteneur.html',
'systems/foundryvtt-reve-de-dragon/templates/editor-notes-mj.html',
// HUD
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-init.html',
'systems/foundryvtt-reve-de-dragon/templates/hud-actor-attaque.html',
@ -207,10 +180,7 @@ export class RdDUtility {
'systems/foundryvtt-reve-de-dragon/templates/chat-resultat-alchimie.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-turn-summary.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-competence-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-potionenchantee-chateaudormant.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-fabriquer-potion-base.html',
'systems/foundryvtt-reve-de-dragon/templates/chat-signe-draconique-actor.html'
'systems/foundryvtt-reve-de-dragon/templates/chat-actor-carac-xp.html'
];
Handlebars.registerHelper('upperFirst', str => Misc.upperFirst(str ?? 'Null'));
@ -219,103 +189,10 @@ export class RdDUtility {
Handlebars.registerHelper('un', str => Grammar.articleIndetermine(str));
Handlebars.registerHelper('accord', (genre, ...args) => Grammar.accord(genre, args));
Handlebars.registerHelper('buildConteneur', (objet) => { return RdDUtility.buildConteneur(objet); });
Handlebars.registerHelper('caseTmr-label', coord => TMRUtility.getTMRLabel(coord));
Handlebars.registerHelper('caseTmr-type', coord => TMRUtility.getTMRType(coord));
Handlebars.registerHelper('typeTmr-name', coord => TMRUtility.typeTmrName(coord));
Handlebars.registerHelper('min', (...args) => Math.min(...args.slice(0, -1)));
Handlebars.registerHelper('sortCompetence', competences => competences.sort((a, b) => {
if (a.name.startsWith("Survie") && b.name.startsWith("Survie")) {
if (a.name.includes("Cité")) return -1;
if (b.name.includes("Cité")) return 1;
if (a.name.includes("Extérieur")) return -1;
if (b.name.includes("Extérieur")) return 1;
return a.name.localeCompare(b.name);
}
if (a.data.categorie.startsWith("melee") && b.data.categorie.startsWith("melee")) {
if (a.name.includes("Corps")) return -1;
if (b.name.includes("Corps")) return 1;
if (a.name.includes("Dague")) return -1;
if (b.name.includes("Dague")) return 1;
if (a.name.includes("Esquive")) return -1;
if (b.name.includes("Esquive")) return 1;
return a.name.localeCompare(b.name);
}
if (a.name.startsWith("Voie") && b.name.startsWith("Voie")) {
if (a.name.includes("Oniros")) return -1;
if (b.name.includes("Oniros")) return 1;
if (a.name.includes("Hypnos")) return -1;
if (b.name.includes("Hypnos")) return 1;
if (a.name.includes("Narcos")) return -1;
if (b.name.includes("Narcos")) return 1;
if (a.name.includes("Thanatos")) return -1;
if (b.name.includes("Thanatos")) return 1;
return a.name.localeCompare(b.name);
}
return a.name.localeCompare(b.name);
}));
return loadTemplates(templatePaths);
}
/* -------------------------------------------- */
static async creerObjet(actorSheet) {
let itemType = $(".item-type").val();
await actorSheet.createItem('Nouveau ' + itemType, itemType);
}
/* -------------------------------------------- */
static async selectObjetType( actorSheet) {
let typeObjets = RdDItem.getTypeObjetsEquipement();
let options = `<span class="competence-label">Selectionnez le type d'équipement</span><select class="item-type">`;
for (let typeName of typeObjets) {
options += `<option value="${typeName}">${typeName}</option>`
}
options += '</select>';
let d = new Dialog({
title: "Créer un équipement",
content: options,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'objet",
callback: () => this.creerObjet(actorSheet)
}
}
});
d.render(true);
}
/* -------------------------------------------- */
static async selectTypeOeuvre( actorSheet) {
let typeObjets = RdDItem.getTypesOeuvres();
let options = `<span class="competence-label">Selectionnez le type d'oeuvre</span><select class="item-type">`;
for (let typeName of typeObjets) {
options += `<option value="${typeName}">${typeName}</option>`
}
options += '</select>';
let d = new Dialog({
title: "Créer un équipement",
content: options,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Créer l'objet",
callback: () => this.creerObjet(actorSheet)
}
}
});
d.render(true);
}
/* -------------------------------------------- */
static buildListOptions(min, max) {
let options = ""
for (let i = min; i <= max; i++) {
options += `<option value="${i}">${i}</option>`
}
return options;
}
/* -------------------------------------------- */
static checkNull(items) {
@ -349,87 +226,93 @@ export class RdDUtility {
/* -------------------------------------------- */
static filterItemsPerTypeForSheet(formData) {
formData.materiel = this.checkNull(formData.itemsByType['objet']);
formData.conteneurs = this.checkNull(formData.itemsByType['conteneur']);
formData.armes = this.checkNull(formData.itemsByType['arme']);
formData.armures = this.checkNull(formData.itemsByType['armure']);
formData.livres = this.checkNull(formData.itemsByType['livre']);
formData.potions = this.checkNull(formData.itemsByType['potion']);
formData.ingredients = this.checkNull(formData.itemsByType['ingredient']);
formData.munitions = this.checkNull(formData.itemsByType['munition']);
formData.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.sorts = this.checkNull(formData.itemsByType['sort']);
formData.signesdraconiques = this.checkNull(formData.itemsByType['signedraconique']);
formData.queues = this.checkNull(formData.itemsByType['queue']);
formData.souffles = this.checkNull(formData.itemsByType['souffle']);
formData.ombres = this.checkNull(formData.itemsByType['ombre']);
formData.tetes = this.checkNull(formData.itemsByType['tete']);
formData.taches = this.checkNull(formData.itemsByType['tache']);
formData.monnaie = this.checkNull(formData.itemsByType['monnaie']);
formData.nourritureboissons = this.checkNull(formData.itemsByType['nourritureboisson']);
formData.meditations = this.checkNull(formData.itemsByType['meditation']);
formData.chants = this.checkNull(formData.itemsByType['chant']);
formData.danses = this.checkNull(formData.itemsByType['danse']);
formData.musiques = this.checkNull(formData.itemsByType['musique']);
formData.oeuvres = this.checkNull(formData.itemsByType['oeuvre']);
formData.jeux = this.checkNull(formData.itemsByType['jeu']);
formData.recettescuisine = this.checkNull(formData.itemsByType['recettecuisine']);
formData.recettesAlchimiques = this.checkNull(formData.itemsByType['recettealchimique']);
formData.objets = formData.conteneurs.concat(formData.materiel)
.concat(formData.armes)
.concat(formData.armures)
.concat(formData.munitions)
.concat(formData.livres)
.concat(formData.potions)
.concat(formData.herbes)
.concat(formData.ingredients)
.concat(formData.nourritureboissons)
.concat(formData.monnaie);
formData.competences = (formData.itemsByType.competence ?? []).concat(formData.itemsByType.competencecreature ?? []);
formData.monnaie.sort(Monnaie.triValeurDenier());
formData.data.materiel = this.checkNull(formData.itemsByType['objet']);
formData.data.conteneurs = this.checkNull(formData.itemsByType['conteneur']);
formData.data.armes = this.checkNull(formData.itemsByType['arme']);
formData.data.armures = this.checkNull(formData.itemsByType['armure']);
formData.data.livres = this.checkNull(formData.itemsByType['livre']);
formData.data.potions = this.checkNull(formData.itemsByType['potion']);
formData.data.ingredients = this.checkNull(formData.itemsByType['ingredient']);
formData.data.munitions = this.checkNull(formData.itemsByType['munition']);
formData.data.herbes = this.checkNull(formData.itemsByType['herbe']);
formData.data.sorts = this.checkNull(formData.itemsByType['sort']);
formData.data.queues = this.checkNull(formData.itemsByType['queue']);
formData.data.souffles = this.checkNull(formData.itemsByType['souffle']);
formData.data.ombres = this.checkNull(formData.itemsByType['ombre']);
formData.data.tetes = this.checkNull(formData.itemsByType['tete']);
formData.data.taches = this.checkNull(formData.itemsByType['tache']);
formData.data.monnaie = this.checkNull(formData.itemsByType['monnaie']);
formData.data.meditations = this.checkNull(formData.itemsByType['meditation']);
formData.data.chants = this.checkNull(formData.itemsByType['chant']);
formData.data.danses = this.checkNull(formData.itemsByType['danse']);
formData.data.musiques = this.checkNull(formData.itemsByType['musique']);
formData.data.oeuvres = this.checkNull(formData.itemsByType['oeuvre']);
formData.data.jeux = this.checkNull(formData.itemsByType['jeu']);
formData.data.recettescuisine = this.checkNull(formData.itemsByType['recettecuisine']);
formData.data.recettesAlchimiques = this.checkNull(formData.itemsByType['recettealchimique']);
formData.data.objets = formData.data.conteneurs.concat(formData.data.materiel)
.concat(formData.data.armes)
.concat(formData.data.armures)
.concat(formData.data.munitions)
.concat(formData.data.livres)
.concat(formData.data.potions)
.concat(formData.data.herbes)
.concat(formData.data.ingredients);
formData.data.competences = (formData.itemsByType.competence??[]).concat(formData.itemsByType.competencecreature??[]);
}
/* -------------------------------------------- */
static buildArbreDeConteneurs(conteneurs, objets) {
let objetVersConteneur = {};
static async processItemDropEvent(actorSheet, event) {
let dragData = JSON.parse(event.dataTransfer.getData("text/plain"));
console.log(dragData, actorSheet.actor._id);
let dropID = $(event.target).parents(".item").attr("data-item-id"); // Only relevant if container drop
let objetId = dragData.id || dragData.data._id;
if (dragData.type == 'Item') {
if (dropID) { // Dropped over an item !!!
if (actorSheet.objetVersConteneur[objetId] != dropID && objetId != dropID) {
if (actorSheet.actor.validateConteneur(objetId, dropID) && actorSheet.actor.testConteneurCapacite(objetId, dropID)) {
await actorSheet.actor.enleverDeConteneur(objetId, actorSheet.objetVersConteneur[objetId]);
await actorSheet.actor.ajouterAConteneur(objetId, dropID);
}
}
}
if (dragData.actorId && dragData.actorId != actorSheet.actor._id) { // Un acteur est à l'origine de l'item -> deplacement
console.log("Moving objects");
actorSheet.actor.moveItemsBetweenActors(objetId, dragData.actorId);
return false;
}
actorSheet.actor.computeEncombrementTotalEtMalusArmure();
} else if (dragData.type == "Actor") {
actorSheet.actor.addSubacteur(objetId);
}
return true;
}
/* -------------------------------------------- */
static buildArbreDeConteneur(actorSheet, data) {
actorSheet.objetVersConteneur = {}; // Table de hash locale pour recupération rapide du conteneur parent (si existant)
// Attribution des objets aux conteneurs
for (let conteneur of conteneurs) {
for (let conteneur of data.data.conteneurs) {
conteneur.subItems = [];
for (let id of conteneur.data.contenu ?? []) {
let objet = objets.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.data.encTotal) conteneur.data.encTotal = 0;
//conteneur.data.encTotal = ; Deja calculé
if (conteneur.data.contenu) {
for (let id of conteneur.data.contenu) {
let objet = data.data.objets.find(objet => (id == objet._id));
if (objet) {
if (!objet.data.encombrement) objet.data.encombrement = 0; // Auto-fix
objet.estContenu = true; // Permet de filtrer ce qifui est porté dans le template
actorSheet.objetVersConteneur[id] = conteneur._id;
conteneur.data.encTotal += Number(objet.data.encombrement) * Number(((objet.data.quantite) ? objet.data.quantite : 1));
conteneur.subItems.push(objet);
}
}
}
}
for (let conteneur of conteneurs) {
conteneur.data.encTotal = RdDUtility.calculEncContenu(conteneur, objets);
}
return objetVersConteneur;
}
static calculEncContenu(conteneur, objets) {
const itemData = Misc.data(conteneur);
const contenuDatas = (itemData.data.contenu ?? []).filter(id => id != undefined)
.map(id => Misc.data(objets.find(it => (id == it._id))))
.filter(it => it);
let enc = Number(itemData.data.encombrement ?? 0) * Number(itemData.data.quantite ?? 1);
for (let itemData of contenuDatas){
if (itemData.type == 'conteneur') {
enc += RdDUtility.calculEncContenu(itemData, objets);
}
else{
enc += Number(itemData.data.encombrement ?? 0) * Number(itemData.data.quantite ?? 1);
}
}
return enc;
}
// Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur)
static conteneursRacine(conteneurs) {
return conteneurs.filter((conteneur, index, arr) => !conteneur.estContenu);
// Construit la liste des conteneurs de niveau 1 (c'est à dire non contenu eux-même dans un conteneur)
let newConteneurs = data.data.conteneurs.filter(function (conteneur, index, arr) { return !conteneur.estContenu });
data.data.conteneurs = newConteneurs;
//console.log(newConteneurs);
}
/* -------------------------------------------- */
@ -440,7 +323,7 @@ export class RdDUtility {
if (!niveau) niveau = 1;
objet.niveau = niveau;
//console.log("OBJ:", objet);
let str = Handlebars.partials['systems/foundryvtt-reve-de-dragon/templates/actor-sheet-inventaire-conteneur.html']({ item: objet });
let str = Handlebars.partials['systems/foundryvtt-reve-de-dragon/templates/actor-inventaire-conteneur.html']({ item: objet });
if (objet.type == 'conteneur') {
//console.log("ITEM DISPLAYED", objet );
if (this.getAfficheContenu(objet._id)) {
@ -493,14 +376,6 @@ export class RdDUtility {
}
return -7;
}
static calculFatigueHtml(fatigue, endurance) {
return ReglesOptionelles.isUsing("appliquer-fatigue") ? {
malus: RdDUtility.calculMalusFatigue(fatigue, endurance),
html: "<table class='table-fatigue'>" + RdDUtility.makeHTMLfatigueMatrix(fatigue, endurance).html() + "</table>"
} : { malus: 0, html: '' };
}
/* -------------------------------------------- */
// Build the nice (?) html table used to manage fatigue.
// max should be the endurance max value
@ -544,8 +419,8 @@ export class RdDUtility {
}
/* -------------------------------------------- */
static async getLocalisation(type = 'personnage') {
let result = await RdDDice.rollTotal("1d20");
static getLocalisation(type = 'personnage') {
let result = new Roll("1d20").roll().total;
let txt = ""
if (type == 'personnage') {
if (result <= 3) txt = "Jambe, genou, pied, jarret";
@ -577,35 +452,56 @@ export class RdDUtility {
return duplicate(table[0]);
}
/* -------------------------------------------- */
static currentFatigueMalus(value, max) {
if (ReglesOptionelles.isUsing("appliquer-fatigue")) {
max = Math.max(1, Math.min(max, 60));
value = Math.min(max * 2, Math.max(0, value));
let fatigueTab = fatigueMatrix[max];
let fatigueRem = value;
for (let idx = 0; idx < fatigueTab.length; idx++) {
fatigueRem -= fatigueTab[idx];
if (fatigueRem <= 0) {
return fatigueMalus[idx];
}
}
return -7; // This is the max !
}
return 0;
/* -------------------------------------------- */
static _evaluatePerte(formula, over20) {
console.log("_evaluatePerte", formula, over20);
let perte = new Roll(formula, { over20: over20 });
perte.evaluate();
return perte.total;
}
/* -------------------------------------------- */
static async loadCompendiumData(compendium) {
static currentFatigueMalus(value, max) {
max = Math.max(1, Math.min(max, 60));
value = Math.min(max * 2, Math.max(0, value));
let fatigueTab = fatigueMatrix[max];
let fatigueRem = value;
for (let idx = 0; idx < fatigueTab.length; idx++) {
fatigueRem -= fatigueTab[idx];
if (fatigueRem <= 0) {
return fatigueMalus[idx];
}
}
return -7; // This is the max !
}
/* -------------------------------------------- */
static async loadCompendiumNames(compendium) {
const pack = game.packs.get(compendium);
return await pack?.getDocuments() ?? [];
let competences;
await pack.getIndex().then(index => competences = index);
return competences;
}
/* -------------------------------------------- */
static async loadCompendium(compendium, filter = item => true) {
let compendiumData = await RdDUtility.loadCompendiumData(compendium);
return compendiumData.filter(filter);
if (!compendium){
return [];
}
let compendiumItems = await RdDUtility.loadCompendiumNames(compendium);
const pack = game.packs.get(compendium);
let list = [];
for (let compendiumItem of compendiumItems) {
await pack.getEntity(compendiumItem._id).then(it => {
const item = it.data;
if (filter(item)) {
list.push(item);
}
});
};
return list;
}
/* -------------------------------------------- */
@ -616,6 +512,7 @@ export class RdDUtility {
/* -------------------------------------------- */
static onSocketMesssage(sockmsg) {
console.log(">>>>> MSG RECV", sockmsg);
switch (sockmsg.msg) {
case "msg_gm_chat_message":
return ChatUtility.handleGMChatMessage(sockmsg.data);
@ -626,14 +523,16 @@ export class RdDUtility {
case "msg_response_nombre_astral":
return RdDUtility.responseNombreAstral(sockmsg.data);
case "msg_tmr_move":
let actor = game.actors.get(sockmsg.data.actorId);
if (actor.isOwner || game.user.isGM) {
if (game.user.isGM) {
let actor = game.actors.get(sockmsg.data.actorId);
actor.refreshTMRView(sockmsg.data.tmrPos);
}
break;
}
}
/* -------------------------------------------- */
static async chatListeners(html) {
RdDCombat.registerChatCallbacks(html);
@ -653,72 +552,27 @@ export class RdDUtility {
let actor = game.actors.get(actorId);
actor.tmrApp.lancerSortEnReserve(coord, sortId);
});
// gestion bouton tchat Acheter
html.on("click", '.button-acheter', event => DialogItemAchat.onButtonAcheter(event));
// Gestion du bouton payer
html.on("click", '.payer-button', event => {
let sumdenier = event.currentTarget.attributes['data-somme-denier']?.value ?? 0;
let quantite = event.currentTarget.attributes['data-quantite']?.value ?? 1;
let fromActorId = event.currentTarget.attributes['data-actor-id']?.value;
html.on("click", '#payer-button', event => {
let sumdenier = event.currentTarget.attributes['data-somme-denier'].value;
let quantite = 1;
if ( event.currentTarget.attributes['data-quantite'] ) {
quantite = event.currentTarget.attributes['data-quantite'].value;
}
let jsondata = event.currentTarget.attributes['data-jsondata']
let objData
if (jsondata) {
objData = JSON.parse(jsondata.value)
}
let actor = RdDUtility.getSelectedActor("Pour effectuer le paiement:");
if (actor) {
actor.depenserDeniers(sumdenier, objData, quantite, fromActorId);
ChatUtility.removeChatMessageId(RdDUtility.findChatMessageId(event.currentTarget));
if (game.user.character) {
game.user.character.payerDenier(sumdenier, objData, quantite);
} else {
let msgPayer = "Vous devez avoir un acteur relié pour effectuer le paiement";
ChatMessage.create({ content: msgPayer, whisper: [game.user] });
}
});
}
static findChatMessageId(current) {
return RdDUtility.getChatMessageId(RdDUtility.findChatMessage(current));
}
static getChatMessageId(node) {
return node?.attributes.getNamedItem('data-message-id')?.value;
}
static findChatMessage(current) {
return RdDUtility.findNodeMatching(current, it => it.classList.contains('chat-message') && it.attributes.getNamedItem('data-message-id'));
}
static findNodeMatching(current, predicate) {
if (current) {
if (predicate(current)) {
return current;
}
return RdDUtility.findNodeMatching(current.parentElement, predicate);
}
return undefined;
}
static getSelectedActor(msgPlayer = undefined) {
if (canvas.tokens.controlled.length == 1) {
let token = canvas.tokens.controlled[0];
if (token.actor && token.data.actorLink) {
return token.actor;
}
if (msgPlayer != undefined) {
msgPlayer += "<br>le token sélectionné doit être lié à un personnage";
}
}
if (game.user.character) {
return game.user.character;
}
if (msgPlayer != undefined) {
msgPlayer += "<br>vous pouvez sélectionner un seul token lié à un personnage";
msgPlayer += "<br>vous devez être connecté comme joueur avec un personnage sélectionné";
ui.notifications.warn(msgPlayer);
ChatMessage.create({ content: msgPlayer, whisper: [game.user] });
}
return undefined;
}
/* -------------------------------------------- */
static createMonnaie(name, valeur_deniers, img = "", enc = 0.01) {
let piece = {
@ -750,14 +604,14 @@ export class RdDUtility {
let sumtotald = sumd + (sums * 100);
let msgPayer = "La somme de " + sums + " Sols et " + sumd + " Deniers est à payer, cliquer sur le lien ci-dessous si besoin.<br>";
msgPayer += "<a class='payer-button chat-card-button' data-somme-denier='" + sumtotald + "'>Payer</a>"
msgPayer += "<a id='payer-button' class='chat-card-button' data-somme-denier='" + sumtotald + "'>Payer</a>"
ChatMessage.create({ content: msgPayer });
}
/* -------------------------------------------- */
static chatDataSetup(content, modeOverride, isRoll = false, forceWhisper) {
let chatData = {
user: game.user.id,
user: game.user._id,
rollMode: modeOverride || game.settings.get("core", "rollMode"),
content: content
};
@ -805,13 +659,7 @@ export class RdDUtility {
/* -------------------------------------------- */
static async confirmerSuppression(actorSheet, li) {
let itemId = li.data("item-id");
let objet = actorSheet.actor.getObjet(itemId);
if ( objet.type == 'monnaie' && Monnaie.isSystemMonnaie(objet) ) {
ui.notifications.warn("Suppression des monnaies de base impossible");
return;
}
let objet = actorSheet.actor.items.find(item => item._id == itemId);
let msgTxt = "<p>Etes vous certain de vouloir supprimer cet objet ?";
let buttons = {
delete: {
@ -819,7 +667,7 @@ export class RdDUtility {
label: "Supprimer l'objet",
callback: () => {
console.log("Delete : ", itemId);
actorSheet.actor.deleteEmbeddedDocuments('Item', [itemId]);
actorSheet.actor.deleteOwnedItem(itemId);
li.slideUp(200, () => actorSheet.render(false));
}
},
@ -828,9 +676,8 @@ export class RdDUtility {
label: "Annuler"
}
}
const docData = Misc.data(objet);
if (docData.type == 'conteneur' && docData.data.contenu.length > 0) {
msgTxt += "<br>Ce conteneur n'est pas vide. Choisissez l'option de suppression";
if (objet.data.type == 'conteneur' && objet.data.data.contenu.length > 0) {
msgTxt += "<br>Cet objet est aussi un conteneur avec du contenu : choisissez l'option de suppression";
buttons['deleteall'] = {
icon: '<i class="fas fa-check"></i>',
label: "Supprimer le conteneur et tout son contenu",
@ -854,23 +701,18 @@ export class RdDUtility {
/* -------------------------------------------- */
static afficherHeuresChanceMalchance(heureNaissance) {
if ( game.user.isGM) {
let heure = game.system.rdd.calendrier.findHeure(heureNaissance);
if (heureNaissance && heure) {
if (heureNaissance) {
let ajustement = game.system.rdd.calendrier.getAjustementAstrologique(heureNaissance);
const current = game.system.rdd.calendrier.findHeure(game.system.rdd.calendrier.getCurrentHeure());
ChatMessage.create({
content: `A l'heure de <strong>${current.label}</strong>, le modificateur de Chance/Malchance est de <strong>${Misc.toSignedString(ajustement)}</strong> pour l'heure de naissance <strong>${heure.label}</strong>.`,
content: `A l'heure ${game.system.rdd.calendrier.getCurrentHeure()}, le modificateur de Chance/Malchance pour l'heure de naissance ${heureNaissance} est de : ${ajustement}.`,
whisper: ChatMessage.getWhisperRecipients("GM")
});
}
else if (heureNaissance) {
ui.notifications.warn(heureNaissance+" ne correspond pas à une heure de naissance");
}
else {
ui.notifications.warn("Pas d'heure de naissance selectionnée");
ui.notifications.warn("Pas d'heure de naissance selectionnée")
}
} else {
ui.notifications.warn("Vous n'avez pas accès à cette commande");
ui.notifications.warn("Vous n'avez pas accès à cette commande")
}
}
@ -885,32 +727,6 @@ export class RdDUtility {
}
}
/*-------------------------------------------- */
static distribuerStress(stressValue, raison = 'Inconnu', nomJoueur = undefined) {
if (game.user.isGM) {
if (stressValue == undefined){
ui.notifications.warn("Pas de valeuir de stress à distribuer!");
return;
}
if (nomJoueur == undefined) {
for (let actor of game.actors) {
if (actor.hasPlayerOwner && actor.isPersonnage() ) {
actor.addCompteurValue('stress', stressValue, raison);
ui.notifications.info(`${actor.name} a reçu ${stressValue} points de Stress (raison : ${raison})`);
}
}
} else {
//console.log(stressValue, nomJoueur);
let joueur = game.users.find(user => user.name.toLowerCase() == nomJoueur.toLowerCase());
//console.log("Player", joueur, joueur.character );
joueur.character.addCompteurValue('stress', stressValue, raison);
ui.notifications.info(`${joueur.character.name} a reçu ${stressValue} points de Stress (raison : ${raison})`);
}
} else {
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /stress");
}
}
/*-------------------------------------------- */
static async onRenderChatMessage(app, html, msg) {
// TODO

View File

@ -1,15 +1,12 @@
import { Misc } from "./misc.js";
const listeReglesOptionelles = [
{ name: 'recul', group: 'Règles de combat', descr: "Appliquer le recul en cas de particulière en force ou de charge" },
{ name: 'resistanceArmeParade', group: 'Règles de combat', descr: "Faire le jet de résistance des armes lors de parades pouvant les endommager" },
{ name: 'deteriorationArmure', group: 'Règles de combat', descr: "Tenir compte de la détérioration des armures" },
{ name: 'defenseurDesarme', group: 'Règles de combat', descr: "Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier" },
{ name: 'categorieParade', group: 'Règles de combat', descr: "Le défenseur doit obtenir une significative en cas de parade avec des armes de catégories différentes" },
{ name: 'tripleSignificative', group: 'Règles de combat', descr: "En cas de demi-surprise, d'attaque particulière en finesse, et de catégories d'armes différentes, le défenseur doit obtenir 1/8 des chances de succès" },
{ name: 'astrologie', group: 'Règles de générales', descr: "Appliquer les ajustements astrologiques aux jets de chance et aux rituels", default: true },
{ name: 'afficher-prix-joueurs', group: 'Règles de générales', descr: "Afficher le prix de l'équipement des joueurs", default: true },
{ name: 'appliquer-fatigue', group: 'Règles de générales', descr: "Appliquer les règles de fatigue", default: true },
{name:'recul', group:'combat', descr:"Appliquer le recul en cas de particulière en force ou de charge"},
{name:'resistanceArmeParade', group:'combat', descr:"Faire le jet de résistance des armes lors de parades pouvant les endommager"},
{name:'deteriorationArmure', group:'combat', descr:"Tenir compte de la détérioration des armures"},
{name:'defenseurDesarme', group:'combat', descr:"Le défenseur peut être désarmé en parant une particulière en force ou une charge avec une arme autre qu'un bouclier"},
{name:'categorieParade', group:'combat', descr:"Le défenseur doit obtenir une significative en cas de parade avec des armes de catégories différentes"},
{name:'tripleSignificative', group:'combat', descr:"En cas de demi-surprise, d'attaque particulière en finesse, et de catégories d'armes différentes, le défenseur doit obtenir 1/8 des chances de succès"},
{name:'astrologie', group:'generale', descr:"Appliquer les ajustements astrologiques aux jets de chance et aux rituels"}
];
export class ReglesOptionelles extends FormApplication {
@ -17,7 +14,7 @@ export class ReglesOptionelles extends FormApplication {
for (const regle of listeReglesOptionelles) {
const name = regle.name;
const id = ReglesOptionelles._getIdRegle(name);
game.settings.register("foundryvtt-reve-de-dragon", id, { name: id, scope: "world", config: false, default: regle.default == undefined ? true : regle.default, type: Boolean });
game.settings.register("foundryvtt-reve-de-dragon", id, { name: id, scope: "world", config: false, default: regle.default??true, type: Boolean });
}
game.settings.registerMenu("foundryvtt-reve-de-dragon", "rdd-options-regles", {
@ -41,27 +38,25 @@ export class ReglesOptionelles extends FormApplication {
static get defaultOptions() {
const options = super.defaultOptions;
mergeObject(options, {
id: "optional-settings",
id: "combat-settings",
template: "systems/foundryvtt-reve-de-dragon/templates/regles-optionelles.html",
height: 600,
width: 350,
minimizable: false,
closeOnSubmit: true,
title: "Règles optionnelles"
title: "Options de combat"
});
return options;
}
getData() {
let formData = super.getData();
const regles = listeReglesOptionelles.map(it => {
it = duplicate(it);
it.id = ReglesOptionelles._getIdRegle(it.name);
it.active = ReglesOptionelles.isUsing(it.name);
return it;
});
formData.regles = regles;
formData.groups = Misc.classify(regles, it => it.group);
formData.regles = listeReglesOptionelles.map(it => {
let r = duplicate(it);
r.id = ReglesOptionelles._getIdRegle(r.name);
r.active = ReglesOptionelles.isUsing(r.name);
return r;
})
return formData;
}

View File

@ -5,7 +5,6 @@ import { RdDItemSort } from "./item-sort.js";
import { Misc } from "./misc.js";
import { RdDBonus } from "./rdd-bonus.js";
import { RdDCarac } from "./rdd-carac.js";
import { RdDUtility } from "./rdd-utility.js";
import { ReglesOptionelles } from "./regles-optionelles.js";
/**
@ -51,12 +50,12 @@ export const referenceAjustements = {
getValue: (rollData, actor) => RdDBonus.find(rollData.surpriseDefenseur).attaque,
},
etat: {
isUsed: (rollData, actor) => !RdDCarac.isIgnoreEtatGeneral(rollData),
isUsed: (rollData, actor) => !RdDCarac.isIgnoreEtatGeneral(rollData.selectedCarac, rollData.competence),
getLabel: (rollData, actor) => 'Etat général',
getValue: (rollData, actor) => actor.getEtatGeneral({ ethylisme: rollData.forceAlcool != undefined })
getValue: (rollData, actor) => actor.getEtatGeneral()
},
malusArmure: {
isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac),
isVisible: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.competence),
isUsed: (rollData, actor) => RdDCarac.isAgiliteOuDerivee(rollData.selectedCarac),
getLabel: (rollData, actor) => 'Malus armure',
getValue: (rollData, actor) => actor.getMalusArmure()
@ -121,24 +120,6 @@ export const referenceAjustements = {
isUsed: (rollData, actor) => rollData.tmr && rollData.rencontre?.name,
getLabel: (rollData, actor) => rollData.rencontre?.name,
getValue: (rollData, actor) => - (rollData.rencontre?.force ?? 0)
},
ethylismeAlcool: {
isVisible: (rollData, actor) => rollData.nbDoses != undefined,
isUsed: (rollData, actor) => rollData.nbDoses != undefined,
getLabel: (rollData, actor) => "Doses déjà bues: ",
getValue: (rollData, actor) => - rollData.nbDoses,
},
ethylismeDoses: {
isVisible: (rollData, actor) => rollData.nbDoses != undefined,
isUsed: (rollData, actor) => rollData.nbDoses != undefined,
getLabel: (rollData, actor) => "Force de l'alcool: ",
getValue: (rollData, actor) => rollData.forceAlcool,
},
ethylisme:{
isVisible: (rollData, actor) => rollData.ethylisme != undefined,
isUsed: (rollData, actor) => rollData.ethylisme != undefined,
getLabel: (rollData, actor) => "Ethylisme - " + RdDUtility.getNomEthylisme(rollData.ethylisme),
getValue: (rollData, actor) => rollData.ethylisme,
}
}
@ -150,7 +131,6 @@ export class RollDataAjustements {
for (var key in referenceAjustements) {
const reference = referenceAjustements[key];
rollData.ajustements[key] = {
visible: reference.isVisible && reference.isVisible(rollData, actor),
used: reference.isUsed(rollData, actor),
label: reference.getLabel && reference.getLabel(rollData, actor),
value: reference.getValue && reference.getValue(rollData, actor),

View File

@ -1,6 +1,5 @@
import { Grammar } from "./grammar.js";
import { Misc } from "./misc.js";
import { RdDDice } from "./rdd-dice.js";
import { TMRUtility } from "./tmr-utility.js";
import { TMRType } from "./tmr-utility.js";
@ -8,11 +7,11 @@ import { TMRType } from "./tmr-utility.js";
const typeRencontres = {
messager: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose d'emmener le message de votre un sort à ${rencData.rencontre.force} cases ${rencData.tmr.label}.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
msgSucces: (data) => `Le ${data.rencontre.name} vous propose d'emmener le message de votre un sort à ${data.rencontre.force} cases ${data.tmr.label}.`,
msgEchec: (data) => `Le ${data.rencontre.name} est pressé et continue son chemin d'une traite sans vous accorder un regard.`,
postSucces: (tmrDialog, data) => {
tmrDialog.setStateRencontre(data.rencontre.type);
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force);
},
poesieSucces: {
reference: "La chevelure, Charles Baudelaire",
@ -28,11 +27,11 @@ const typeRencontres = {
},
passeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vous propose de vous transporter à ${rencData.rencontre.force} cases des ${rencData.tmr.label}.`,
msgEchec: (rencData) => `Le prix que demande le ${rencData.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCasePortee(rencData.tmr.coord, rencData.rencontre.force);
msgSucces: (data) => `Le ${data.rencontre.name} vous propose de vous transporter à ${data.rencontre.force} cases des ${data.tmr.label}.`,
msgEchec: (data) => `Le prix que demande le ${data.rencontre.name} est trop élevé, vous êtes réduit à poursuivre votre chemin par vos propres moyens.`,
postSucces: (tmrDialog, data) => {
tmrDialog.setStateRencontre(data.rencontre.type);
tmrDialog.choisirCasePortee(data.tmr.coord, data.rencontre.force);
},
poesieSucces: {
reference: "Femmes damnées (2), Charles Baudelaire",
@ -49,9 +48,9 @@ const typeRencontres = {
},
fleur: {
msgSucces: (rencData) => `Vous cueillez la ${rencData.rencontre.name}, son parfum vous apporte ${rencData.rencontre.force} points de Rêve.`,
msgEchec: (rencData) => `La ${rencData.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(rencData.rencontre.force),
msgSucces: (data) => `Vous cueillez la ${data.rencontre.name}, son parfum vous apporte ${data.rencontre.force} points de Rêve.`,
msgEchec: (data) => `La ${data.rencontre.name} se fâne et disparaît entre vos doigts.`,
postSucces: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(data.rencontre.force),
poesieSucces: {
reference: "L'Ennemi, Charles Baudelaire",
extrait: `Et qui sait si les fleurs nouvelles que je rêve
@ -66,9 +65,9 @@ const typeRencontres = {
},
mangeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} croque votre Rêve ! Il emporte ${rencData.rencontre.force} de vos points de rêve actuels`,
postEchec: (tmrDialog, rencData) => tmrDialog.actor.reveActuelIncDec(-rencData.rencontre.force),
msgSucces: (data) => `Le ${data.rencontre.name} claque de sa machoire dans le vide avant de fuir.`,
msgEchec: (data) => `Le ${data.rencontre.name} croque votre Rêve ! Il emporte ${data.rencontre.force} de vos points de rêve actuels`,
postEchec: (tmrDialog, data) => tmrDialog.actor.reveActuelIncDec(-data.rencontre.force),
poesieSucces: {
reference: "Conseil, Victor Hugo",
extrait: `Rois ! la bure est souvent jalouse du velours.
@ -85,16 +84,16 @@ const typeRencontres = {
},
changeur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[rencData.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: (rencData) => {
rencData.newTMR = TMRUtility.getTMRAleatoire(it => it.type = rencData.tmr.type);
return `Le ${rencData.rencontre.name} vous embobine avec des promesses, et vous transporte en ${rencData.newTMR.label} sans attendre votre avis.`;
msgSucces: (data) => `Le ${data.rencontre.name} vaincu accepte de vous déplacer sur une autre ${TMRType[data.tmr.type].name} de votre choix en échange de sa liberté.`,
msgEchec: (data) => {
data.newTMR = TMRUtility.getTMRAleatoire(it => it.type = data.tmr.type);
return `Le ${data.rencontre.name} vous embobine avec des promesses, et vous transporte en ${data.newTMR.label} sans attendre votre avis.`;
},
postSucces: (tmrDialog, rencData) => {
tmrDialog.setStateRencontre(rencData.rencontre.type);
tmrDialog.choisirCaseType(rencData.tmr.type);
postSucces: (tmrDialog, data) => {
tmrDialog.setStateRencontre(data.rencontre.type);
tmrDialog.choisirCaseType(data.tmr.type);
},
postEchec: (tmrDialog, rencData) => tmrDialog.forceDemiRevePosition(rencData.newTMR.coord),
postEchec: (tmrDialog, data) => tmrDialog.forceDemiRevePosition(data.newTMR.coord),
poesieSucces: {
reference: "Caligula - IIIème chant, Gérard de Nerval",
extrait: `Allez, que le caprice emporte
@ -111,9 +110,9 @@ const typeRencontres = {
},
briseur: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: (tmrDialog, rencData) => tmrDialog.close(),
msgSucces: (data) => `Le ${data.rencontre.name} tente vainement de vous déconcentrer, avant de fuir sans demander son reste.`,
msgEchec: (data) => `Le ${data.rencontre.name} vous déconcentre au point de briser votre demi-rêve.`,
postEchec: (tmrDialog, data) => tmrDialog.close(),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `La légende affirme que ce sont les Gnomes qui furent
@ -134,8 +133,8 @@ const typeRencontres = {
},
reflet: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: (rencData) => `Vous êtes submergé par un ${rencData.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
msgSucces: (data) => `Le ${data.rencontre.name} s'estompe dans l'oubli.`,
msgEchec: (data) => `Vous êtes submergé par un ${data.rencontre.name}, les souvenirs vous retiennent tant qu'il ne sera pas vaincu!`,
poesieSucces: {
reference: "Une charogne, Charles Baudelaire",
extrait: `Les formes s'effaçaient et n'étaient plus qu'un rêve,
@ -152,9 +151,9 @@ const typeRencontres = {
},
passeurfou: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: (rencData) => TMRRencontres.msgEchecPasseurFou(rencData),
postEchec: (tmrDialog, rencData) => TMRRencontres.postEchecPasseurFou(tmrDialog, rencData),
msgSucces: (data) => `Le ${data.rencontre.name} tente vainement de découvrir où vous avez caché vos réserves. Vous le chassez, et en déroute il part harceler un autre voyageur du rêve.`,
msgEchec: (data) => TMRRencontres.msgEchecPasseurFou(data),
postEchec: (tmrDialog, data) => TMRRencontres.postEchecPasseurFou(tmrDialog, data),
poesieSucces: {
reference: "Un Fou et un Sage, Jean de La Fontaine",
extrait: `Certain Fou poursuivait à coups de pierre un Sage.
@ -174,9 +173,9 @@ const typeRencontres = {
},
tbblanc: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: (rencData) => `Le souffle du ${rencData.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 1),
msgSucces: (data) => `Le ${data.rencontre.name} souleve une poussière blanche, vous tenez bon, et il tourbillonne en s'éloignant.`,
msgEchec: (data) => `Le souffle du ${data.rencontre.name} vous déstabilise et vous emmène dans un nuage de poussière.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 1),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le Premier Âge fut appelé l'Âge des Dragons. Ce fut le commencement
@ -191,9 +190,9 @@ const typeRencontres = {
},
tbnoir: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillon(tmrDialog, rencData, 2),
msgSucces: (data) => `Le ${data.rencontre.name} orageux vous enveloppe de fureur et d'éclairs, vous tenez bon face à la tempête qui s'éloigne sans vous éloigner de votre chemin.`,
msgEchec: (data) => `Le ${data.rencontre.name} furieux vous secoue tel un fichu de paille malmené par les vents, et vous emporte dans la tourmente.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillon(tmrDialog, data, 2),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Car le Second Âge fut bel et bien celui des Magiciens. Durant cette période, les
@ -207,9 +206,9 @@ const typeRencontres = {
},
tbrouge: {
msgSucces: (rencData) => `Le ${rencData.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: (rencData) => `Le ${rencData.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, rencData),
msgSucces: (data) => `Le ${data.rencontre.name} s'abat avec violence mais vous êtes plus rapide et parvenez à lui échapper.`,
msgEchec: (data) => `Le ${data.rencontre.name} vous frappe de milliers de morsure et vous malmène à travers les terres médianes.`,
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecTourbillonRouge(tmrDialog, data),
poesieSucces: {
reference: "Qu'est-ce de votre vie ? une bouteille molle, Jean-Baptiste Chassignet",
extrait: `Qu'est-ce de votre vie ? un tourbillon rouant
@ -228,10 +227,10 @@ const typeRencontres = {
},
rdd: {
msgSucces: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${rencData.rencontre.force} points de rêve`,
msgEchec: (rencData) => `A tout seigneur, tout honneur, vous faites face à un ${rencData.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${rencData.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: (tmrDialog, rencData) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, rencData),
postEchec: (tmrDialog, rencData) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, rencData),
msgSucces: (data) => `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. Vous le maîtrisez et récupérez ses rêves. Vous gagnez ses ${data.rencontre.force} points de rêve`,
msgEchec: (data) => `A tout seigneur, tout honneur, vous faites face à un ${data.rencontre.name}. La rencontre tourne au cauchemar, dans la lutte épique, vous subissez ${data.rolled.isETotal ? 'deux queues' : 'une queue'} de dragon!`,
postSucces: (tmrDialog, data) => TMRRencontres.onPostSuccessReveDeDragon(tmrDialog, data),
postEchec: (tmrDialog, data) => TMRRencontres.onPostEchecReveDeDragon(tmrDialog, data),
poesieSucces: {
reference: "Rêve de Dragon, Denis Gerfaud",
extrait: `Le monde est Rêve de Dragons, mais nous ne savons
@ -325,12 +324,12 @@ export class TMRRencontres {
return false;
}
if (!roll || roll <= 0 || roll > 100) {
roll = await RdDDice.rollTotal("1d100");
roll = new Roll("1d100").evaluate().total;
}
let rencontre = await TMRRencontres.getRencontreAleatoire(terrain, roll);
ChatMessage.create({
user: game.user.id,
whisper: [game.user.id],
user: game.user._id,
whisper: [game.user._id],
content: `Rencontre en ${terrain} (jet : ${roll}%)<br>Vous rencontrez un ${rencontre.name} de ${rencontre.force} Points de Rêve`
});
return false;
@ -349,7 +348,7 @@ export class TMRRencontres {
return duplicate(rencontre);
}
else {
ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.<br>Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`)
ui.notifications.info(`Pas de rencontre pour ${index}, seulement ${rencontresAll.length} rencontres sont connues.<br>Vous pouvez aussi essayer par type (ie: mangeur, fleur, fleur2d6, ...)`)
}
return undefined;
}
@ -357,13 +356,15 @@ export class TMRRencontres {
/* -------------------------------------------- */
static async getRencontreAleatoire(terrain, roll = undefined) {
if (!roll || roll <= 0 || roll > 100) {
roll = await RdDDice.rollTotal("1d100");
roll = new Roll("1d100").evaluate().total;
}
terrain = Grammar.toLowerCaseNoAccent(terrain);
//console.log("getRencontreAleatoire", terrain, roll);
const code = tableRencontres[terrain].find(it => it.range[0] <= roll && roll <= it.range[1]).code;
const rencontre = duplicate(rencontresStandard.find(it => it.code == code));
rencontre.roll = roll;
await TMRRencontres.evaluerForceRencontre(rencontre);
//console.log(rencontre);
return rencontre;
}
@ -372,14 +373,14 @@ export class TMRRencontres {
const rencontre = duplicate(
(index && index >= 0 && index < mauvaisesRencontres.length)
? mauvaisesRencontres[index]
: await RdDDice.rollOneOf(mauvaisesRencontres));
: Misc.rollOneOf(mauvaisesRencontres));
await TMRRencontres.evaluerForceRencontre(rencontre);
return rencontre;
}
/* -------------------------------------------- */
static async evaluerForceRencontre(rencontre) {
rencontre.force = await new Roll(rencontre.force).evaluate().total;
rencontre.force = new Roll(rencontre.force).evaluate().total;
return rencontre.force;
}
@ -399,59 +400,58 @@ export class TMRRencontres {
}
/* -------------------------------------------- */
static async gererRencontre(tmrDialog, rencData) {
let gestion = TMRRencontres.getGestionRencontre(rencData.rencontre.type);
if (rencData.rolled.isSuccess) {
rencData.message = gestion.msgSucces(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Au total, vous avez passé ${rencData.nbRounds} rounds à vous battre!`;
static async gererRencontre(tmrDialog, data) {
let gestion = TMRRencontres.getGestionRencontre(data.rencontre.type);
if (data.rolled.isSuccess) {
data.message = gestion.msgSucces(data);
if (data.nbRounds > 1) {
data.message += ` Au total, vous avez passé ${data.nbRounds} rounds à vous battre!`;
}
rencData.poesie = gestion.poesieSucces;
data.poesie = gestion.poesieSucces;
return gestion.postSucces;
}
rencData.message = gestion.msgEchec(rencData);
if (rencData.nbRounds > 1) {
rencData.message += ` Vous avez passé ${rencData.nbRounds} rounds à lutter!`;
data.message = gestion.msgEchec(data);
if (data.nbRounds > 1) {
data.message += ` Vous avez passé ${data.nbRounds} rounds à lutter!`;
}
rencData.poesie = gestion.poesieEchec;
data.poesie = gestion.poesieEchec;
return gestion.postEchec;
}
/* -------------------------------------------- */
static async msgEchecPasseurFou(tmrData) {
tmrData.sortReserve = Misc.templateData(tmrData.actor).reve.reserve.list[0];
if (tmrData.sortReserve) {
static msgEchecPasseurFou(data) {
data.sortReserve = data.actor.data.data.reve.reserve.list[0];
if (data.sortReserve) {
// Passeur fou positionne sur la case d'un ort en réserve // TODO : Choisir le sort le plus loin ou au hasard
tmrData.newTMR = TMRUtility.getTMR(tmrData.sortReserve.coord);
data.newTMR = TMRUtility.getTMR(data.sortReserve.coord);
} else {
// Déplacement aléatoire de la force du Passeur Fou
const newCoord = await RdDDice.rollOneOf(TMRUtility.getTMRPortee(tmrData.tmr.coord, tmrData.rencontre.force));
tmrData.newTMR = TMRUtility.getTMR(newCoord);
const newCoord = Misc.rollOneOf(TMRUtility.getTMRPortee(data.tmr.coord, data.rencontre.force));
data.newTMR = TMRUtility.getTMR(newCoord);
}
if (tmrData.sortReserve) {
return `Le ${tmrData.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${tmrData.newTMR.label} déclencher votre sort en réserve de ${tmrData.sortReserve.name}.`;
if (data.sortReserve) {
return `Le ${data.rencontre.name} vous dérobe la clé de vos sorts. Vous vous saisissez de lui, mais dans un nuage violet, il vous emporte en ${data.newTMR.label} déclencher votre sort en réserve de ${data.sortReserve.name}.`;
}
else {
return `Le ${tmrData.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${tmrData.newTMR.label}`;
return `Le ${data.rencontre.name} tente de vous dérober la clé de vos sorts. Ne la trouvant pas, il déclenche un nuage violet et vous emporte en ${data.newTMR.label}`;
}
}
/* -------------------------------------------- */
static async postEchecPasseurFou(tmrDialog, tmrData) {
if (tmrData.sortReserve) {
await tmrDialog.processSortReserve(tmrData.sortReserve);
static async postEchecPasseurFou(tmrDialog, data) {
if (data.sortReserve) {
await tmrDialog.processSortReserve(data.sortReserve);
}
await tmrDialog.forceDemiRevePosition(tmrData.newTMR.coord);
if (tmrData.sortReserve) {
await tmrDialog.forceDemiRevePosition(data.newTMR.coord);
if (data.sortReserve) {
tmrDialog.close();
}
}
/* -------------------------------------------- */
static async onPostEchecTourbillon(tmrDialog, tmrData, cases) {
await tmrData.actor.reveActuelIncDec(-cases);
await TMRRencontres._toubillonner(tmrDialog, tmrData.actor, cases);
static async onPostEchecTourbillon(tmrDialog, data, cases) {
await data.actor.reveActuelIncDec(-cases);
await TMRRencontres._toubillonner(tmrDialog, data.actor, cases);
}
/* -------------------------------------------- */
@ -461,26 +461,23 @@ export class TMRRencontres {
await data.actor.santeIncDec("vie", -1); // Et -1 PV
}
/* -------------------------------------------- */
static async _toubillonner(tmrDialog, actor, cases) {
let coord = Misc.templateData(actor).reve.tmrpos.coord;
let coord = actor.data.data.reve.tmrpos.coord;
for (let i = 0; i < cases; i++) {
coord = await TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
coord = TMRUtility.deplaceTMRAleatoire(actor, coord).coord;
}
await tmrDialog.forceDemiRevePosition(coord)
}
/* -------------------------------------------- */
static async onPostSuccessReveDeDragon(tmrDialog, tmrData) {
if (tmrData.rolled.isPart) {
await tmrData.actor.appliquerAjoutExperience(tmrData, true);
static async onPostSuccessReveDeDragon(tmrDialog, data) {
if (data.rolled.isPart) {
await data.actor.appliquerExperience(data.rolled, 'reve', data.competence);
}
await tmrData.actor.resultCombatReveDeDragon(tmrData);
await data.actor.resultCombatReveDeDragon(data);
}
/* -------------------------------------------- */
static async onPostEchecReveDeDragon(tmrDialog, tmrData) {
await tmrData.actor.resultCombatReveDeDragon(tmrData);
static async onPostEchecReveDeDragon(tmrDialog, data) {
await data.actor.resultCombatReveDeDragon(data);
tmrDialog.close();
}
}

View File

@ -1,7 +1,5 @@
import { TMRRencontres } from "./tmr-rencontres.js";
import { Misc } from "./misc.js";
import { Grammar } from "./grammar.js";
import { RdDDice } from "./rdd-dice.js";
/* -------------------------------------------- */
const TMRMapping = {
@ -337,23 +335,9 @@ export class TMRUtility {
return TMRMapping[coord]?.label ?? (coord + ": case inconnue");
}
static getTMRType(coord) {
const tmr = TMRMapping[coord];
return Misc.upperFirst(TMRType[tmr.type].name);
}
static getTMRDescr(coord) {
const tmr = TMRMapping[coord];
return Grammar.articleDetermine(tmr.type) + ' ' + tmr.label;
}
static typeTmrName(type){
return Misc.upperFirst(TMRType[Grammar.toLowerCaseNoAccent(type)].name);
}
static listSelectedTMR(typesTMR) {
return Object.values(TMRType).map(value => Misc.upperFirst(value.name))
.sort()
.map(name => { return { name: name, selected: typesTMR.includes(name) } });
return Grammar.articleDetermine(tmr.genre) + ' ' + tmr.label;
}
static isCaseHumide(tmr) {
@ -390,13 +374,12 @@ export class TMRUtility {
}
/* -------------------------------------------- */
static async getDirectionPattern() {
return await RdDDice.rollOneOf(tmrRandomMovePatten);
static getDirectionPattern() {
return Misc.rollOneOf(tmrRandomMovePatten);
}
/* -------------------------------------------- */
static async deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, await TMRUtility.getDirectionPattern(), 1);
static deplaceTMRAleatoire(actor, coord) {
return TMRUtility.deplaceTMRSelonPattern(actor, coord, TMRUtility.getDirectionPattern(), 1);
}
/* -------------------------------------------- */
@ -428,8 +411,8 @@ export class TMRUtility {
return TMRUtility.filterTMR(filter).map(it => it.coord);
}
static async getTMRAleatoire(filter = it => true) {
return await RdDDice.rollOneOf(TMRUtility.filterTMR(filter))
static getTMRAleatoire(filter = it => true) {
return Misc.rollOneOf(TMRUtility.filterTMR(filter))
}
/* -------------------------------------------- */
@ -482,14 +465,12 @@ export class TMRUtility {
return caseList;
}
/* -------------------------------------------- */
static distanceTMR(coord1, coord2) {
let pos1 = this.convertToCellPos(coord1);
let pos2 = this.convertToCellPos(coord2);
return this.distancePosTMR(pos1, pos2);
}
/* -------------------------------------------- */
static distancePosTMR(pos1, pos2) {
const dx = pos2.x - pos1.x;
const dy = pos2.y - pos1.y;

View File

@ -1,6 +1,5 @@
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
@ -16,7 +15,7 @@ export class Conquete extends Draconique {
async onActorCreateOwned(actor, item) { await this._creerConquete(actor, item); }
code() { return 'conquete' }
tooltip(linkData) { return `${this.tmrLabel(linkData)}: doit être conquis` }
tooltip(linkData) { return `La ${this.tmrLabel(linkData)} doit être conquise` }
img() { return 'icons/svg/combat.svg' }
createSprite(pixiTMR) {
@ -30,14 +29,14 @@ export class Conquete extends Draconique {
}
async _creerConquete(actor, queue) {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => Misc.data(it).data.coord);
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let possibles = TMRUtility.filterTMR(tmr => !TMRUtility.isCaseHumide(tmr) && !existants.includes(tmr.coord));
let conquete = await RdDDice.rollOneOf(possibles);
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue.id);
let conquete = Misc.rollOneOf(possibles);
await this.createCaseTmr(actor, 'Conquête: ' + conquete.label, conquete, queue._id);
}
async onActorDeleteCaseTmr(actor, casetmr) {
await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
await actor.deleteOwnedItem(casetmr.data.sourceid);
}
}

View File

@ -13,20 +13,20 @@ export class Debordement extends Draconique {
manualMessage() { return false }
async onActorCreateOwned(actor, souffle) {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
const tmr = await TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle.id);
const tmr = TMRUtility.getTMRAleatoire(it => !(TMRUtility.isCaseHumide(it) || existants.includes(it.coord)));
await this.createCaseTmr(actor, 'Debordement: ' + tmr.label, tmr, souffle._id);
}
code() { return 'debordement' }
tooltip(linkData) { return `Débordement en ${this.tmrLabel(linkData)}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/wave.webp' }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/wave.svg' }
createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), {
color: tmrColors.casehumide,
zIndex: tmrTokenZIndex.casehumide,
alpha: 0.6,
taille: tmrConstants.full,
decallage: tmrConstants.center
taille: tmrConstants.twoThird,
decallage: tmrConstants.bottom
});
}

View File

@ -1,6 +1,5 @@
import { Grammar } from "../grammar.js";
import { Misc } from "../misc.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRType, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
@ -14,7 +13,7 @@ export class Desorientation extends Draconique {
manualMessage() { return false }
async onActorCreateOwned(actor, souffle) {
const type = await RdDDice.rollOneOf(this._typesPossibles(actor));
const type = Misc.rollOneOf(this._typesPossibles(actor));
console.log("désorientation", type);
souffle.name += ": " + TMRType[type].name;
await this._creerCasesTmr(actor, type, souffle);
@ -44,7 +43,7 @@ export class Desorientation extends Draconique {
const existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let tmrs = TMRUtility.filterTMR(it => it.type == type && !existants.includes(it.coord));
for (let tmr of tmrs) {
await this.createCaseTmr(actor, 'Désorientation: ' + tmr.label, tmr, souffle.id);
await this.createCaseTmr(actor, 'Désorientation: ' + tmr.label, tmr, souffle._id);
}
}

View File

@ -1,4 +1,3 @@
import { Misc } from "../misc.js";
import { TMRUtility } from "../tmr-utility.js";
import { PixiTMR } from "./pixi-tmr.js";
@ -9,11 +8,11 @@ const registeredEffects = [
* Définition des informations d'une "draconique" (queue, ombre, tête, souffle) qui influence les TMR
*/
export class Draconique {
static isCaseTMR(itemData) { return itemData.type == 'casetmr'; }
static isQueueDragon(itemData) { return itemData.type == 'queue' || itemData.type == 'ombre'; }
static isSouffleDragon(itemData) { return itemData.type == 'souffle'; }
static isTeteDragon(itemData) { return itemData.type == 'tete'; }
static isQueueSouffle(itemData) { return Draconique.isQueueDragon(itemData) || Draconique.isSouffleDragon(itemData); }
static isCaseTMR(element) { return element.type == 'casetmr'; }
static isQueueDragon(element) { return element.type == 'queue' || element.type == 'ombre'; }
static isSouffleDragon(element) { return element.type == 'souffle'; }
static isTeteDragon(element) { return element.type == 'tete'; }
static isQueueSouffle(it) { return Draconique.isQueueDragon(it) || Draconique.isSouffleDragon(it); }
tmrLabel(linkData) { return TMRUtility.getTMRLabel(linkData.data.coord); }
@ -38,8 +37,7 @@ export class Draconique {
* @returns true si l'item correspond
*/
match(item) {
const itemData = Misc.data(item);
return Draconique.isQueueDragon(itemData) || Draconique.isSouffleDragon(itemData) || Draconique.isTeteDragon(itemData);
return Draconique.isQueueDragon(item) || Draconique.isSouffleDragon(item) || Draconique.isTeteDragon(item);
}
/**
@ -112,40 +110,35 @@ export class Draconique {
/**
*
* @param {*} item un item à tester
* @param {*} it un item à tester
* @param {*} coord les coordonnées d'une case. Si undefined toute case du type correspondra,
*/
isCase(item, coord = undefined) {
const itemData = Misc.data(item);
return Draconique.isCaseTMR(itemData) && itemData.data.specific == this.code() && (coord ? itemData.data.coord == coord : true);
isCase(it, coord = undefined) {
return Draconique.isCaseTMR(it) && it.data.specific == this.code() && (coord ? it.data.coord == coord : true);
}
find(list, coord = undefined) {
return list.find(c => this.isCase(Misc.data(c), coord));
return list.find(c => this.isCase(c, coord));
}
async createCaseTmr(actor, label, tmr, sourceId = undefined) {
const casetmrData = {
name: label, type: 'casetmr', img: this.img(),
await actor.createOwnedItem({
name: label, type: 'casetmr', img: this.img(), _id: randomID(16),
data: { coord: tmr.coord, specific: this.code(), sourceid: sourceId }
};
await actor.createEmbeddedDocuments('Item', [casetmrData]);
});
}
async deleteCasesTmr(actor, draconique) {
let caseTmrs = actor.data.items.filter(it => this.isCaseForSource(it, draconique));
await actor.deleteEmbeddedDocuments('Item', caseTmrs.map(it => it.id));
}
isCaseForSource(item, draconique) {
const itemData = Misc.data(item);
return Draconique.isCaseTMR(itemData) && itemData.data.specific == this.code() && itemData.data.sourceid == draconique.id;
let caseTmrs = actor.data.items.filter(it => this.isCase(it) && it.data.sourceid == draconique._id);
for (let casetmr of caseTmrs) {
await actor.deleteOwnedItem(casetmr._id);
}
}
async onVisiteSupprimer(actor, tmr, onRemoveToken) {
let existants = actor.data.items.filter(it => this.isCase(it, tmr.coord));
await actor.deleteEmbeddedDocuments('Item', existants.map(it => it.id));
for (let casetmr of existants) {
await actor.deleteOwnedItem(casetmr._id);
onRemoveToken(tmr, casetmr);
}
}

View File

@ -186,7 +186,7 @@ export class EffetsDraconiques {
}
static toItems(item) {
return (item?.documentName === 'Actor') ? item.data.items : (item?.documentName === 'Item') ? [Misc.data(item)] : [];
return (item?.entity === 'Actor') ? item.data.items : (item?.entity === 'Item') ? [Misc.data(item)] : [];
}
}

View File

@ -32,7 +32,7 @@ export class FermetureCites extends Draconique {
let existants = actor.data.items.filter(it => this.isCase(it)).map(it => it.data.coord);
let ouvertes = TMRUtility.filterTMR(it => it.type == 'cite' && !existants.includes(it.coord));
for (let tmr of ouvertes) {
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle.id);
await this.createCaseTmr(actor, 'Fermeture: ' + tmr.label, tmr, souffle._id);
}
}
}

View File

@ -13,26 +13,26 @@ export class Pelerinage extends Draconique {
manualMessage() { return false }
async onActorCreateOwned(actor, queue) {
let tmr = await TMRUtility.getTMRAleatoire();
await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue.id);
let tmr = TMRUtility.getTMRAleatoire();
await this.createCaseTmr(actor, 'Pèlerinage: ' + tmr.label, tmr, queue._id);
}
code() { return 'pelerinage' }
tooltip(linkData) { return `Votre pèlerinage en ${this.tmrLabel(linkData)}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/pelerin.webp' }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/pelerin.svg' }
createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), {
zIndex: tmrTokenZIndex.conquete,
alpha: 1,
taille: tmrConstants.full,
decallage: tmrConstants.center
taille: tmrConstants.twoThird,
decallage: tmrConstants.right
});
}
async onActorDeleteCaseTmr(actor, casetmr) {
await actor.deleteEmbeddedDocuments('Item', [casetmr.data.sourceid]);
await actor.deleteOwnedItem(casetmr.data.sourceid);
}
}

View File

@ -1,6 +1,5 @@
import { Grammar } from "../grammar.js";
import { RdDDice } from "../rdd-dice.js";
import { tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { tmrColors, tmrConstants, tmrTokenZIndex, TMRUtility } from "../tmr-utility.js";
import { Draconique } from "./draconique.js";
export class Periple extends Draconique {
@ -14,24 +13,25 @@ export class Periple extends Draconique {
manualMessage() { return false }
async onActorCreateOwned(actor, souffle) {
let terrain = (await RdDDice.rollTotal("1d2")) == 1 ? 'sanctuaire' : 'necropole';
let terrain = new Roll("1d2").evaluate().total == 1 ? 'sanctuaire' : 'necropole';
let tmrs = TMRUtility.getListTMR(terrain);
for (let tmr of tmrs) {
await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle.id);
await this.createCaseTmr(actor, 'Périple: ' + tmr.label, tmr, souffle._id);
}
}
code() { return 'periple' }
tooltip(linkData) { return `Votre Périple passe par ${this.tmrLabel(linkData)}` }
img() { return 'systems/foundryvtt-reve-de-dragon/icons/tmr/pelerin.webp' }
img() { return 'icons/svg/acid.svg' }
createSprite(pixiTMR) {
return pixiTMR.sprite(this.code(), {
zIndex: tmrTokenZIndex.conquete,
alpha: 1,
taille: tmrConstants.full,
decallage: tmrConstants.center
color: tmrColors.souffle,
taille: tmrConstants.twoThird,
decallage: tmrConstants.right
});
}
getDifficulte(tmr) {

View File

@ -20,13 +20,12 @@ export class PixiTMR {
this.callbacksOnAnimate = [];
}
load( onLoad = (loader, resources) => {} ) {
load(onLoad = (loader, resources) => {}) {
let loader = this.pixiApp.loader;
for (const [name, img] of Object.entries(PixiTMR.textures)) {
loader = loader.add(name, img);
}
loader.onLoad.add((error, resaon) => { console.log("ERROR", error, resaon) });
loader.load( (loader, resources) => {
loader.load((loader, resources) => {
onLoad(loader, resources);
for (let onAnimate of this.callbacksOnAnimate) {
onAnimate();

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